第1章 机器学习任务
1.1 定义机器学习
机器学习是对软件工程的设计和学习,其使用过去的经验以指导未来的决策。机器学习研究能从数据中进行学习的软件,其基础目标是归纳,或者从一种未知规则的应用实例中归纳出相关规则。
计算机科学家汤姆·米切尔对机器学习给出了一个更加正式的定义:
如果一个程序的性能在’T’中体现,通过’P’来衡量,并通过经验’E’来优化,那么该程序可以被视为针对一些任务类型’T’和性能衡量’P’从经验’E’中进行学习
1.2 从经验中学习
机器学习系统经常被描述为在人类监督或无监督之下从经验中学习。
在监督学习问题中,一个程序会通过标记的输入和输出进行学习,并从一个输入预测输出,也就是说从正确答案中学习。
在无监督学习中,一个程序不会从标记数据中学习,相反,它尝试在数据中发现模式。
监督学习和无监督学习可以被视作问题的两端,此外另有一些半监督学习问题,同时利用监督学习和非监督学习的数据,处于两种学习模式之间。至于强化学习则靠近监督学习,不同于无监督学习,强化学习程序不会从标记的输出对中进行学习,而是从决策中接受反馈,但错误不会显式地更正。
解释变量:自变量、预测器、回归器、控制变量、暴露变量、输入变量;
响应变量:因变量、依赖变量、回归变量、标准变量、测定变量、应答变量、被解释变量、实验变量、标签、输出变量.
组成监督学习经验的实例集合称为一个训练集;一个用于衡量程序性能的实例集合称为一个测试集
1.3机器学习任务
常见的监督机器学习任务可分为分类和回归两类;非监督机器学习任务则可分为聚类和降维。
1.4偏差(Bias)和方差(Variance)
可以理解为偏差为绝对的误差,方差为相对的误差
偏差方差均衡:指减小二者其中一个通常会引起另一个增大。
第2章 简单线性回归
知识架构(希望学完后可自己凭印象画出):
本章中,如下的披萨尺寸与价格关系例子将贯穿始终
直径(英寸) | 价格(美元) |
---|---|
6 | 7 |
8 | 9 |
10 | 13 |
14 | 17.5 |
18 | 18 |
2.1 线性回归流程
2.1.1 导入数据
import numpy as np
import matplotlib.pyplot as plt
# 导入数据
X = np.array([[6],[8],[10],[14],[18]]).reshape(-1, 1) # 变为一列 等价于列向量
y= np.array([7, 9, 13, 17.5, 18])
# 绘图
plt.figure()
plt.title('Pizza price plotted against diameter')
plt.xlabel('Diameter in inches')
plt.ylabel('Price in dollars')
plt.plot(X, y, 'k.')
plt.axis([0,25,0,25])
plt.grid(True)
plt.show()
运行结果:
2.2 创建线性回归模型
# 导入估计器
from sklearn.linear_model import LinearRegression
# 创建实例
model = LinearRegression()
# 学习数据
model.fit(X, y)
# 创建测试集
test_pizza = np.array([[12]])
# 预测值
predicted_price = model.predict(test_pizza)[0]
print(model.predict(test_pizza)) #an array in, an array out!
print('A 12 " pizza shoud cost: $%.2f' % predicted_price)
讲解:
简单线性模型鉴定响应变量和解释变量之间存在线性关系,它使用一个被称为超平面的线性面来对这种关系进行建模。超平面是一个子空间,他比组成它的空间小一个维度。
LinearRegression 类是一种估计器,而估计器会基于观测到的数据去预测其他值。而在scikit-learn中,所有的估计器都实现了fit方法和predict方法,前者会通过学习得出模型的参数,后者则会通过学习到的参数来预测一个解释变量对应的响应变量值。
对于LinearRegression以及其他估计器,要注意在预测时,遵从***"an array in, an array out"的原则,从头至尾我们操作的都是列表*,不是单个的元素!
拟合结果形如下式:
y
=
β
x
+
α
y=\beta x+\alpha
y=βx+α
我们预期的拟合结果应如下图所示:
附图:fit的含义
2.3 用代价函数评价模型的拟合性
S S r e s = ∑ i = 1 n ( y i − f ( x i ) ) 2 SS_{res} = \sum^n_{i=1}(y_i-f(x_i))^2 SSres=i=1∑n(yi−f(xi))2
print('Residual sum of squares: %.2f' % np.mean((model.predict(X)-y)**2)
# RSS cost function
2.4 其他评价手段—— R 2 R^2 R2或 r 2 r^2 r2
S
S
t
o
t
=
∑
i
=
1
n
(
y
i
−
y
ˉ
)
2
SS_{tot} = \sum^n_{i=1}(y_i-\bar{y})^2
SStot=i=1∑n(yi−yˉ)2
R
2
=
1
−
S
S
r
e
s
S
S
t
o
t
R^2=1-\frac{SS_{res}}{SS_{tot}}
R2=1−SStotSSres
X_train = X
y_train = y
X_test = np.array([8, 9, 11, 16, 12]).reshape(-1,1)
y_test = np.array([11, 8.5, 15, 18, 11])
model = LinearRegression()
model.fit(X_train, y_train)
r_squared = model.score(X_test, y_test)
print(r_squared)
2.2 原理:求解简单线性回归的OLS
v a r ( x ) = ∑ i = 1 n ( x i − x ˉ ) 2 n − 1 var(x)=\frac{\sum^n_{i=1}(x_i-\bar{x})^2}{n-1} var(x)=n−1∑i=1n(xi−xˉ)2
x_bar = X.mean()
print(x_bar)
varience = ((X-x_bar)**2).sum()/(X.shape[0]-1)
# 两种方法等效
print(varience)
print(np.var(X, ddof=1))
c o v ( x , y ) = ∑ i = 1 n ( x i − x ˉ ) ( y i − y ˉ ) n − 1 cov(x,y)=\frac{\sum^n_{i=1}(x_i-\bar{x})(y_i-\bar{y})}{n-1} cov(x,y)=n−1∑i=1n(xi−xˉ)(yi−yˉ)
y_bar = y.mean()
covarience = np.multiply((X-x_bar).transpose(), y-y_bar).sum()/(X.shape[0]-1)
print(covarience)
print(np.cov(X.transpose(), y)[0][1])
我们有:
β
=
c
o
v
(
x
,
y
)
v
a
r
(
x
)
α
=
y
ˉ
−
β
x
ˉ
\beta = \frac{cov(x,y)}{var(x)}\\ \alpha = \bar{y} - \beta\bar{x}
β=var(x)cov(x,y)α=yˉ−βxˉ
求解完毕!
第3章 K-近邻算法(KNN)的分类与回归
知识结构:
3.1 K-近邻模型
KNN模型是一种用于回归任务和分类任务的简单模型。拟合好的模型会根据输入的测试实例以距离为指标将原有数据进行排序并取前k个数据,其中所占数量最多的数据类型标签将会被赋给该输入测试实例。通常来说,k会被赋值成奇数以防出现两种类型标签占比平局的现象。
3.2 惰性学习和非参数模型
KNN是一种惰性学习模型,亦称作基于实例的学习模型,会对训练数据集进行少量的处理或者完全不处理,和简单线性回归这样的勤奋学习模型不同,KNN在训练阶段不会估计由模型生成的参数。训练勤奋学习模型需要耗费计算资源,但预测阶段代价并不高;惰性学习模型几乎可以进行即时预测,但是需要付出高昂的代价。
KNN还是一种非参数模型。对应地,参数模型使用固定数量的参数或者系数去定义能够对数据进行总结的模型,参数的数量独立于训练实例的数量,相反,非参数模型意味着模型的参数个数并不固定,它可能随着训练实例数量的增加而增加。
KNN模型只基于一个假设:互相接近的实例拥有类似的响应变量值。
3.3 KNN模型分类
本章中我们会使用KNN模型的二元分类功能解决一个根据身高和体重预测性别的分类问题。
身高 | 体重 | 性别 |
---|---|---|
158cm | 64kg | 男 |
170cm | 66kg | 男 |
183cm | 84kg | 男 |
191cm | 80kg | 男 |
155cm | 49kg | 女 |
163cm | 59kg | 女 |
180cm | 67kg | 女 |
158cm | 54kg | 女 |
178cm | 77kg | 女 |
3.3.1导入数据
import numpy as np
import matplotlib.pyplot as plt
X_train = np.array([
[158, 64],
[170, 86],
[183, 84],
[191, 80],
[155, 49],
[163, 59],
[180, 67],
[158, 54],
[170, 67]
])
y_train = ['male', 'male', 'male', 'male', 'female', 'female', 'female', 'female', 'female']
plt.figure()
plt.title('Human Heights and Weights by Sex')
plt.xlabel('Height in cm')
plt.ylabel('Weight in kg')
for i, x in enumerate(X_train):
plt.scatter(x[0], x[1], c='k', marker='x' if y_train[i] == 'male' else 'D')
plt.grid(True)
plt.show()
3.3.2 KNN模型二元分类原理
# 测算距离
x = np.array([155, 70])
distances = np.sqrt(np.sum((X_train - x) ** 2, axis=1))
print(distances)
# 选择最近的k个数据(此处k=3)
nearest_neighbor_indices = distances.argsort()[:3]
nearest_neighbor_genders = np.take(y_train, nearest_neighbor_indices)
print(nearest_neighbor_genders)
# 现实出现次数最多的标签
from collections import Counter
b = Counter(np.take(y_train, distances.argsort()[:3]))
print(b.most_common(1)[0][0])
3.3.3 创建KNN分类器
from sklearn.preprocessing import LabelBinarizer
from sklearn.neighbors import KNeighborsClassifier
lb = LabelBinarizer()
y_train_binarized = lb.fit_transform(y_train)
print(y_train_binarized)
K = 3
clf = KNeighborsClassifier(n_neighbors=K)
clf.fit(X_train, y_train_binarized.reshape(-1))
prediction_binarized = clf.predict(np.array([155, 70]).reshape(1,-1))[0]
predicted_label = lb.inverse_transform(prediction_binarized)
print(predicted_label)
讲解:
我们的标签(male和female)是字符串,因此应首先将其转换为整数,这里使用了LabelBinarized类,意为将标签进行二元整数化。该类实现了转换器接口,其中包含fit、transform和fit_transform方法。fit可以理解为根据输入数据归纳出对应转换法则但不会进行转换,如果想实现归纳规则的同时实现转换,应使用fit_transform,同样遵循"an array in, an array out"原则。在归纳好法则后,每一次转换都要使用transform,不需要再调用fit_transform。
3.3.4 预测结果
X_test = np.array([
[168, 65],
[180, 96],
[160, 52],
[169, 67]
])
y_test = ['male', 'male', 'female', 'female']
y_test_binarized = lb.transform(y_test)
print('Binarized labels: %s' % y_test_binarized.T[0])
predictions_binarized = clf.predict(X_test)
print('Binarized predictions: %s' % predictions_binarized)
print('Predicted labels: %s' % lb.inverse_transform(predictions_binarized))
3.3.5 评价结果
3.3.5.1 准确率
即查对了几个:
from sklearn.metrics import accuracy_score
print('Accuracy: %s' % accuracy_score(y_test_binarized, predictions_binarized))
3.3.5.2 精确率
即查出来的正向类有几个是真正向类(此处选定男性为正向类)
from sklearn.metrics import precision_score
print('Precision: %s' % precision_score(y_test_binarized, predictions_binarized))
3.3.5.3 召回率
即男性被我们的模型检测出来的比例
from sklearn.metrics import recall_score
print('Precision: %s' % recall_score(y_test_binarized, predictions_binarized))
3.3.5.4 F1度量 / F1得分
即精准率和召回率的调和平均值
from sklearn.metrics import f1_score
print('Precision: %s' % f1_score(y_test_binarized, predictions_binarized))
注:a和b的调和平均值定义为:
2
1
a
+
1
b
\frac{2}{\frac{1}{a}+\frac{1}{b}}
a1+b12
3.3.5.5 马修斯相关系数(MCC)
完美分类器的MCC为1,随机分类器的MCC为0,完全错误预测的分类器MCC为-1
from sklearn.metrics import matthews_corrcoef
print('Matthews correlation coefficient: %s' % matthews_corrcoef(y_test_binarized, predictions_binarized))
3.3.5.6 分类汇总
from sklearn.metrics import classification_report
print(classification_report(y_test_binarized, predictions_binarized))
结果:
3.4 KNN 模型回归
3.4.1 导入数据并创建回归器
现在研究问题改变为:已知身高和性别,预测体重。
from sklearn.neighbors import KNeighborsRegressor
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
X_train = np.array([
[158,1],
[170,1],
[183,1],
[191,1],
[155,0],
[163,0],
[180,0],
[158,0],
[170,0]
])
y_train = [64, 86, 84, 80, 49, 59, 67, 54, 67]
X_test = np.array([
[168,1],
[180,1],
[160,0],
[169,0]
])
y_test = [65, 96, 52, 67]
K = 3
clf = KNeighborsRegressor(n_neighbors=K)
clf.fit(X_train, y_train)
predictions = clf.predict(X_test)
print("Predicted weights: %s" % predictions)
3.4.2 评价模型
print("Coefficient of determination: %s" % r2_score(y_test, predictions))
print("Mean absolute error: %s" % mean_absolute_error(y_test, predictions))
print("Mean squared error: %s" % mean_squared_error(y_test, predictions))
M
A
E
=
1
n
∑
i
=
0
n
−
1
∣
y
i
−
y
i
^
∣
MAE = \frac{1}{n}\sum^{n-1}_{i=0}|y_i - \hat{y_i}|
MAE=n1i=0∑n−1∣yi−yi^∣
M
A
E
=
1
n
∑
i
=
0
n
−
1
(
y
i
−
y
i
^
)
2
MAE = \frac{1}{n}\sum^{n-1}_{i=0}(y_i - \hat{y_i})^2
MAE=n1i=0∑n−1(yi−yi^)2
此两者中,MSE(均方偏差)是性能衡量指标的不二选择。
3.4.3 使用特征缩放技术优化模型
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
X_train_scaled = ss.fit_transform(X_train)
print(X_train)
print(X_train_scaled)
X_test_scaled = ss.transform(X_test)
clf.fit(X_train_scaled, y_train)
predictions = clf.predict(X_test_scaled)
print("Predicted weights: %s" % predictions)
print("Coefficient of determination: %s" % r2_score(y_test, predictions))
print("Mean absolute error: %s" % mean_absolute_error(y_test, predictions))
print("Mean squared error: %s" % mean_squared_error(y_test, predictions))
讲解:
当特征具有相同的取值范围时,很多学习算法会运行得更好。上例中,我们使用了sklearn.preprocessing库中的StandardScaler类将数据进行标准化,其中标准化数据是指均值为0,方差为1的数据集。