前言

一本很好的机器学习入门书籍,既不失严谨性又不失趣味性。书中介绍了机器学习中一些比较基础的概念和相应公式的数学推导过程,算不上多么全面,更多的是一个抛砖引玉的效果,让我们能够对机器学习入门有一个很好的印象。 这篇博客通过对文章目录的每一章节进行回顾,去梳理整本书的知识体系,用自己的话把整本书逻辑连接起来,以此来更好地帮助自己更好地把学过的东西都串起来,也希望能对读者有所启发。(文中只有一级标题是原文目录,其他二级标题按我自己理解划分的)

第一章 开始二人之旅

从两个人的对话开始入手整本书机器学习的教学,简要地介绍了机器学习的概念和重要性,以及用简单的生活例子解释了机器学习算法中回归、分类和聚类的概念

回归:处理连续数据如时间序列数据时使用的技术,从数据中学习它的趋势,从而对未来进行预测。分类:对数据进行分类贴标签,有二分类和多分类问题聚类:与分类相似,又有些不同。分类的训练数据是带标签的(正确答案),而聚类的训练数据是不带标签的。

有监督学习:使用带有标签的数据进行的学习称为有监督学习,如回归、分类 无监督学习:使用没有标签的数据进行的学习称为无监督学习,如聚类

第二章 学习回归——基于广告费预测点击量

从数据中进行学习,然后给出预测值,重点在于如何利用好训练数据而调教出一个好的预测模型。

第二章利用某个网站投入的广告费来预测网站的点击量作为案例,来介绍回归算法的基本流程和算法中用到的数学公式推导。其训练数据分布如下图所示:

2.1 直线拟合

先用简单的一次函数作为预测函数,来初步了解回归算法

y

=

θ

0

+

θ

1

x

y= \theta_0 + \theta_1 x

y=θ0​+θ1​x 为了把预测数据和训练数据的 y 值区分开来,这里对一次函数进一步变换,把 y 换成

f

θ

(

x

)

f_\theta(x)

fθ​(x),看成一个含有参数

θ

\theta

θ 、并且和变量

x

x

x 相关的函数

f

θ

(

x

)

=

θ

0

+

θ

1

x

f_\theta(x)= \theta_0 + \theta_1 x

fθ​(x)=θ0​+θ1​x 我们希望这个一次函数最终能够显示如下的结果,对所有的训练数据有一个较好的拟合。那么如何得到这样的一条曲线呢?问题就在于我们如何设置

θ

0

\theta_0

θ0​和

θ

1

\theta_1

θ1​这两个参数的取值了,这就是回归算法所需要做的事情。

2.2 最小二乘法

怎么样算得上好的

θ

\theta

θ 呢?如果该

θ

\theta

θ 能使得预测数据和训练数据两者之间最小,就是我们所需要的

θ

\theta

θ 。 也就是说使所有点的

y

y

y 和

f

θ

(

x

)

f_\theta(x)

fθ​(x) 之间的误差尽可能地小,因为我们做不到所有点的误差都为0。

那么怎么找呢?假设现在有n个训练数据,那么它们之间的误差之和可以用如下的目标函数表示,我们要做的就是要找到使

E

(

θ

)

E(\theta)

E(θ) 的值最小的

θ

\theta

θ。

E

(

θ

)

=

1

2

i

=

1

n

(

y

(

i

)

f

θ

(

x

(

i

)

)

)

2

E(\theta)= \frac{1}{2} \sum_{i=1}^n \left( y^{(i)} - f_\theta(x^{(i)}) \right)^2

E(θ)=21​i=1∑n​(y(i)−fθ​(x(i)))2

上标

i

i

i 表示第几个训练数据给误差加平方,是因为考虑到误差为赋值的情况,就平方统一变成正数来考虑1/2 是为了让表达式的结果变得更简洁而加的常数,没有也不影响,因为只要乘以正常数,函数本身取最小值的点是不变的。

如何找到使得使

E

(

θ

)

E(\theta)

E(θ) 的值最小的

θ

\theta

θ呢?我们可以直接对

E

(

θ

)

E(\theta)

E(θ)的不同参数进行偏导,采用暴力简单的解方程组方式进行求解,这样求解很简单,但是实际问题中很多时候不能够如此暴力,所以在这本书就没有涉及到这部分的内容,作者是用下面我要提到的梯度下降法来逐步逼近最优解的,但是我在这边也做一个拓展。

以上的做法就是最小二乘法。

最小二乘法(又称最小平方法)是一种数学优化技术。它通过最小化误差的平方和寻找数据的最佳函数匹配。利用最小二乘法可以简便地求得未知的数据,并使得这些求得的数据与实际数据之间误差的平方和为最小

2.3 梯度下降法

梯度下降法的目标函数

E

(

θ

)

E(\theta)

E(θ)和最小二乘法是一样的,如何用梯度下降法找到使得使

E

(

θ

)

E(\theta)

E(θ) 的值最小的

θ

\theta

θ 呢? 这边使用也是用求导来求它。

E

(

θ

)

=

1

2

i

=

1

n

(

y

(

i

)

f

θ

(

x

(

i

)

)

)

2

E(\theta)= \frac{1}{2} \sum_{i=1}^n \left( y^{(i)} - f_\theta(x^{(i)}) \right)^2

E(θ)=21​i=1∑n​(y(i)−fθ​(x(i)))2

微分着代表计算变化的快慢程度,对于最小化问题只要存在解,我们只要把点向导数的符号相反的方向移动,函数值就会沿着最小值的方向前进了。换句话说就是让函数沿着梯度下降的方向求解极小值(所以容易陷入局部最优解,后面会进一步拓展)

梯度下降是迭代法的一种,可以用于求解最小二乘问题(线性和非线性都可以)。在求解机器学习算法的模型参数,即无约束优化问题时,梯度下降(Gradient Descent)是最常采用的方法之一,另一种常用的方法是最小二乘法。 在求解损失函数的最小值时,可以通过梯度下降法来一步步的迭代求解,得到最小化的损失函数和模型参数值。反过来,如果我们需要求解损失函数的最大值,这时就需要用梯度上升法来迭代了。在机器学习中,基于基本的梯度下降法发展了两种梯度下降方法,分别为随机梯度下降法和批量梯度下降法。

这就是梯度下降法,通过不断沿着梯度下降方向移动,从而找到最值,它虽然简单但是有着明显的缺点,后续会接着介绍如何解决它的缺点。其表达式如下:

x

:

=

x

η

d

d

x

g

(

x

)

x := x -\eta \, \frac{ {\text d} }{{\text d} x} g(x)

x:=x−ηdxd​g(x)

η

\eta

η 是学习率的正常数。根据学习率的大小,到达最小值的更新次数也会发生变化,收敛速度也就会不同。如果

η

\eta

η 过大,

x

x

x 就可能在两个值上陷入循环,甚至有可能远离最小值,这就是发散状态,可以理解为参数跨度太大;而当

η

\eta

η 较小时,移动量也会变小,收敛速度就会变慢,可以理解为参数跨度过小。所以选择一个合适的

η

\eta

η 是需要我们进行尝试选择的。(其实是有方法可以找到合适的值,只不过这边不做拓展了)

根据这个参数更新表达式,我们可以对之前设定好的直线模型中的参数进行更新,初始参数是随机选择的,后续通过梯度下降更新为合适的参数。 其中对于

E

(

θ

)

E(\theta)

E(θ) 的偏导,需要使用到复合函数的偏导 偏导的计算并不复杂,这里直接给出最后的结果,根据这个公式进行更新参数,最后用得到的参数就能得到如开头所示的拟合效果。

2.4 曲线拟合(多项式回归)

对于之前的训练数据其实曲线会更拟合数据,只是刚开始接触回归从直线入门开始比较好,现在我们把模型定义为二次函数,其表达式如下:

y

=

θ

0

+

θ

1

x

+

θ

2

x

2

y= \theta_0 + \theta_1 x+ \theta_2 x^2

y=θ0​+θ1​x+θ2​x2

或者用更大次数的表达式也行,这样就可以表示更复杂的曲线,虽然次数越大拟合越好,但是也可能会出现过拟合的问题。 所以想要找出最适合的表达式之前,我们需要不断地去尝试。

二次函数增加了次数,也就增加了新的参数,这边同样用梯度下降法找到模型中合适的参数

θ

\theta

θ,道理都是一样的,也是对复合函数进行偏导,这边直接给出了最终的参数更新表达式。

2.4 多重回归

上面提到的模型中网站的点击量只以广告费的投入费用为变量,也就是一元函数,但是我们现实中的很多问题是变量超过两个的复杂问题,这个时候预测模型中的变量也就要增加,此时的回归我们称为多重回归。其表达式如下:

因为式子较长,此处我们可以用向量的内积形式来表示上式。同样引入向量的表示方法,就可以方便我们使用一些线性代数中的方法,方便我们进行计算。 最后拟合曲线简化成如下的形式: 对

f

θ

(

x

)

f_\theta(x)

fθ​(x) 中的

θ

\theta

θ参数更新表达式和上面的方法如出一辙,这里将表达式汇总成一个。

2.5 随机梯度下降法

之前提到梯度下降法中存在着明显的缺点,

梯度下降法的一个缺点就是计算量大、计算时间长。 是因为在梯度下降法中对于每一个参数的更新时都会应到所有的训练数据。当有多个参数时,就会对所有的训练数据进行重复计算,这就会导致当训练数据越多时,循环的次数也就越多,计算时间也就越花时间。 另一个缺点就是容易陷入局部最优解。 用梯度下降法寻找函数最小值时,会先随机选择

x

x

x 的初始值,但你又怎么能保证向着梯度下降的方向移动,找到的不是极小值呢?如何去确保自己找到的是最值呢?

因为如此,我们会想办法寻找另一个更高效率的梯度下降法,这就是随机梯度下降法。其表达式如下。我们可以很明显看到与梯度下降算法的区别,梯度下降法是用到了所有训练数据的误差值,而在随机梯度下降算法是随机选择一个训练数据。 随机梯度算法对于梯度下降算法的缺点弥补:

梯度下降算法更新一次参数的时间,随机梯度下降算法可以更新 n 次随机梯度下降法由于训练数据是随机选择的,所以不容易陷入目标函数的局部最优解。

2.6 小批量梯度下降法

和之前提到的随机梯度下降算法类似,只不过随机梯度下降算法随机选择 1 个训练数据,而小批量梯度下降算法是随机选择 m 个训练数据来更新参数。设随机选择 m 个训练数据的集合为

K

K

K,其表达式如下:

第三章 学习分类——基于图像大小进行分类

此处引入对图像分类的例子,根据图像尺寸把图像分类为纵向图像和横向图像。如下所示,高和宽的部分是数据,形状的部分是标签。

将其用坐标图展现出来如下,然后分类的目的就是想要找到中间那条线。

3.1 权重向量

但是这条直线并不像回归算法时一样,其直线是直接用参数表示的。

分类问题中采用的是向量来找到那条直线,有方向有大小,它被称为权重向量,我们用参数表示的是权重向量,而上图所求直线是与权重向量相互垂直的,我们是通过权重向量找到直线的。

设权重向量为

ω

\omega

ω ,那么这条直线的表达式就如下所示: 当我们假设

ω

\omega

ω 为(1,1)时,我们就可以得到直线的具体形式。 在直角坐标系中的体现如下:

在二分类问题中,我们所找到的这条直线也可以被称为决策边界。

权重向量一开始并不存在,需要我们通过训练找到权重向量,然后才能找到对应的决策边界,从而利用决策边界对数据进行分类。

3.2 感知机

如何求出权重向量呢?这里我们使用感知机模型。感知机是接受多个输入后将每个值与各自的权重相乘,最后输出总和的模型。这里我们可以看成向量的内积。

在人工神经网络领域中,感知器也被指为单层的人工神经网络,以区别于较复杂的多层感知器(Multilayer Perceptron)。作为一种线性分类器,(单层)感知器可说是最简单的前向人工神经网络形式。尽管结构简单,感知器能够学习并解决相当复杂的问题。感知器主要的本质缺陷是它不能处理线性不可分问题。

在使用感知机之前,我们需要对训练数据进行一些处理,表示宽的轴为

x

1

x_1

x1​、表示高的轴为

x

2

x_2

x2​,用

y

y

y 来表示图像是横向还是纵向的,横向的值为 1、纵向的值为 −1。处理后结果如下:

然后我们再引入判别函数的概念。它可以根据训练数据

x

x

x 向量与权重向量的内积结果来判断,输入数据

x

x

x 是横向还是纵向,也就是返回 1 或 -1 ,我们将其作为

f

ω

(

x

)

f_\omega(x)

fω​(x),这也就是我们的结果函数,数据分类判定由它给出,其函数定义如下:

内积是衡量向量之间相似程度的指标。结果为正,说明二者相似;为 0 则二者垂直;为负则说明二者不相似。

接下来引入权重向量的更新表达式。正如之前在回归中提到关于

θ

\theta

θ 的更新表达式一样,我们这边也是用一系列的方法,去不断更新参数,最后找到合适的一个值从而使模型真正有效起来。如下所示:

当我们用判别函数进行分类的结果

f

ω

(

x

)

f_\omega(x)

fω​(x) 与实际标签

y

y

y 不同时,也就是说判别函数的结果是错误的,这时我们就对权重向量

ω

\omega

ω 进行更新; 分类时更新权重向量的公式为

(

ω

+

y

i

x

i

)

(\omega + y^i x^i)

(ω+yixi),就是把正确的标签结果乘上相应的数据向量

x

x

x,然后再与原先的权重向量做向量加法或者向量减法,从而使直线旋转相应的角度,不断调整直线找到决策边界最终正确的位置。如下图所示的就是一次判别错误后的更新调整: 而当判别结果与实际标签相同时,也就是说判别函数的分类结果正确,这时就不用更新权重向量

ω

\omega

ω

以上就是感知机的学习方法了。但它只是一种简单的二元线性分类器,那么遇到线性不可分的情况我们就不能用感知机处理,我们需要用到接下来介绍的逻辑回归。

3.3 逻辑回归

线性可分指的就是能够使用直线分类的情况,而不能用直线分类的情况称为线性不可分,如下所示:

逻辑回归与感知机不同之处在于,它是把分类作为概率来考虑的。如图像为纵向的概率是 80%、为横向的概率是 20%这样的分类。

另外,这里设横向的值为 1、纵向的值为 0。(设这样的值主要是因为后面是用sigmoid函数作为结果函数的,因为sigomoid函数的特性,我们这样设置后面还会继续展开这点)

只要是两个不同的值,用什么都可以。在学习感知机时之所以设置值为 1 和 −1,是因为这样会使参数更新表达式看起来更简洁,而现在则是设置为 1 和 0 会更简洁

为了初步学习逻辑回归,我们先用逻辑回归处理下线性可分问题,有了初步了解后我们再来用它处理线性不可分问题。

3.3.1 逻辑回归处理线性可分问题

因为是线性可分问题,所以实际上我们要求的就是一条决策边界,这里我们依旧可以用之前的做法用向量表示该直线,即

θ

T

x

\theta^Tx

θTx。 我们在这边也需要一个像感知机的判别函数一样,一个能够将未知数据分类为某个类别的函数

f

θ

(

x

)

f_\theta(x)

fθ​(x),也就是我们整个分类算法通过训练最后调教出来一个含参数的分类判别模型。 因为我们使用概率来表示分类结果的,所以此处引入

s

i

g

m

o

i

d

sigmoid

sigmoid 函数,其函数表示和图形表示如下: 可以很明显看出 sigmoid 函数的两个特征,因为我们是用概率来考虑分类的,所以sigmoid函数的取值范围刚好可以作为概率来使用(小数转化成百分比)

θ

T

x

=

0

\theta^Tx = 0

θTx=0 时,

f

θ

(

x

)

=

0.5

f_\theta(x) = 0.5

fθ​(x)=0.5

0

<

f

θ

(

x

)

<

1

0 \lt f_\theta(x) \lt 1

0

现在我们有了可以输出分类概率的函数了,但我们还需要对分类概率进行进一步判定,也就是判定当某一事件的概率高达多少时即可判定事件发生,即阈值。这里我们将 0.5作为阈值。当大于50%时,即认定为 1,小于50%即认定为0.

利用 sigmoid 函数进行条件表示转换,当我们调教好

θ

\theta

θ 的值之后,就可以直接令

θ

T

x

=

0

\theta^Tx = 0

θTx=0 从找到决策边界的具体形式。

a. 似然函数(逻辑回归参数调教方法)

好了,上面先介绍的都是找到了正确的参数

θ

\theta

θ 后做的事情,接下来我们介绍如何进行参数

θ

\theta

θ 调教优化.之前回归是用梯度下降法进行参数调教的,逻辑回归这边是另一种调教方法. 从训练数据的标签出发,我们如何使得参数的数值大小能够正好配合我们对预测结果的期望呢?即呈现如下效果。 假定所有的训练数据都是互不影响、独立发生的,这种情况下整体的概率就可以用下面的联合概率来表示。把我们对于分类结果的期望联合在一起。目标函数

