1.基于 Logistic 回歸和 Sigmoid 函式的分類
邏輯回歸適合于01情況的分類就是描述一個問題是或者不是,所以就引入sigmoid函式,因為這個函式可以將所有值變成0-1之間的一個值,這樣就方便算概率 首先我們可以先看看Sigmoid函式(又叫Logistic函式)將任意的輸入映射到了[0,1]區間我們在線性回歸中可以得到一個預測值,再將該值映射到sigmoid函式中這樣就完成了由值到概率的轉換,也就是分類任務,公式如下:

整合成一個公式,就變成了如下公式:

z是一個矩陣,θ是引數列向量(要求解的),x是樣本列向量(給定的資料集),θ^T表示θ的轉置
Sigmoid函式的輸入記為z,由下面公式得出:
z=w0x0+w1x1+w2x2+...+wnxn
如果采用向量的寫法,上述公式可以寫成z = wTx,它表示將這兩個數值向量對應元素相乘然后
全部加起來即得到z值,其中的向量x是分類器的輸入資料,向量w也就是我們要找到的最佳引數 (系數),從而使得分類器盡可能地精確,
邏輯回歸的簡單來說,就是根據資料得到的回歸直線方程z=a*x+b方程之后,將z作為sigmoid的輸入使得z的值轉化為在0-1之間的值,然后計算概率,最后根據sigmod函式的特點也就是當輸入為零的時候,函式值為0.5,以0.5為分界線來劃分資料的型別,
1.1梯度上升法
梯度上升演算法用來求函式的最大值,而梯度下降演算法用來求函式的最小值,
求一個函式的最大值,在數學中,是不是通過對函式求導,然后算出導數等于0,或者導數不存在的位置作為極值,然后如果極值只有一個開區間內是不是極值就是最大值,但是在實際應用中卻不是這么簡單的去求最大值,而是通過迭代的方式一步一步向最值點靠近,最后得到最值,這也就是梯度上升法的思想

其中,m為樣本的總數,y(i)表示第i個樣本的類別,x(i)表示第i個樣本,需要注意的是θ是多維向量,x(i)也是多維向量,
梯度上升迭代公式為:

代碼實作:
import matplotlib.pyplot as plt
import numpy as np
import warnings
warnings.filterwarnings('ignore')
def loadDataSet():
dataMat = [] #創建資料串列
labelMat = [] #創建標簽串列
fr = open('testSet.txt') #打開檔案
for line in fr.readlines(): #逐行讀取
lineArr = line.strip().split() #去回車,放入串列
dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])]) #添加資料
labelMat.append(int(lineArr[2])) #添加標簽
fr.close() #關閉檔案
return dataMat, labelMat #回傳
def sigmoid(inX):
return 1.0/(1+np.exp(-inX))
#dataMatIn,它是一個2維NumPy陣列,每列分別代表每個不同的特征,每行則代表每個訓練樣本
def gradAscent(dataMatIn,classLabels):
dataMatrix=np.mat(dataMatIn)#轉換成numpy的mat
labelMat=np.mat(classLabels).transpose()#為了便于矩陣運算,需要將該行向量轉換為列向量,做法是將原向量轉置,再將它賦值給labelMat
m,n=np.shape(dataMatrix) #回傳dataMatrix的大小,m為行數,n為列數,
alpha=0.001 #向目標移動的步長
maxCycles=500 #maxCycles是迭代次數
weights=np.ones((n,1))#權重初始化都為1
for k in range(maxCycles):
h=sigmoid(dataMatrix*weights)#梯度上升矢量化公式
error=(labelMat-h)#相當于公式中的y(i)-h(x(i))
weights=weights+alpha*dataMatrix.transpose()*error#公式里面的累加在這里使用矩陣相乘來實作(矩陣相乘的程序中先乘再加)
return weights.getA() #回傳權重陣列
def plotBestFit(weights):
dataMat, labelMat = loadDataSet() #加載資料集
dataArr = np.array(dataMat) #轉換成numpy的array陣列
n = np.shape(dataMat)[0] #資料個數
xcord1 = []; ycord1 = [] #正樣本
xcord2 = []; ycord2 = [] #負樣本
for i in range(n): #根據資料集標簽進行分類
if int(labelMat[i]) == 1:
xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2]) #1為正樣本
else:
xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2])#0為負樣本
fig = plt.figure()
ax = fig.add_subplot(111) #添加subplot
ax.scatter(xcord1, ycord1, s = 20, c = 'red', marker = 's',alpha=.5)#繪制正樣本
ax.scatter(xcord2, ycord2, s = 20, c = 'green',alpha=.5) #繪制負樣本
x = np.arange(-3.0, 3.0, 0.1)
y = (-weights[0] - weights[1] * x) / weights[2]
ax.plot(x, y)
plt.title('BestFit') #繪制title
plt.xlabel('X1'); plt.ylabel('X2') #繪制label
plt.show()
if __name__ == '__main__':
dataMat, labelMat = loadDataSet()
weights = gradAscent(dataMat, labelMat)
plotBestFit(weights)
#plotDataSet()
正常運行之前報了如下錯誤AttributeError: partially initialized module ‘matplotlib.cbook’ has no attribute ‘deprecated’ (most likely due to a circular import)
然后就是你安裝的matplotlib版本太高了,可以將以前的版本給卸載了,然后安裝一個版本較低的matplotlib,然后就可以解決
測驗結果

總結:代碼運行的大致思路如下:
-
拿到資料之后通過loadDataSet函式將資料的坐標和類別分別存放在兩個陣列中
-
然后通過拿到的坐標陣列和分類陣列,首先先將陣列轉換為矩陣,方便后面矩陣的運算,然后根據sigmoid函式將所有資料轉化為0-1之間的資料,也即公式中的h(xi)的值,然后用每個樣本的類標簽減去梯度上升的矢量值,最后帶入公式算出當前的權重值
-
繪圖
-
然后繪圖的時候定義兩種資料型別的x坐標的陣列和對應的y坐標的陣列,然后通過資料集,將每種類別對應的x坐標和y坐標分開存入對應的陣列中
-
然后繪制一張空的面板,添加坐標系,然后將每個同一類別的點畫在面板上,并且同一類別的點的顏色相同
-
最后畫擬合的直線,橫坐標的范圍已知,然后取sigmoid 函式為0,0是兩個分類(類別1和類別0)的分界處,因此,我們設定 0 = w0x0 + w1x1 + w2x2,然后解出X2和X1的關系式(即分隔線的方程,注意X0=1),
-
最后根據函式方程和x的值將直線畫在面板上即可
-
1.2改進的梯度上升演算法
改進的第一點也就是改變每次向目標點靠近的步長的值,最初的時候也能稍微大點,然后隨著迭代次數的增加,也就是離目標點越來越近,此時每次向前的步長也越來越小;第二點就是樣本的選取也是隨機的;第三點就是原來計算出來的h是一個100乘以1的矩陣,而現在算出來的是一個0-1之間的數值;第四點就是原來計算回歸系數的時候使用一個3*100的矩陣乘以一個100*1的一個矩陣,現在是三個數值的乘積#改進的梯度上升演算法
#迭代次數150是根據上面的代碼測驗出來的
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
m,n = np.shape(dataMatrix) #回傳dataMatrix的大小,m為行數,n為列數,
weights = np.ones(n) #引數初始化
for j in range(numIter):
dataIndex = list(range(m))
for i in range(m):
alpha = 4/(1.0+j+i)+0.01 #降低alpha的大小,每次減小1/(j+i),
randIndex = int(random.uniform(0,len(dataIndex))) #隨機選取樣本
h = sigmoid(sum(dataMatrix[randIndex]*weights)) #選擇隨機選取的一個樣本,計算h
error = classLabels[randIndex] - h #計算誤差
weights = weights + alpha * error * dataMatrix[randIndex] #更新回歸系數
del(dataIndex[randIndex]) #洗掉已經使用的樣本
return weights
1.3回歸系數與迭代次數的關系
#2.為改進之前查看回歸系數與迭代次數的關系
def gradAscent1(dataMatIn, classLabels):
dataMatrix = np.mat(dataMatIn) #轉換成numpy的mat
labelMat = np.mat(classLabels).transpose() #轉換成numpy的mat,并進行轉置
m, n = np.shape(dataMatrix) #回傳dataMatrix的大小,m為行數,n為列數,
alpha = 0.01 #移動步長,也就是學習速率,控制更新的幅度,
maxCycles = 500 #最大迭代次數
weights = np.ones((n,1))
weights_array = np.array([])
for k in range(maxCycles):
h = sigmoid(dataMatrix * weights) #梯度上升矢量化公式
error = labelMat - h
weights = weights + alpha * dataMatrix.transpose() * error
weights_array = np.append(weights_array,weights)
weights_array = weights_array.reshape(maxCycles,n)
return weights.getA(),weights_array #將矩陣轉換為陣列,并回傳
#改進之后的
def stocGradAscent(dataMatrix, classLabels, numIter=150):
m,n = np.shape(dataMatrix) #回傳dataMatrix的大小,m為行數,n為列數,
weights = np.ones(n) #引數初始化
weights_array = np.array([]) #存盤每次更新的回歸系數
for j in range(numIter):
dataIndex = list(range(m))
for i in range(m):
alpha = 4/(1.0+j+i)+0.01 #降低alpha的大小,每次減小1/(j+i),
randIndex = int(random.uniform(0,len(dataIndex))) #隨機選取樣本
h = sigmoid(sum(dataMatrix[randIndex]*weights)) #選擇隨機選取的一個樣本,計算h
error = classLabels[randIndex] - h #計算誤差
weights = weights + alpha * error * dataMatrix[randIndex] #更新回歸系數
weights_array = np.append(weights_array,weights,axis=0) #添加回歸系數到陣列中
del(dataIndex[randIndex]) #洗掉已經使用的樣本
weights_array = weights_array.reshape(numIter*m,n) #改變維度
return weights,weights_array
測驗結果

讓我們分析一下,我們一共有100個樣本點,改進的隨機梯度上升演算法迭代次數為150,而上圖顯示15000次迭代次數的原因是,使用一次樣本就更新一下回歸系數,因此,迭代150次,相當于更新回歸系數150*100=15000次,簡而言之,迭代150次,更新1.5萬次回歸引數,從上圖左側的改進隨機梯度上升演算法回歸效果中可以看出,其實在更新2000次回歸系數的時候,已經收斂了,相當于遍歷整個資料集20次的時候,回歸系數已收斂,訓練已完成,
上圖右側的梯度上升演算法回歸效果,梯度上升演算法每次更新回歸系數都要遍歷整個資料集,從圖中可以看出,當迭代次數為300多次的時候,回歸系數才收斂,湊個整,就當它在遍歷整個資料集300次的時候已經收斂好了,
2.從疝氣病癥狀預測病馬的死亡率
代碼實作def classifyVector(inX, weights):
prob = sigmoid(sum(inX*weights))
if prob > 0.5: return 1.0
else: return 0.0
def colicSklearn():
frTrain = open('horseColicTraining.txt') #打開訓練集
frTest = open('horseColicTest.txt') #打開測驗集
trainingSet = []; trainingLabels = []
testSet = []; testLabels = []
for line in frTrain.readlines():#取出訓練集中的每一行的所有資料
currLine = line.strip().split('\t')#每一行里資料的劃分以空格劃分
lineArr = []
for i in range(len(currLine)-1):#遍歷每一行的每個元素
lineArr.append(float(currLine[i]))#lineArr里存放的就是每一行中所有的資料
trainingSet.append(lineArr)#將每一行的資料存放在訓練集中
trainingLabels.append(float(currLine[-1]))#拿到每一行的最后一列也即資料類別
for line in frTest.readlines():#取出測驗集中每一行的所有資料
currLine = line.strip().split('\t')
lineArr =[]
for i in range(len(currLine)-1):
lineArr.append(float(currLine[i]))
testSet.append(lineArr)
testLabels.append(float(currLine[-1]))
classifier = LogisticRegression(solver='liblinear',max_iter=10).fit(trainingSet, trainingLabels)
test_accurcy = classifier.score(testSet, testLabels) * 100
print('正確率:%f%%' % test_accurcy)
測驗結果

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/513649.html
標籤:Python
上一篇:python學習:map函式和filter函式用法教程
下一篇:pytorch-實作天氣識別
