Logistic迴歸預測收入----臺大李宏毅機器學習做業2(HW2)

1、做業說明

  給定訓練集spam_train.csv,要求根據每一個ID各類屬性值來判斷該ID對應角色是Winner仍是Losser(收入是否大於50K),這是一個典型的二分類問題。html

訓練集介紹:算法

  (1)、CSV文件,大小爲4000行X59列;機器學習

  (2)、4000行數據對應着4000個角色,ID編號從1到4001;ide

  (3)、59列數據中, 第一列爲角色ID,最後一列爲分類結果,即label(0、1兩種),中間的57列爲角色對應的57種屬性值;函數

  (4)、數據集地址:https://pan.baidu.com/s/1mG7ndtlT4jWYHH9V-Rj_5g, 提取碼:hwzf 。學習

2、思路分析及實現

2.1 思路分析

  這是一個典型的二分類問題,結合課上所學內容,決定採用Logistic迴歸算法。優化

  與線性迴歸用於預測不一樣,Logistic迴歸則經常使用於分類(一般是二分類問題)。Logistic迴歸實質上就是在普通的線性迴歸後面加上了一個sigmoid函數,把線性迴歸預測到的數值壓縮成爲一個機率,進而實現二分類(關於線性迴歸模型,可參考上一次做業)。編碼

  在損失函數方面,Logistic迴歸並無使用傳統的歐式距離來度量偏差,而使用了交叉熵(用於衡量兩個機率分佈之間的類似程度)。spa

   

2.2 數據預處理

  在機器學習中,數據的預處理是很是重要的一環,能直接影響到模型效果的好壞。本次做業的數據相對簡單純淨,在數據預處理方面並不須要花太多精力。3d

  首先是空值處理(儘管沒看到空值,但爲了以防萬一,仍是作一下),全部空值用0填充(也能夠用平均值、中位數等,視具體狀況而定)。

  接着就是把數據範圍儘可能scale到同一個數量級上,觀察數據後發現,多數數據值爲0,非0值也都在1附近,只有倒數第二列和倒數第三列數據值較大,能夠將這兩列分別除上每列的平均值,把數值範圍拉到1附近。

  因爲並無給出這57個屬性具體是什麼屬性,所以沒法對數據進行進一步的挖掘應用。

  上述操做完成後,將表格的第2列至58列取出爲x(shape爲4000X57),將最後一列取出作label y(shape爲4000X1)。進一步劃分訓練集和驗證集,分別取x、y中前3500個樣本爲訓練集x_test(shape爲3500X57),y_test(shape爲3500X1),後500個樣本爲驗證集x_val(shape爲500X57),y_val(shape爲500X1)。

  數據預處理到此結束。

 1 # 從csv中讀取有用的信息
 2 df = pd.read_csv('spam_train.csv')
 3 # 空值填0
 4 df = df.fillna(0)
 5 # (4000, 59)
 6 array = np.array(df)
 7 # (4000, 57)
 8 x = array[:, 1:-1]
 9 # scale
10 x[-1] /= np.mean(x[-1])
11 x[-2] /= np.mean(x[-2])
12 # (4000, )
13 y = array[:, -1]
14 
15 # 劃分訓練集與驗證集
16 x_train, x_val = x[0:3500, :], x[3500:4000, :]
17 y_train, y_val = y[0:3500], y[3500:4000]

2.3 模型創建

2.3.1 線性迴歸

  先對數據作線性迴歸,得出每一個樣本對應的迴歸值。下式爲對第n個樣本的迴歸,迴歸結果爲

1 y_pre = weights.dot(x_val[j, :]) + bias

2.3.2 sigmoid函數壓縮回歸值

  以後將回歸結果送進sigmoid函數,獲得機率值。

