一 评价尺度
sklearn包含四种评价尺度
1 均方差(mean-squared-error)
2 平均绝对值误差(mean_absolute_error)
3 可释方差得分(explained_variance_score)
4 中值绝对误差(Median absolute error)
5 R2 决定系数(拟合优度)
- 模型越好:r2→1
- 模型越差:r2→0
二 逻辑斯蒂回归
1 概述
在逻辑斯蒂回归中,我们将会采用sigmoid函数作为激励函数,所以它被称为sigmoid回归或对数几率回归(logistic regression),需要注意的是,虽然带有回归,但事实上它并不是一种回归算法,而是一种分类算法。
优点:
1 它是直接对分类的可能性进行建模的,无需事先假设数据分布,这样就避免了假设分布不准确所带来的问题
2 其针对于分类的可能性进行建模的,所以它不仅能预测出类别,还可以得到属于该类别的概率
3 实现简单,易于理解和实现;计算代价不高,速度很快,存储资源低
4 数据量大就用逻辑斯蒂 数据量小,特征多,用SVM knn
缺点:
容易欠拟合,分类精度可能不高
线性回归与逻辑回归的区别
线性回归: 线性回归用来做回归预测,解决回归问题
根据几组已知数据和拟合函数训练其中未知参数,使得拟合损失达到最小。然后用所得拟合函数进行预测。
逻辑回归: 逻辑回归用于做二分类 , 解决分类问题
和拟合函数训练其中未知参数 , 使得对数似然函数最大。然后用所得的拟合函数进行二分类。
线性回归 | 逻辑回归 | |
---|---|---|
目的 | 预测 | 分类 |
未知 | {0,1} | |
函数 | 拟合函数 | 预测函数 |
参数计算方式 | 最小二乘 | 最大似然估计 |
注意:
1 预测函数其实就是拟合函数做了一个逻辑函数的转换
2 最大似然估计是计算使得数据出现的可能性最大的参数,依仗的自然是Probability。而最小二乘是计算误差损失。因此两者不可混淆
(2) 本质的区分
逻辑回归就是对线性回归做了一个压缩,将y 的值从y∈(+∞,−∞)压缩到(0,1)。为什么简单的压缩就能将回归问题变成分类问题?
从数据说起,线性回归的样本的输出,都是连续值,y∈(+∞,−∞)而,逻辑回归中y∈{0,1},只能取0和1。对于拟合函数也有本质上的差别:
\[ 逻辑回归:f(x)=p(y=1∣x;θ)=g(θTX) \]
\[ 线性回归:f(x)=θTX=θ1x1+θ2x2+⋯+θnxn \]
线性回归拟合函数,的确是对f(x)的输出变量y的拟合,而逻辑回归的拟合函数是对为1类的样本概率拟合。
-
为什么采用1类的样本概率进行拟合,这里就要谈到logstic函数的本质
若要直接通过回归的方法去预测二分类问题, y 到底是0类还是1类,最好的函数是单位阶跃函数。然而单位阶跃函数不连续(GLM 的必要条件),而 logsitic 函数恰好接近于单位阶跃函数,且单调可微。于是希望通过该复合函数去拟合分类问题,产生:
于是,θTX=0就相当于是1类和0类的决策边界:
\[ 当θTX>0,则有y>0.5;若θTX→+∞ ,则y→1 ,即y 为1类; \]
-
\[ 当θTX<0,则有y<0.5 ; 若θTX→−∞,则y→0,即 y 为0类。 \]
这个时候就能看出区别来了,在线性回归中θTXθTX为预测值的拟合函数;而在逻辑回归中θTX=0为决策边界
因此利用Logistics回归进行分类的主要思想是:根据现有数据对分类边界线建立回归公式,以此进行分类。
三 Logistic Regression实战练习
实例: 手写数字分类
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
import matplotlib.pyplot as plt
%matplotlib inline
# LogisticRegression虽然是线性回归模型,但是只能处理分类问题
# 概率模型,使用概率进行分类
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
# 加载手写数字集
from sklearn import datasets
digits = datasets.load_digits() #
#输出 {'data': array([[ 0., 0., 5., ..., 0., 0., 0.],
[ 0., 0., 0., ..., 10., 0., 0.],
[ 0., 0., 0., ..., 16., 9., 0.],
...,
[ 0., 0., 1., ..., 6., 0., 0.],
[ 0., 0., 2., ..., 12., 0., 0.],
[ 0., 0., 10., ..., 12., 1., 0.]]),
'target': array([0, 1, 2, ..., 8, 9, 8]),
'target_names': array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
'images': array([[[ 0., 0., 5., ..., 1., 0., 0.],
[ 0., 0., 13., ..., 15., 5., 0.],
....
data = digits.data #(1797, 64) 表示1797条,一维64的矩阵
images = digits.images #(1797, 8, 8) 表示1797条,8*8的二维矩阵
display(data.shape,images.shape)
plt.imshow(images[0],cmap='gray')
plt.imshow(data[0].reshape((8,8)),cmap='gray') #将64一维转成8*8的二维矩阵实际都是表示一组数据
# 对数据集进行拆分,得到训练集和测试集
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(data,target,test_size=0.2,random_state=1)
#采用逻辑斯蒂回归模型与KNN
logistic = LogisticRegression()
knn = KNeighborsClassifier(n_neighbors=5)
#对knn与逻辑斯蒂进行训练
logistic.fit(X_train,y_train)
y1_ = logistic.predict(X_test)
knn.fit(X_train,y_train)
y2_ = knn.predict(X_test)
查看模型评分
# 分类模型可以查看准确率来对模型进行评价
# 直接用算法模型调用score方法来实现
logistic.score(X_test,y_test)
knn.score(X_test,y_test)
#输出 0.9694444444444444
0.9944444444444445
# 模型在测试集上评分特别高,但是在真实环境下准确率却很低,这叫病态
# 引起这种现象的原因,主要是算法训练的过度拟合
分类展示
# 展示分类的成果
# 取测试集的前100个数据
plt.figure(figsize=(12,16))
for i in range(100):
axes = plt.subplot(10,10,i+1)
img = X_test[i].reshape((8,8))
axes.imshow(img,cmap='gray')
axes.axis('off')
true = y_test[i]
knn_r = y2_[i]
logistic_r = y1_[i]
title = 'T:'+str(true)+'\nK:'+str(knn_r) + ' L:'+str(logistic_r)
axes.set_title(title)
# 对logistic函数进行调参,查看参数对结果的影响
# 超参 函数级别 knn n_neibors logistic pentily C
# 模型参数 f(x) = wx+b
logistic = LogisticRegression(C=0.5,penalty='l1')
logistic.fit(X_train,y_train)
logistic.score(X_test,y_test)
#0.975
人脸的自动补全
导包
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
from sklearn.datasets import fetch_olivetti_faces
import matplotlib.pyplot as plt
%matplotlib inline
提取数据
faces = fetch_olivetti_faces()
data = faces.data
images = faces.images
target = faces.target
拆分测试训练集
from sklearn.linear_model import LinearRegression,Ridge,Lasso
from sklearn.neighbors import KNeighborsRegressor
# 拆分训练集和测试集
from sklearn.model_selection import train_test_split
# 每个人拿出9张照片做训练数据,拿出1张照片做测试数据
# 样本特征采用上半边脸,样本标签采用下半边脸
def train_test_split_face(data,test_size):
X_train = []
X_test = []
y_train = []
y_test = []
for i in range(40):
for j in range(10):
face = data[i*10+j]
up_face = face[:2048]
bottom_face = face[2048:]
if j < (1-test_size)*10:
# 保存为训练数据
X_train.append(up_face)
y_train.append(bottom_face)
else:
# 保存为测试数据
X_test.append(up_face)
y_test.append(bottom_face)
return np.array(X_train),np.array(X_test),np.array(y_train),np.array(y_test)
#训练集与测试集
X_train,X_test,y_train,y_test = train_test_split_face(data,test_size=0.1)
#拆分出的上下半边脸
plt.imshow(X_train[0].reshape((32,64)),cmap='gray')
plt.imshow(y_train[0].reshape((32,64)),cmap='gray')
训练模型
knn = KNeighborsRegressor()
linear = LinearRegression()
ridge = Ridge()
lasso = Lasso()
knn.fit(X_train,y_train)
linear.fit(X_train,y_train)
ridge.fit(X_train,y_train)
lasso.fit(X_train,y_train)
预测数据
# 预测所有数据
knn_y_ = knn.predict(X_test)
linear_y_ = linear.predict(X_test)
ridge_y_ = ridge.predict(X_test)
lasso_y_ = lasso.predict(X_test)
plt.figure(figsize=(10,4))
true_up_face = X_test[0]
true_bottom_face = y_test[0]
pre_bottom_face = knn_y_[0]
axes1 = plt.subplot(1,2,1)
true_face = np.concatenate((true_up_face,true_bottom_face))
axes1.imshow(true_face.reshape((64,64)),cmap='gray')
axes1.set_title('True')
axes2 = plt.subplot(1,2,2)
pre_face = np.concatenate((true_up_face,pre_bottom_face))
axes2.imshow(pre_face.reshape((64,64)),cmap='gray')
axes2.set_title('Predict')
results = np.array([knn_y_,ridge_y_,lasso_y_,linear_y_])
titles = np.array(['KNN','RIDGE','LASSO','LINEAR'])
plt.figure(figsize=(16,18))
for i in range(5):
true_up_face = X_test[i]
true_bottom_face = y_test[i]
true_face = np.concatenate((true_up_face,true_bottom_face)).reshape((64,64))
axes = plt.subplot(5,5,i*5+1)
axes.imshow(true_face,cmap='gray')
axes.set_title('True')
for index,y_ in enumerate(results):
axes = plt.subplot(5,5,i*5+1+index+1)
pre_bottom_face = y_[index]
pre_face = np.concatenate((true_up_face,pre_bottom_face)).reshape((64,64))
axes.imshow(pre_face,cmap='gray')
axes.set_title(titles[index])
数据量较少,仅为测试使用