L

(

θ

)

L(\theta)

L(θ) 也称为似然函数,取自英文单词Likelihood的首字母。 而在联合概率上,我们还可以进一步简化,用一种巧妙的数学方式将联合概率表达式一般化。这样我们就可以不用区分不同情况下的写法了,而是汇总到同一个表达式了。 接下来我们要做的工作就是使上面的目标函数最大化。回归时处理的是误差,所以要最小化;现在考虑的是联合概率,我们希望概率尽可能大,所以要最大化。 同样我们这边也是要求导从而找到最值,不过用的是梯度上升法找到最大值)。 直接对似然函数进行求导很麻烦,乘法求导麻烦工作量大。因为是连乘式我们可以先对其求对数,把连乘式变换为连加式。因为我们是优化问题,而log函数又是递增函数不会影响找到最大值。 进一步简化得到如下式子: 然后我们和前面提到的梯度下降法中的复合函数求导一样,这里就不具体展开计算过程,而是侧重于提供一个思路,下面直接给出自重结果,具体过程可以自己看书。

3.3.2 逻辑回归处理线性不可分问题

前面解决的是线性可分的问题使我们对逻辑回归有一个初步了解,接下来我们要真正地用逻辑回归去解决线性不可分问题了。 其实也不难,线性不可分直线不可分,那么我们就用曲线区分就行了。就像上文提到的多项式回归一样,我们去给决策边界增加次数,如增加

x

1

2

x_1^2

x12​,变成如下的式子。 后面的步骤和逻辑回归处理线性可分问题类似,这里就不做拓展了。

第四章 评估——评估已建立的模型

前面的工作都是为了得到一个预测模型或者分类模型,但我们如何知道调教出来的模型正确性(精度)呢?此时我们需要能够定量地表示机器学习模型的精度,这就是模型评估要做的事情。

4.1 交叉验证

我们之前调教出来的参数,都是通过训练数据调教出来的,也就是说这样的参数对训练数据来说肯定是正确的,那如果我们用其他非训练数据测试的效果会怎么样呢?这就是交叉验证要做的事情。

把所有的数据分成两份,一份用于训练,一份用于测试,然后用后者来评估模型,检查训练好的模型对测试数据的拟合情况。

a. 对回归问题的验证

在回归问题中,我们如何使用测试数据对模型精度进行定量表示呢?

这边用均方误差(MSE,全称 Mean Square Error)来表示,这个误差越小,精度就越高,模型也就越好,我们可以称为误差函数。在回归问题中之前用来调教参数的目标函数和误差函数是一样的。

b. 对分类问题的验证

在回归中要考虑的是答案不完全一致时的误差,而分类中要考虑的是答案是否正确。

关于分类是否成功可以分为一下四种情况:

图像是横向的,被正确分类了图像被分类为横向,但实际上不是横向的图像不是横向的,被正确分类了图像被分类为非横向,但实际上是横向的

整合成一张表就是这样的: 然后进一步用更规范的形式表达 有了上面这张表,我们就可以得到分类问题的一个精确率

A

c

c

u

r

a

c

y

Accuracy

Accuracy,它表示在整个数据集中,被正确分类的数据TP和TN所占的比例。 有了

A

c

c

u

r

a

c

y

Accuracy

Accuracy 我们就能够在一定程度上,体现分类模型整体的精度了。但是当训练数据比较极端的时候,单看

A

c

c

u

r

a

c

y

Accuracy

Accuracy 这个指标能够反映的信息还是有限。所以我们需要引出其他指标。

精确率Precision和召回率

精确率

P

r

e

c

i

s

i

o

n

Precision

Precision。它只关注TP和FP,它的含义是在被分类为 Positive 的数据中,为实际 Positive 数据的比率。这个值越高说明分类错误越少。 召回率

R

e

c

a

l

l

Recall

Recall。它只关注TP和FN。它的含义是在实际为Positive的数据中,被正确分类的比率。这个值越高,说明被正确分类的数据越多。 不过一般来说,精确率和召回率会一个高一个低,需要我们进行取舍。同理上面计算是以TP为主进行计算的,用TN为主进行计算也可以。当测试数据不平衡时,我们使用数量少的那个为主会更好。

F-measure值

为了能够综合平均地考虑这两个因素,我们这边引入F值的概念。在F值中精确率和找回来只要由只要有一个低,就会拉低 F 值,充分考虑到了两者之间的平衡 上面的F值称为F1值会更合适,更通用的F值是带有权重的,F1的权重可以看成

β

=

1

\beta=1

β=1

c. K 折交叉验证

交叉验证中比较有名的是 K折交叉验证,实际上就是让被K等份的每一份数据都有机会、轮流来充当测试数据,其中K值需要我们自己确定合适的K值。 下面以 4 折交叉验证为例子。

4.2 过拟合(侧重说明正则化)

如果经过模型评估后,发现模型过拟合(只对训练数据拟合效果好),我们可以采取以下的方法避免过拟合:

增加全部训练数据的数量 增大模型的数据摄入量,让模型能够更充分了解数据使用简单的模型 使用过于复杂的模型,就会导致训练出的模型会过度贴合训练数据,我们就可以用简单的模型来防止过拟合正则化 在我们调教参数使用的目标函数中,加入正则化项,防止参数变得过大,有助于参数的影响变小,正则化项如下:

一般来说不对

θ

0

\theta_0

θ0​ 应用正则化。所以仔细看会发现求和符号中的下标 j 的取值是从 1 开始的。像这种只有参数的项称为偏置项,一般不对它进行正则化。

λ

\lambda

λ 是决定正则化项影响程度的正的常数。这个值需要我们自己来定,它可以控制正则化惩罚的强度。

若使用上面提到的正则化项进行正则化,则这种方法称为 L2 正则化。除 L2 正则化方法之外,还有 L1 正则化方法。它的正则化项 R 是这样的: 正则化的方法不至于一种,需要我们根据实际需要使用。 L1 正则化的特征是被判定为不需要的参数会变为 0,从而减少变量个数。而 L2 正则化不会把参数变为 0。L2 正则化会抑制参数,使变量的影响不会过大,而 L1 会直接去除不要的变量

4.3 欠拟合

上面提到了过拟合,其实还存在一种情况就是欠拟合,欠拟合是与过拟合相反的状态,它是没有拟合训练数据的状态。出现这种情况的主要原因就是模型相对于要解决的问题来说太简 单了。原因也和过拟合的情况相反。如果模型过于简单,那么随着数据量的增加,误差也会一点点变大,换句话说就是模型过于简单,兜不住太多数据。

那怎么样才能判断到底是过拟合还是欠拟合呢?我们需要用学习曲线来判断模型的拟合状态。以数据的数量为横轴、以精度为纵轴,然后把用于训练的数据和用于测试的数据画成图。像这样展示了数据数量和精度的图称为学习曲线

将两份数据的精度用图来展示后,如果是这种形状,就说明出现了欠拟合的状态。也有一种说法叫作高偏差。这是一种即使增加数据的数量,无论是使用训练数据还是测试数 据,精度也都会很差的状态 而在过拟合的情况下,图是这样的。这也叫作高方差。随着数据量的增加,使用训练数据时的精度一直很高,而使用测试数据时的精度一直没有上升到它的水准。只对训练数据拟合得较好,这就是过拟合的特征。

在知道模型精度低,却不知道是过拟合还是欠拟合的时候,就可以画一下学习曲线,通过学习曲线判断出是过拟合还是欠拟合之后,就可以采取相应的对策以便改进模型了。

第五章 实现——使用Python编程

代扩展,代码部分可自行实现

总结

写这篇博客的工作量之大,是我之前想象不到的,我读完这本都没花几天时间,而写这篇博客花的时间都够把这本书读好几遍了。由此可以看出自己的写作方面的问题,如果今后还想继续尝试这种读后复盘模式,就得注意了:

还没有形成自己清晰的博客文章写作模式,或者说是没有形成Markdown编辑器的自己一套的写作风格。所以每次写文章时,都要临时思考如何排版更好看这次写读后复盘,感觉很多话还是太拖沓了,为什么会这样?肯定是因为自己还没有把书读薄,对于整本书的内容还做不到真正的了解,但其实就是因为做不到真正了解,所以我才会写博客进行知识梳理的。希望随着自己的知识积累,以后读新书再进行知识梳理时语言能够更加简练。

2023.02.24 帅小帅家的小吴昊定稿❤️

好文阅读

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: