文章目录
逻辑回归
逻辑回归(Logistic Regression)虽然是一种广泛使用的分类算法,但它通常更适用于二分类问题。然而,通过一些策略(如一对多分类,也称为OvR或One-vs-Rest),逻辑回归也可以被扩展到多分类问题,如手写数字识别(通常是0到9的10个类别)。
本篇我们就来尝试一下如何通过逻辑回归来实现手写数字识别:
- 训练模型
- 测试模型
实现手写数字识别
训练模型
- 收集数据
- 读取图片
使用opencv处理图片,将图片的像素数值读取进来,并返回的是一个三维(高,宽,颜色)numpy数组:
pip install opencv-python==3.4.11.45
import cv2
img = cv2.imread("digits.png")
- 转为灰度图
将图片转化为灰度图,从而让三维数组变成二位的数组:
grey = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
- 处理图片信息
对图片进行处理:将其先垂直切分(横向)成50份,再将每一份水平切分(竖向)成100份,这样我们的每份图片的像素值都为20*20(训练的图片比较规范)共500个,比如:
import numpy as np
img_info = [np.hsplit(row,100) for row in np.vsplit(grey,50)]
- 装进array数组
将切分的每一份图片像素数据都装进array数组中:
x = np.array(img_info)
- 分隔训练集与测试集
将数据竖着分隔一半,一半作为训练集,一般作为测试集:
train_x = x[:,:50]
test_x = x[:,50:100]
- 调整数据结构
由于我们最后要将数据放在逻辑回归模型中训练,我们得将数据结构调整为适合逻辑回归算法训练的结构,那么我们就来改变每份图片数组的维度:reshape:
new_train_x = train_x.reshape(-1,400).astype(np.float32)
new_test_x = test_x.reshape(-1,400).astype(np.float32)
- Z-score标准化
逻辑回归算法进行手写数字识别时,对数据进行标准化是为了提高优化算法的收敛速度、提升模型的预测性能,并避免潜在的数值问题。将数据都进行表示话,避免参数的影响:
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
fin_train = scaler.fit_transform(new_train_x)
fin_test = scaler.fit_transform(new_test_x)
- 分配标签
我们训练着那么多的数据,却没有给他们具体的类别标签(图像的实际值),因为我们之前的图像处理都是在寻找图像特征,但是并没有给他们一个具体对应的类别,只有空荡荡的特征,无法分类,所以我们得给切分的每份图片打上它们对应的标签:
k = np.arange(10)
train_y = np.repeat(k,250)
test_y = np.repeat(k,250)
train_y = train_y.ravel()
- 交叉验证
在逻辑回归的算法中,逻辑模型的参数中,有一参数为正则化强度C,越小的数值表示越强的正则化。我们要进行调参数,看看哪个惩罚因子最为合适,使模型拟合效果更好:
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
#交叉验证选择较优的惩罚因子
scores = []
c_param_range = [0.01,0.1,1,10,100] #参数:一般常用的惩罚因子
for i in c_param_range:
lr = LogisticRegression(C = i,penalty='l2',solver='lbfgs',max_iter=1000,random_state=0)
# C表示正则化强度,越小的数值表示越强的正则化。防止过拟合
score = cross_val_score(lr,fin_train,train_y,cv=10,scoring='recall_macro')
#交叉验证,将模型和数据集传入,对其进行划分,每份轮流作为测试集来测试模型。返回一个列表对象
score_mean = sum(score)/len(score)
scores.append(score_mean)
c_choose = c_parma[np.argmax(scores)] #argmax取出最大值的索引位置
- 训练模型
lr_model = LogisticRegression(C = c_choose,max_iter=1000,random_state=0)
lr_model.fit(fin_train,train_y)
测试模型
- 先用训练数据再次进入模型测试,查看他本身的模型训练效果怎么样:
from sklearn import metrics
train_predict = lr_model.predict(fin_train)
print(metrics.classification_report(train_y,train_predict)) #查看混淆矩阵
-------------------------------
precision recall f1-score support
0 0.99 1.00 0.99 250
1 0.98 1.00 0.99 250
2 1.00 0.98 0.99 250
3 0.98 0.98 0.98 250
4 1.00 1.00 1.00 250
5 0.98 0.98 0.98 250
6 0.99 1.00 1.00 250
7 0.98 0.99 0.98 250
8 0.98 0.99 0.99 250
9 0.99 0.97 0.98 250
accuracy 0.99 2500
macro avg 0.99 0.99 0.99 2500
weighted avg 0.99 0.99 0.99 2500
- 再用分割的测试集来测试模型:
test_predict = lr_model.predict(fin_test)
print(metrics.classification_report(test_y,test_predict))
---------------------------
precision recall f1-score support
0 0.95 0.96 0.95 250
1 0.94 0.96 0.95 250
2 0.88 0.86 0.87 250
3 0.90 0.86 0.88 250
4 0.92 0.84 0.88 250
5 0.84 0.90 0.87 250
6 0.92 0.95 0.93 250
7 0.89 0.93 0.91 250
8 0.89 0.84 0.86 250
9 0.83 0.86 0.85 250
accuracy 0.90 2500
macro avg 0.90 0.90 0.89 2500
weighted avg 0.90 0.90 0.89 2500
到这为止!!我们就训练好一个关于手写数字识别的逻辑回归模型啦!!
总结
本篇介绍了如何用逻辑回归算法实现手写数字识别:
- 逻辑回归更适合二分类算法,但是也可以通过一些策略,扩展到多分类问题。
- 注意要将读取的数据进行标准化操作,灰度图图片数据相差过大。
- 学会调整参数,优化模型,比如本篇在交叉验证中找寻最优的惩罚因子。