学习机器学习已经有一周了。和许多机器学习的初学者一样,首先接触的就是Linear Regression和 Logistic Regression.
二者都是在确定了方法集(Model)之后,利用Gradient Descent 求的相关损失函数的最小值,从而确定权重W以及偏置Bias的过程。但是,二者在Model , Loss Functions 以及如何找最佳解答方向上有所区别,具体区别如下:
首先在Logistic regression中,Model采用Sigmod作为阈值函数,在Python中,实现sigmod函数十分简单:
#定义sigmod 函数
def sig(x):
'''
input : x(mat):feature * w
output : sigmod 值
即为 P(C1|X)的概率
:param x:
:return:
'''
return 1.0/(1+np.exp(-x))
利用梯度下降(GD)原理,不断调整W的值,使得其朝着梯度的方向进行移动:
#Logistic Regression model
def Ir_train_bgd(features,labels,maxCycle,alpha):
n = np.shape(features)[1] # 特征值的个数,并且将其赋值给n
w = np.mat(np.ones((n,1))) # 初始化权重为1,而且数量为 n*1 的矩阵
i = 0 # 目前做 GD 的次数为0
while i<=maxCycle:
i = i+1
h = sig (features * w)
err = labels-h
if i%100==0:
print('\t------------------------'+str(i)+\
",train error rate= "+ str(error_rate(h,label)))
w= w+ alpha* features.T *err #修正权重, learning data
return w
至于如何评价损失函数,Linear Regression 与 Logistic Regression区别在于 : Linear Regression 损失函数 Loss Function 主要依据Square大小,而 Logistic Regression 则是交互熵损失函数来反应预测集和测试集两个伯努利分布的接近程度。
在了解算法的基本原理后,我们看看利用Python经常使用的机器学习库Sklearn 以及 OpenCv 的ML 库来正真实现 Logistic Regression 中的 Binary Classification问题。
#进入ML相关库文件
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
from sklearn import model_selection
from sklearn import metrics
from sklearn import datasets
#100表示样本数 ,2 表示特征数,centers表示类别数目y,cluster_std表示类别方差
X,y=datasets.make_blobs(100,2,centers=2,random_state=1000,cluster_std=2)
plt.scatter(X[:,0],X[:,1],s=100,c=y)
plt.xlabel("X1")
plt.ylabel("X2")
首先利用dataset的make_blobs方法,生成随意数组
为了能够在OpenCV中使用,我们需要将数据转化为float32
X=X.astype(np.float32)
y=y.astype(np.float32)
接着利用model_selection里面的train_test_spilt方法进行训练集与测试集的分类;其中训练集与测试集为9:1
X_train,X_test,y_train,y_test=model_selection.train_test_split(\
X,y,test_size=0.1,random_state=42)
利用Opencv的ml 库中,建立一个Logistic Regression 的分类器,并且在GD的方式上采用SGD的模式,即每次使用完一个数据点使用完后就要更新一次,设置更新次数为100次,即求100次关于W的偏导数。
Lr1.setTrainMethod(cv.ml.LOGISTIC_REGRESSION_MINI_BATCH)
Lr1.setMiniBatchSize(1)
Lr1.setIterations(100)
完成设置之后,对分类器Lr1进行训练:
Lr1.train(X_train,cv.ml.ROW_SAMPLE,y_train)
这个返回值的是一个布尔值,true/false 代表训练是否成功
C:\Users\asus\AppData\Local\Programs\Python\Python35-32\python.exe "D:/BaiduYunDownload/python_exe/daily exercise/OpenCV and MachineLearning/CSDN_logistic_regression.py"
True
Process finished with exit code 0
我们可以使用分类型的类方法get_learnt_thetas()获得最终的权重列表:
[[-0.00883594 0.2545947 0.352442 ]] 分别代表W0,W1,以及偏置常数b
我们可以将其转为列表,然后将其作为 多元方程输出:
weights=Lr1.get_learnt_thetas().tolist()[0]
b=weights[-1]
Ws= dict.fromkeys(['w0','w1'])
for i in range (len(weights)-1):
Ws['w{}'.format(str(i))]= weights[i]
print("function is : "
"y={}*X1+{}*X2+{}".format(Ws['w0'],Ws['w1'],b))
C:\Users\asus\AppData\Local\Programs\Python\Python35-32\python.exe "D:/BaiduYunDownload/python_exe/daily exercise/OpenCV and MachineLearning/CSDN_logistic_regression.py"
function is : y=-0.008835938759148121*X1+0.25459471344947815*X2+0.3524419963359833
Process finished with exit code 0
然后,我们利用训练好的分类器在测试集上做测试:
ret2,y_pred=Lr1.predict(X_test)
score = metrics.accuracy_score(y_pred,y_test)
print(score)
1.0
Process finished with exit code 0
我们可以看到,结果为1.0, 我们的分类器在测试集上很好。
我们可以尝试将最后的结果可视化:
def plot_descison_boundary(model,X_Train,y_train):
h=0.02 #确定网格间距
x_min,x_max=X_Train[:,0].min()-1,X_Train[:,0].max()+1 #确定feature 1的range
y_min,y_max=X_Train[:,1].min()-1,X_Train.max()+1 #确定 feature 2 的range
xx,yy=np.meshgrid(np.arange(x_min,x_max,h), #确定 feature 1与 feature 2 的位置矩阵
np.arange(y_min,y_max,h))
X_hyop =np.column_stack((xx.ravel().astype(np.float32),#将连个矩阵进行合并,成为(F1,F2)
yy.ravel().astype(np.float32))) 矩阵
ret2,zz=model.predict(X_hyop) # predic()返回值为两个,一个bool,一个predict-label
zz = zz.reshape(xx.shape) #制作等高线,需要xx,yy,zz的shape相同
plt.contourf(xx,yy,zz,cmap=plt.cm.coolwarm,alpha=0.8) #以冷热与基调
plt.scatter(X_Train[:,0],X_Train[:,1],c=y_train,s=100)
plt.show()
在函数中调用plot_descison_boundary,作用域在整体的数据集:
plt.title("this is a case of Logistic regression")
print(score)
plot_descison_boundary(Lr1,X,y)
可以看到分割效果不错。
接下来我们用Sklearn来进行实现:
from sklearn import linear_model
Lr2= linear_model.LogisticRegression()
Lr2.fit(X_train,y_train)
y_predict=Lr2.predict(X_test)
score= Lr2.score(X_test,y_test)
print(score)
plot_descison_boundary(Lr2,X,y)
注意:Lr2.predict返回值只有一项,即为y_predict 的array ,与OpenCv 的ml 不同,因此需要修改plot_descison_boundary函数
def plot_descison_boundary(model,X_Train,y_train):
h=0.02 #确定网格间距
x_min,x_max=X_Train[:,0].min()-1,X_Train[:,0].max()+1 #确定feature 1的range
y_min,y_max=X_Train[:,1].min()-1,X_Train.max()+1 #确定 feature 2 的range
xx,yy=np.meshgrid(np.arange(x_min,x_max,h), #确定 feature 1与 feature 2 的位置矩阵
np.arange(y_min,y_max,h))
X_hyop =np.column_stack((xx.ravel().astype(np.float32),#将连个矩阵进行合并,成为(F1,F2)矩阵
yy.ravel().astype(np.float32)))
zz = model.predict(X_hyop) # predic()返回值为两个,一个bool,一个predict-label
zz = zz.reshape(xx.shape) #制作等高线,需要xx,yy,zz的shape相同
plt.contourf(xx,yy,zz,cmap=plt.cm.coolwarm,alpha=0.8) #以冷热与基调
plt.scatter(X_Train[:,0],X_Train[:,1],c=y_train,s=100)
plt.show()
ok,最后结果如下,分隔效果良好: