逻辑回归
我们之前讲述了线性回归,那么这里面引入逻辑回归,逻辑回归更侧重于数据的分类。
我们在线性回归中所说的无论是一元线性回归,多元线性回归或者是多项式回归,其函数构造成代价函数之后可能是非凸函数,所以使用
梯度下降法可能会造成求出的是局部最小值。
所以我们在参数回归中所用到的函数是 sigmoid函数,而且是用参数矩阵和sigmoid函数所结合:
在图像中我们用0.5作为边界,大于0.5的都可以归到1里面,小于0.5的都可以归于0中,便于分类。
我们想要想到决策边界,就是就数据分成不同类型的边界,这样我们在拥有已知数据时,就可以根据决策边界对未知类别的数据进行分类。例如:
构造逻辑回归的代价函数,因为根据刚才的图像,我们以0.5为边界线,大于0.5的分到1类,小于0.5的分为0类。所以在逻辑回归中定义的代价函数会有y有0和1两类就有两种。
图像表示的话就是:
当y等于0的时候也是一样的。
那么我们构造逻辑回归的代价函数的时候就应该将y=0和y=1两种情况合并在一起,变为:
这样y=0的时候或者y=1的时候就和分开的一样了,所以我们的逻辑回归代价函数为:
求的含参变量θ就为:
那么我们之后的重点就是对J(θ)求导的问题了:
其中:
求导的时候要记得分布求导,避免少项缺项,之后再用:
求得含参系数即可。
逻辑回归代价函数的正则化:
正则化逻辑回归代价函数和之前的正则化线性回归代价函数是一样的,都是在普通代价函数之后添项变成L1或L2正则化。
正确率 召回率 综合评价指标
就是我们在构造出逻辑回归的模型之后我们可以用于检验我们构造的吻合程度是怎么样的,用于评断我们构造模型的所能达到的程度是多少。
代码部分:
导入包:
import matplotlib.pyplot as plt
import numpy as np
from sklearn.metrics import classification_report
from sklearn import preprocessing
# 数据是否需要标准化
scale = True
导入并处理数据:
# 载入数据
data = np.genfromtxt("LR-testSet.csv", delimiter=",")
x_data = data[:,:-1]
y_data = data[:,-1]
def plot():
x0 = []
x1 = []
y0 = []
y1 = []
# 切分不同类别的数据
for i in range(len(x_data)):
if y_data[i]==0:
x0.append(x_data[i,0]) # 如果数据后面的标记位是0,那么把第一个数据传入x0中,第二个数据传入y0中
y0.append(x_data[i,1])
else:
x1.append(x_data[i,0]) # 如果数据后面的标记位是1,那么把第一个数据传入x1中,第二个数据传入y1中
y1.append(x_data[i,1])
# 画图
scatter0 = plt.scatter(x0, y0, c='b', marker='o')
scatter1 = plt.scatter(x1, y1, c='r', marker='x')
#画图例
plt.legend(handles=[scatter0,scatter1],labels=['label0','label1'],loc='best')
plot()
plt.show()
因为我们的数据都是用0和1在最后做了标注存入了y_data中,就是已经分成了不同的两类,所以我们把不同的类存入不同的数组,最后用不同的颜色将点画出来:
给数据添加偏置项
# 数据处理,添加偏置项
x_data = data[:,:-1]
y_data = data[:,-1,np.newaxis]
print(np.mat(x_data).shape)
print(np.mat(y_data).shape)
# 给样本添加偏置项
X_data = np.concatenate((np.ones((100,1)),x_data),axis=1)
因为是矩阵运算,就和我们在标准方程法中添加的偏置项一样。
构建各种函数
# 构造sigmoid函数
def sigmoid(x):
return 1.0/(1+np.exp(-x))
# 逻辑回归的代价函数
def cost(xMat, yMat, ws):
left = np.multiply(yMat, np.log(sigmoid(xMat*ws)))
right = np.multiply(1 - yMat, np.log(1 - sigmoid(xMat*ws)))
return np.sum(left + right) / -(len(xMat))
def gradAscent(xArr, yArr):
if scale == True:
xArr = preprocessing.scale(xArr)
xMat = np.mat(xArr)
yMat = np.mat(yArr)
lr = 0.001
epochs = 10000
costList = []
# 计算数据行列数
# 行代表数据个数,列代表权值个数
m,n = np.shape(xMat)
# 初始化权值
# ws就相当于公式中的θT
ws = np.mat(np.ones((n,1)))
for i in range(epochs+1):
# xMat和weights矩阵相乘
h = sigmoid(xMat*ws)
# 计算误差
ws_grad = xMat.T*(h - yMat)/m
ws = ws - lr*ws_grad
if i % 50 == 0:
costList.append(cost(xMat,yMat,ws))
return ws,costList
# 训练模型,得到权值和cost值的变化
ws,costList = gradAscent(X_data, y_data)
画图:
# 画图 loss值的变化
x = np.linspace(0,10000,201)
plt.plot(x, costList, c='r')
plt.title('Train')
plt.xlabel('Epochs')
plt.ylabel('Cost')
plt.show()
预测
# 预测
def predict(x_data, ws):
if scale == True:
x_data = preprocessing.scale(x_data)
xMat = np.mat(x_data)
ws = np.mat(ws)
return [1 if x >= 0.5 else 0 for x in sigmoid(xMat*ws)]
predictions = predict(X_data, ws)
print(classification_report(y_data, predictions))
sklearn实现
导入包
import matplotlib.pyplot as plt
import numpy as np
from sklearn.metrics import classification_report
from sklearn import preprocessing
from sklearn import linear_model
# 数据是否需要标准化
scale = False
处理导入数据
# 载入数据
data = np.genfromtxt("LR-testSet.csv", delimiter=",")
x_data = data[:,:-1]
y_data = data[:,-1]
def plot():
x0 = []
x1 = []
y0 = []
y1 = []
# 切分不同类别的数据
for i in range(len(x_data)):
if y_data[i]==0:
x0.append(x_data[i,0])
y0.append(x_data[i,1])
else:
x1.append(x_data[i,0])
y1.append(x_data[i,1])
# 画图
scatter0 = plt.scatter(x0, y0, c='b', marker='o')
scatter1 = plt.scatter(x1, y1, c='r', marker='x')
#画图例
plt.legend(handles=[scatter0,scatter1],labels=['label0','label1'],loc='best')
plot()
plt.show()
构造逻辑回归模型
logistic = linear_model.LogisticRegression()
logistic.fit(x_data, y_data)
图像模型
if scale == False:
# 画图决策边界
plot()
x_test = np.array([[-4],[3]])
y_test = (-logistic.intercept_ - x_test*logistic.coef_[0][0])/logistic.coef_[0][1]
plt.plot(x_test, y_test, 'k')
plt.show()
最后做预测函数
predictions = logistic.predict(x_data)
print(classification_report(y_data, predictions))
非线性逻辑回归:
非线性逻辑回归和线性逻辑回归对比的话,就相当于是线性回归中一元线性回归和多项式回归一样,所以在代码部分只要加上多项式回归中的PolynomialFeatures模型就可以了。
代码部分:
导入包
import matplotlib.pyplot as plt
import numpy as np
from sklearn.metrics import classification_report
from sklearn import preprocessing
from sklearn.preprocessing import PolynomialFeatures
# 数据是否需要标准化
scale = False
导入和处理数据
# 载入数据
data = np.genfromtxt("LR-testSet2.txt", delimiter=",")
x_data = data[:,:-1]
y_data = data[:,-1,np.newaxis]
def plot():
x0 = []
x1 = []
y0 = []
y1 = []
# 切分不同类别的数据
for i in range(len(x_data)):
if y_data[i]==0:
x0.append(x_data[i,0])
y0.append(x_data[i,1])
else:
x1.append(x_data[i,0])
y1.append(x_data[i,1])
# 画图
scatter0 = plt.scatter(x0, y0, c='b', marker='o')
scatter1 = plt.scatter(x1, y1, c='r', marker='x')
#画图例
plt.legend(handles=[scatter0,scatter1],labels=['label0','label1'],loc='best')
plot()
plt.show()
定义多项式回归
# 定义多项式回归,degree的值可以调节多项式的特征
poly_reg = PolynomialFeatures(degree=3)
# 特征处理
x_poly = poly_reg.fit_transform(x_data)
构造各种函数
def sigmoid(x):
return 1.0/(1+np.exp(-x))
def cost(xMat, yMat, ws):
left = np.multiply(yMat, np.log(sigmoid(xMat*ws)))
right = np.multiply(1 - yMat, np.log(1 - sigmoid(xMat*ws)))
return np.sum(left + right) / -(len(xMat))
def gradAscent(xArr, yArr):
if scale == True:
xArr = preprocessing.scale(xArr)
xMat = np.mat(xArr)
yMat = np.mat(yArr)
lr = 0.03
epochs = 50000
costList = []
# 计算数据列数,有几列就有几个权值
m,n = np.shape(xMat)
# 初始化权值
ws = np.mat(np.ones((n,1)))
for i in range(epochs+1):
# xMat和weights矩阵相乘
h = sigmoid(xMat*ws)
# 计算误差
ws_grad = xMat.T*(h - yMat)/m
ws = ws - lr*ws_grad
if i % 50 == 0:
costList.append(cost(xMat,yMat,ws))
return ws,costList
ws,costList = gradAscent(x_poly, y_data)
画图
# 获取数据值所在的范围
x_min, x_max = x_data[:, 0].min() - 1, x_data[:, 0].max() + 1
y_min, y_max = x_data[:, 1].min() - 1, x_data[:, 1].max() + 1
# 生成网格矩阵
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),
np.arange(y_min, y_max, 0.02))
z = sigmoid(poly_reg.fit_transform(np.c_[xx.ravel(), yy.ravel()]).dot(np.array(ws)))# ravel与flatten类似,多维数据转一维。flatten不会改变原始数据,ravel会改变原始数据
for i in range(len(z)):
if z[i] > 0.5:
z[i] = 1
else:
z[i] = 0
z = z.reshape(xx.shape)
# 等高线图
cs = plt.contourf(xx, yy, z)
plot()
plt.show()
对于画图,需要注意的点是:
获取数据值所在的范围
x_min, x_max = x_data[:, 0].min() - 1, x_data[:, 0].max() + 1
y_min, y_max = x_data[:, 1].min() - 1, x_data[:, 1].max() + 1生成网格矩阵
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),np.arange(y_min, y_max, 0.02))
首先获得x坐标的上下限,y的上下限,那么这样根据xy的上下限就可以确定出一个网格为,np.meshgrid生成网格矩阵最后一个参数控制网格距离的大小。加入是0.2的话:
换成0.02的话:
np.r_按row来组合array,
np.c_按colunm来组合array
>>> a = np.array([1,2,3])
>>> b = np.array([5,2,5])
>>> np.r_[a,b]
array([1, 2, 3, 5, 2, 5])
>>> np.c_[a,b]
array([[1, 5],
[2, 2],
[3, 5]])
>>> np.c_[a,[0,0,0],b]
array([[1, 0, 5],
[2, 0, 2],
[3, 0, 5]])
预测
# 预测
def predict(x_data, ws):
# if scale == True:
# x_data = preprocessing.scale(x_data)
xMat = np.mat(x_data)
ws = np.mat(ws)
return [1 if x >= 0.5 else 0 for x in sigmoid(xMat*ws)]
predictions = predict(x_poly, ws)
print(classification_report(y_data, predictions))