1 sig = 1 / (1 + np.exp(-y_pre)  

2.3.3 偏差反向傳播

  接着就到重頭戲了。衆所周知,無論線性迴歸仍是Logistic迴歸,其關鍵和核心就在於經過偏差的反向傳播來更新參數,進而使模型不斷優化。所以,損失函數的肯定及對各參數的求導就成了重中之重。在分類問題中,模型通常針對各種別輸出一個機率分佈,所以經常使用交叉熵做爲損失函數。交叉熵可用於衡量兩個機率分佈之間的類似、統一程度,兩個機率分佈越類似、越統一,則交叉熵越小;反之,兩機率分佈之間差別越大、越混亂,則交叉熵越大。

  下式表示k分類問題的交叉熵,P爲label,是一個機率分佈,經常使用one_hot編碼。例如針對3分類問題而言,若樣本屬於第一類,則P爲(1,0,0),若屬於第二類,則P爲(0,1,0),若屬於第三類,則爲(0,0,1)。即所屬的類機率值爲1,其餘類機率值爲0。Q爲模型得出的機率分佈,能夠是(0.1,0.8,0.1)等。

  在實際應用中,爲求導方便,常使用以e爲底的對數。

  針對本次做業而言,雖然模型只輸出了一個機率值p,但因爲處理的是二分類問題,所以能夠很快求出另外一機率值爲1-p,便可視爲模型輸出的機率分佈爲Q(p,1-p)。將本次的label視爲機率分佈P(y,1-y),即Winner(label爲1)的機率分佈爲(1,0),分類爲Losser(label爲0)的機率分佈爲(0,1)。

  損失函數對權重w求偏導,可得:

  由於:

  因此有:

 

   同理,損失函數對偏置b求偏導,可得:

 1 # 在全部數據上計算梯度,梯度計算時針對損失函數求導,num爲樣本數量
 2 for j in range(num):
 3     # 線性函數
 4     y_pre = weights.dot(x_train[j, :]) + bias
 5     # sigmoid函數壓縮回歸值,求得機率
 6     sig = 1 / (1 + np.exp(-y_pre))
 7     # 對偏置b求梯度
 8     b_g += (-1) * (y_train[j] - sig)
 9     # 對權重w求梯度,2 * reg_rate * weights[k] 爲正則項,防止過擬合
10     for k in range(dim):
11         w_g[k] += (-1) * (y_train[j] - sig) * x_train[j, k] + 2 * reg_rate * weights[k] 

2.3.4 參數更新

  求出梯度後,再拿原參數減去梯度與學習率的乘積,便可實現參數的更新。

 1 # num爲樣本數量
 2 b_g /= num
 3 w_g /= num
 4 
 5 # adagrad
 6 bg2_sum += b_g**2
 7 wg2_sum += w_g**2
 8 
 9 # 更新權重和偏置
10 bias -= learning_rate/bg2_sum**0.5 * b_g
11 weights -= learning_rate/wg2_sum**0.5 * w_g

3、代碼分享與結果展現

3.1 源代碼

  1 import pandas as pd
  2 import numpy as np
  3 
  4 
  5 # 更新參數,訓練模型
  6 def train(x_train, y_train, epoch):
  7     num = x_train.shape[0]
  8     dim = x_train.shape[1]
  9     bias = 0  # 偏置值初始化
 10     weights = np.ones(dim)  # 權重初始化
 11     learning_rate = 1  # 初始學習率
 12     reg_rate = 0.001  # 正則項係數
 13     bg2_sum = 0  # 用於存放偏置值的梯度平方和
 14     wg2_sum = np.zeros(dim)  # 用於存放權重的梯度平方和
 15 
 16     for i in range(epoch):
 17         b_g = 0
 18         w_g = np.zeros(dim)
 19         # 在全部數據上計算梯度,梯度計算時針對損失函數求導
 20         for j in range(num):
 21             y_pre = weights.dot(x_train[j, :]) + bias
 22             sig = 1 / (1 + np.exp(-y_pre))
 23             b_g += (-1) * (y_train[j] - sig)
 24             for k in range(dim):
 25                 w_g[k] += (-1) * (y_train[j] - sig) * x_train[j, k] + 2 * reg_rate * weights[k]
 26         b_g /= num
 27         w_g /= num
 28 
 29         # adagrad
 30         bg2_sum += b_g ** 2
 31         wg2_sum += w_g ** 2
 32         # 更新權重和偏置
 33         bias -= learning_rate / bg2_sum ** 0.5 * b_g
 34         weights -= learning_rate / wg2_sum ** 0.5 * w_g
 35 
 36         # 每訓練100輪,輸出一次在訓練集上的正確率
 37         # 在計算loss時,因爲涉及到log()運算,所以可能出現無窮大,計算並打印出來的loss爲nan
 38         # 有興趣的同窗能夠把下面涉及到loss運算的註釋去掉,觀察一波打印出的loss
 39         if i % 3 == 0:
 40             # loss = 0
 41             acc = 0
 42             result = np.zeros(num)
 43             for j in range(num):
 44                 y_pre = weights.dot(x_train[j, :]) + bias
 45                 sig = 1 / (1 + np.exp(-y_pre))
 46                 if sig >= 0.5:
 47                     result[j] = 1
 48                 else:
 49                     result[j] = 0
 50 
 51                 if result[j] == y_train[j]:
 52                     acc += 1.0
 53                 # loss += (-1) * (y_train[j] * np.log(sig) + (1 - y_train[j]) * np.log(1 - sig))
 54             # print('after {} epochs, the loss on train data is:'.format(i), loss / num)
 55             print('after {} epochs, the acc on train data is:'.format(i), acc / num)
 56 
 57     return weights, bias
 58 
 59 
 60 # 驗證模型效果
 61 def validate(x_val, y_val, weights, bias):
 62     num = 500
 63     # loss = 0
 64     acc = 0
 65     result = np.zeros(num)
 66     for j in range(num):
 67         y_pre = weights.dot(x_val[j, :]) + bias
 68         sig = 1 / (1 + np.exp(-y_pre))
 69         if sig >= 0.5:
 70             result[j] = 1
 71         else:
 72             result[j] = 0
 73 
 74         if result[j] == y_val[j]:
 75             acc += 1.0
 76         # loss += (-1) * (y_val[j] * np.log(sig) + (1 - y_val[j]) * np.log(1 - sig))
 77     return acc / num
 78 
 79 
 80 def main():
 81     # 從csv中讀取有用的信息
 82     df = pd.read_csv('spam_train.csv')
 83     # 空值填0
 84     df = df.fillna(0)
 85     # (4000, 59)
 86     array = np.array(df)
 87     # (4000, 57)
 88     x = array[:, 1:-1]
 89     # scale
 90     x[:, -1] /= np.mean(x[:, -1])
 91     x[:, -2] /= np.mean(x[:, -2])
 92     # (4000, )
 93     y = array[:, -1]
 94 
 95     # 劃分訓練集與驗證集
 96     x_train, x_val = x[0:3500, :], x[3500:4000, :]
 97     y_train, y_val = y[0:3500], y[3500:4000]
 98 
 99     epoch = 30  # 訓練輪數
100     # 開始訓練
101     w, b = train(x_train, y_train, epoch)
102     # 在驗證集上看效果
103     acc = validate(x_val, y_val, w, b)
104     print('The acc on val data is:', acc)
105 
106 
107 if __name__ == '__main__':
108     main()
View Code

3.2 結果展現

      

  能夠看出,在訓練30輪後,分類正確率能達到94%左右。

 

參考資料:

  李宏毅老師機器學習課程視頻:https://www.bilibili.com/video/av10590361

  李宏毅老師機器學習課程講義資料:http://speech.ee.ntu.edu.tw/~tlkagk/courses_ML17_2.html

相關文章
相關標籤/搜索