本文侧重代码实现,不讨论原理。
github图床出了一点问题,就不插图了。
距离计算
欧氏距离:d(x,y)=k=1∑N?(xk??yk?)2?
曼哈顿距离:d(x,y)=k=1∑N?∣xk??yk?∣
切比雪夫距离:d(x,y)=max(∣xk??yk?∣)
余弦距离:cosθ=x12?+x22??y12?+y22??x1?x2?+y1?y2??
import numpy as np
dot1 = np.array([1,2])
dot2 = np.array([4,5])
d1 = np.sqrt(np.sum((dot1-dot2)**2))
d2 = np.sum(np.abs(dot1-dot2))
d3 = np.max(np.abs(dot1-dot2))
d4 = np.dot(dot1,dot2) / np.sqrt(np.dot(dot1,dot1)*np.dot(dot2,dot2))
模型选择
留出法
将数据分为训练集和测试集,使用训练集生成模型,使用测试集检验模型准确率。
train_test_split(data,data_lable,test_size=0.6)
from sklearn.model_selection import train_test_split
import numpy as np
data = np.array([10,21,23,53,63])
data_lable = [0,1,2,3,4]
"""
训练集数据, 测试集数据, 训练集标签, 测试集标签 =
train_test_split(数据列表,数据列表标签,test_size=训练集/总数)
"""
data_train, data_test, lable_train, lable_test = train_test_split(data,data_lable,test_size=0.6)
交叉验证法
相当于多次train_test_split 操作。将数据集划分为k个大小相似的子集,每次选取其中一个子集作为测试集,其他数据作为训练集。如[10,20,30,40],我们设k=4,则生成如下4种数据集:
训练集:[10,20,30],测试集:[40]
训练集:[10,20,40],测试集:[30]
训练集:[10,30,40],测试集:[20]
训练集:[20,30,40],测试集:[10]
代码如下:
"""
将data数组分成3折 : KFold(n_splits=3).split(data)
train_index:训练集索引 使用data[train_index]获取训练集
test_index:测试集索引 使用data[test_index]获取测试集
"""
for train_index, test_index in KFold(n_splits=3).split(data):
...略...
import numpy as np
from sklearn.model_selection import KFold
data = np.array([10,21,23,53,63,25])
for train_index, test_index in KFold(n_splits=3).split(data):
print("————————————————————————————————")
print("训练集索引:",train_index,"训练集:",data[train_index])
print("测试集索引:",test_index,"测试集:",data[test_index])
————————————————————————————————
训练集索引: [2 3 4 5] 训练集: [23 53 63 25]
测试集索引: [0 1] 测试集: [10 21]
————————————————————————————————
训练集索引: [0 1 4 5] 训练集: [10 21 63 25]
测试集索引: [2 3] 测试集: [23 53]
————————————————————————————————
训练集索引: [0 1 2 3] 训练集: [10 21 23 53]
测试集索引: [4 5] 测试集: [63 25]
留一法
交叉验证的变种,每次只留一个数据作为测试集。例如有n个数需要被划分,则留一法就相当于k=n的交叉验证。
for train_index, test_index in LeaveOneOut().split(data):
...略...
from sklearn.model_selection import LeaveOneOut
import numpy as np
data = np.array([10,20,30,40])
for train_index, test_index in LeaveOneOut().split(data):
print("————————————————————————————————")
print("训练集索引:",train_index,"训练集:",data[train_index])
print("测试集索引:",test_index,"测试集:",data[test_index])
————————————————————————————————
训练集索引: [1 2 3] 训练集: [20 30 40]
测试集索引: [0] 测试集: [10]
————————————————————————————————
训练集索引: [0 2 3] 训练集: [10 30 40]
测试集索引: [1] 测试集: [20]
————————————————————————————————
训练集索引: [0 1 3] 训练集: [10 20 40]
测试集索引: [2] 测试集: [30]
————————————————————————————————
训练集索引: [0 1 2] 训练集: [10 20 30]
测试集索引: [3] 测试集: [40]
性能度量
均方误差MSE
MSE=n1?i=1∑n?(f(xi?)?yi?)2
实现如下:
"""
均方误差 = mean_squared_error(真值列表,预测值列表)
"""
result = mean_squared_error(y_true, y_pred)
import numpy as np
from sklearn.metrics import mean_squared_error
y_true = np.array([1, 2, 3, 4, 5, 6])
y_pred = np.array([0, 2, 2, 4, 5, 7])
result = mean_squared_error(y_true, y_pred)
均方根误差RMSE
RMSE=n1?i=1∑n?(f(xi?)?yi?)2?
result = np.sqrt( mean_squared_error(y_true, y_pred) )
平均绝对误差MAE
MAE=n1?i=1∑m?∣f(xi?)?yi?∣
实现起来非常简单,就是将MSE中的mean_squared_error 替换成mean_absolute_error 。
import numpy as np
from sklearn.metrics import mean_absolute_erro
y_true = np.array([1, 2, 3, 4, 5, 6])
y_pred = np.array([0, 2, 2, 4, 5, 7])
result = mean_absolute_error(y_true, y_pred)
准确率
预测对的 / 所有
acc=n1?i=1∑n?(f(xi?)=yi?)
"""
准确率 = accuracy_score(正确数据列表,预测数据列表)
"""
result = accuracy_score(y_true,y_pred)
import numpy as np
from sklearn.metrics import accuracy_score
y_true = np.array([1, 2, 3, 4, 5, 6])
y_pred = np.array([0, 2, 2, 4, 5, 7])
result = accuracy_score(y_true,y_pred)
混淆矩阵
真实情况\预测结果 |
正例 |
反例 |
正例 |
TP(真正例) |
FN(假反例) |
反例 |
FP(假正例) |
TN(真反例) |
-
查准率:预测为正中,预测正确的概率
P=TP+FPTP?
-
查全率:真实情况为正中,预测正确的概率
R=TP+FNTP?
-
准确率
ACC=TP+FP+TN+FNTP+TN?
通过生成真实数据与预测数据的混淆矩阵,可以更好的看出预测的情况。
"""
混淆矩阵 = confusion_matrix(真实数据集,预测数据集,labels=标签集)
此处的标签集不好理解,看下面的样例就懂了
"""
result = confusion_matrix(y_true,y_pred,labels=[0,1])
import numpy as np
from sklearn.metrics import confusion_matrix
y_pred = np.array([0, 1, 0, 1])
y_true = np.array([1, 0, 1, 1])
result = confusion_matrix(y_true,y_pred,labels=[0,1])
[[0 1]
[2 1]]
上述输出可以用如下表格来解释
此处假设0为正例,1为反例
真实情况\预测结果 |
0 |
1 |
0 |
0 |
1 |
1 |
2 |
1 |
以上表格蕴含了以下信息:
真实情况 |
预测结果 |
预测次数 |
结果 |
0 |
0 |
0 |
真正例TP = 0 |
0 |
1 |
1 |
假反例FN = 1,预测错误1次 |
1 |
0 |
2 |
假正例FP = 2,预测错误2次 |
1 |
1 |
1 |
真反例TN = 1,预测成功1次 |
查准率=TP+FPTP?=0+20?=0
查全率=TP+FNTP?=0+10?=0
准确率=TP+FP+TN+FNTP+TN?=0+2+1+10+1?=41?
实际上,sklearn也提供了直接计算查准率的函数precision_score
import numpy as np
from sklearn.metrics import precision_score
y_pred = np.array([0, 1, 0, 1])
y_true = np.array([1, 0, 1, 1])
accu = precision_score(y_true,y_pred,average='macro')
ROC曲线
真实情况\预测结果 |
正例 |
反例 |
正例 |
TP(真正例) |
FN(假反例) |
反例 |
FP(假正例) |
TN(真反例) |
ROC曲线X轴:fpr=FP+TNFP?=真实情况中:反例总和真实情况中:反例预测错误的?
ROC曲线Y轴:tpr(查全率)=TP+FNTP?=真实情况中:正例总和真实情况中:正例中预测正确的?
在ROC曲线中,AUC(曲线下的面积)值越大,说明该模型性能越好。
"""
x轴列表, y轴列表, _ = roc_curve(真实数据,预测数据)
曲线下面积 = auc(x轴列表, y轴列表)
"""
fpr_x, tpr_y, _ = roc_curve(y_true, y_pred)
auc = auc(fpr_x, tpr_y)
import numpy as np
from sklearn.metrics import roc_curve, auc
y_pred = np.array([0.1, 0.8, 0.2, 0.5, 0.5, 0.7, 0.3, 0.1])
y_true = np.array([0, 1, 0, 1, 1, 1, 0, 1])
fpr_x, tpr_y, _ = roc_curve(y_true, y_pred)
auc = auc(fpr_x, tpr_y)
协方差Cov
Cov(X,Y)=n?1∑i=1n?(xi??x)(yi??y?)?
通过一个实例来计算:
- 为方便计算,我们只定义两个点,每个点(样本)有两个特征:x与y
dot1?=(1,3)dot2?=(5,7)(n=2)
-
用两个变量空间x,y分别表示特征对应的向量
x=[15?],y=[37?]
-
计算特征的均值
x=3,y?=5
-
计算协方差
Cov(x,x)=2?1(1?3)2+(5?3)2?=8Cov(x,y)=2?1(1?3)(3?5)+(5?3)(7?5)?=8Cov(y,x)=Cov(x,y)=8Cov(y,y)=2?1(3?5)2+(7?5)2?=8
-
生成协方差矩阵
Cov(z)=[Cov(x,x)Cov(y,x)?Cov(x,y)Cov(y,y)?]=[88?88?]
下面用代码实现上述过程:
import numpy as np
x = np.array([1,5])
y = np.array([3,7])
z = np.stack([x,y])
result = np.cov(z)
result的值
[[8. 8.]
[8. 8.]]
意义:协方差用来描述X和Y的相关程度
值范围 |
意义 |
Cov( X , Y ) < 0 |
X与Y负相关 |
Cov( X , Y ) > 0 |
X与Y正相关 |
Cov( X , Y ) = 0 |
X与Y不相关 |
Sklearn线性模型
线性回归
给一些点(xi,yi) ,用线性回归找出一条线y=wx+b ,该线能够最大程度的与点拟合。
通过这条回归线,我们能根据xi 预测出yi 的大概值。代码实现如下:
model = LinearRegression()
model.fit(x, y)
x_test = [[4], [5], [6]]
y_test = model.predict(x_test)
import numpy as np
from sklearn.linear_model import LinearRegression
x = np.array([0, 1, 2, 3, 4])
y = 3 * x + 2
x = x + np.random.rand(5)
x = [[i] for i in x]
y = [[i] for i in y]
model = LinearRegression()
model.fit(x, y)
x_test = [[4], [5], [6]]
y_test = model.predict(x_test)
print(y_test)
print("w值:", model.coef_)
print("b截距值为:", model.intercept_)
[[12.79914287]
[15.74000827]
[18.68087368]]
w值: [[2.9408654]]
b截距值为: [1.03568125]
上述代码生成了以下线性模型
y=wx+b=2.9408654x+1.03568125
将测试数据x代入该公式即可得到预测值y。
后面的pytorch部分将会通过梯度下降的方法来生成线性模型。
逻辑回归
以鸢尾花数据集为例。与上述线性回归极其相似,因此不作过多解释。
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
iris = datasets.load_iris()
iris_x = iris.data
iris_y = iris.target
x_train, x_test, y_train, y_test = train_test_split(iris_x, iris_y, test_size=0.1)
model = LogisticRegression()
model.fit(x_train, y_train)
y_pred = model.predict(x_test)
accu = accuracy_score(y_test, y_pred)
Pytorch简介
偏导数计算
计算 y=(x+w)(w+1)对x的偏导数,公式可以分解为下图:
用pytorch构建上述公式,可以很容易的求出偏导数,代码如下:
import torch
x = torch.tensor([2.0], requires_grad=True)
w = torch.tensor([1.0])
a = torch.add(x, w)
b = torch.add(w, 1)
y = torch.mul(a, b)
y.backward()
print(x.grad)
tensor([2.])
多次求导
backward(retain_graph=True) 可以保留计算图,再调用一次backward() 即可实现二阶求导。代码修改如下:
y.backward(retain_graph=True)
print(x.grad)
y.backward()
print(x.grad)
import torch
x = torch.tensor([2.0], requires_grad=True)
w = torch.tensor([1.0])
a = torch.add(x, w)
b = torch.add(w, 1)
y = torch.mul(a, b)
y.backward(retain_graph=True)
print(x.grad)
y.backward()
print(x.grad)
非标量输出
使用torch.cat() 函数我们可以将不同的函数结合到一起,实现下图计算:
y0=(x+w)(w+3) ?(y0)/?w = 7 ?loss/?w = ?(y0)/?w * 1 + ?(y1)/?w * 2 = 7 * 1 + 2 * 2 = 11 y1=(x+w)+(w+3) ?(y1)/?w = 2
代码实现如下
loss = torch.cat([y0, y1], dim=0)
loss_w = torch.tensor([1., 2.])
loss.backward(gradient=loss_w)
import torch
w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], )
a = torch.add(w, x)
b = torch.add(w, 3)
y0 = torch.mul(a, b)
y1 = torch.add(a, b)
loss = torch.cat([y0, y1], dim=0)
loss_w = torch.tensor([1., 2.])
loss.backward(gradient=loss_w)
print(w.grad)
tensor([11.])
线性回归
问题:给定若干(x,y) 点集,找出一条直线y=wx+b,使所有点到直线的距离之和最小。
目标:找到合适的w与b,使损失函数 L=N1?∑i=1N?(wxi?+b?ytrue?)2 的值最小。
方法:我们需要对损失函数关于w和b求导:?w?L?,?b?L?,然后使用公式
wt+1?=wt??μ?w?L?bt+1?=bt??μ?b?L?(μ:学习率,梯度下降的跨度)
不断调整w与b的值,直到得到合适的线性模型。
import matplotlib.pyplot as plt
import torch
x = torch.rand(20, 1) * 10
y = 2 * x + (5 + torch.randn(20, 1))
mu = 0.05
w = torch.tensor(5.0, requires_grad=True)
b = torch.tensor(10.0, requires_grad=True)
for i in range(1000):
"""向前传播,计算预测值 y_pred = wx + b"""
wx = torch.mul(w, x)
y_pred = torch.add(wx, b)
loss = (0.5 * (y - y_pred) ** 2).mean()
loss.backward()
w.data.sub_(mu * w.grad)
b.data.sub_(mu * b.grad)
if i != 999:
w.grad.zero_()
b.grad.zero_()
if i % 50 == 0:
plt.scatter(x.data.numpy(), y.data.numpy())
plt.plot(x.data.numpy(), y_pred.data.numpy())
plt.show()
SVM
基本原理
SVM的原理非常复杂,博主的水平不足以理解透彻并输出为文章,因此引用一位大佬的教程(是我见过写的最棒的,强推)
SVM原理:https://cloud.tencent.com/developer/article/1618598
重要公式
-
支持向量样本点到决策面方程的距离(上述文章中公式2.12)
d=∣∣w∣∣∣wTxi?+γ∣?=∣∣w∣∣1?,(xi?为支持向量)
-
线性SVM最优化问题的数学描述(2.14)
minw,γ?21?∣∣w∣∣2s.t.yi?(wTxi?+γ)≥1,i=1,2,...,m
代码实现
原理虽然不好理解,但是代码实现起来却非常非常简单。
import numpy as np
from sklearn.svm import SVC
x = np.array([[-1, -1], [-2, -1], [1, 1], [2, 1]])
y = np.array([1, 1, 2, 2])
model = SVC()
model.fit(x, y)
pred = model.predict([[-0.8, -1]])
print(pred)
指定核函数
通过调整SVC() 函数中的kernel 属性可以切换所使用的核函数。
下面我们通过不同的核函数来解决经典的鸢尾花分类问题。
clf_rbf = SVC(kernel='rbf')
clf_linear = SVC(kernel='linear')
clf_poly = SVC(kernel='poly')
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
iris = datasets.load_iris()
x = iris.data
y = iris.target
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3)
clf_rbf = SVC(kernel='rbf')
clf_rbf.fit(x_train, y_train)
score_rbf = clf_rbf.score(x_test, y_test)
print("rbf准确率 : %f" % score_rbf)
clf_linear = SVC(kernel='linear')
clf_linear.fit(x_train, y_train)
score_linear = clf_linear.score(x_test, y_test)
print("linear准确率 : %f" % score_linear)
clf_poly = SVC(kernel='poly')
clf_poly.fit(x_train, y_train)
score_poly = clf_poly.score(x_test, y_test)
print("poly准确率 : %f" % score_poly)
rbf准确率 : 0.977778
linear准确率 : 1.000000
poly准确率 : 0.977778
|