Logistic回歸預測收入----台大李宏毅機器學習作業2(HW2)


一、作業說明

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

訓練集介紹:

  (1)、CSV文件,大小為4000行X59列;

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

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

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

二、思路分析及實現

2.1 思路分析

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

  與線性回歸用於預測不同,Logistic回歸則常用於分類(通常是二分類問題)。Logistic回歸實質上就是在普通的線性回歸后面加上了一個sigmoid函數,把線性回歸預測到的數值壓縮成為一個概率,進而實現二分類(關於線性回歸模型,可參考上一次作業)。

  在損失函數方面,Logistic回歸並沒有使用傳統的歐式距離來度量誤差,而使用了交叉熵(用於衡量兩個概率分布之間的相似程度)。

   

2.2 數據預處理

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

  首先是空值處理(盡管沒看到空值,但為了以防萬一,還是做一下),所有空值用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.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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM