深度學習 實驗三 logistic迴歸預測二分類

深度學習 實驗三 logistic迴歸預測二分類

一、問題描述

  學會使用學習到的邏輯迴歸的知識,手動使用梯度下降方法,通過給定的相關數據來完成年薪是否高於50k的二分類預測任務。

二、設計簡要描述

相關文件:鏈接:https://pan.baidu.com/s/1FhWygBCq74EPMmbGCYwuYA 提取碼:2lns

1. 數據預處理

1.1 讀取數據

利用pandas自帶的read_csv函數讀取訓練集和測試集數據。

1.2 輸入數據格式化處理

1.2.1 去除字符串數值前面的空格

方便後續字符串類型數據處理需要去掉字符串之前的空格。

1.2.2 對字符數據進行編碼

對數據進行OneHot編碼處理。

2. 數據標準化

將用於訓練的數據進行標準化處理,這裏是主要是將其進行正態分佈化處理。

3. 邏輯迴歸模型實現

定義用於實現邏輯迴歸模型的各個功能的函數。

① _sigmoid:計算輸入的sigmoid;

② get_prob:在給定權重和偏差的情況下,找出模型預測輸出1的概率;

③ infer: 如果概率>爲0.5,則輸出1,否則輸出0;

④ _crossentropy: 計算模型輸出和真實標籤之間的交叉熵;

⑤ _computeLoss : 計算輸入爲X, Y, w的損失函數L(w) ;

⑥ _gradient_regularization : 通過數學推導損失函數;

⑦ train_dev_split: 按照 dev_size 的比例分割數據,用於使用交叉驗證時的情況;

⑧ _shuffle:打亂一列原來的順序;

⑨ accuracy:精確度計算。

4. 劃分訓練集和驗證集

利用數據分割函數將給定的訓練集劃分爲測試集和驗證集。

5. 訓練模型

調整配置模型訓練的學習率、訓練輪數、權重w和偏置b等各個參數信息,手動實現自適應adagrad,利用交叉熵計算損失值,對訓練集進行訓練得到模型。

6. 驗證集測試

利用得到的模型參數對驗證集進行預測驗證,查看準確率和損失值。

7. 測試集測試

對給定的測試集進行模型預測。

8. 保存預測結果到文件

將對預測集預測得到的結果按照要求格式保存到csv文件中。

三、程序清單

# 邏輯迴歸實現二分類任務:確定一個人是否年收入超過5萬美元。
import pandas as pd
import numpy as np
import csv

# 1. 數據預處理
# 1.1 讀取數據
train_data = pd.read_csv('./train.csv')
test_data = pd.read_csv('./test.csv')

# 1.2 輸入數據格式化處理
# 1.2.1 去除字符串數值前面的空格
str_cols = [1,3,5,6,7,8,9,13,14]
for col in str_cols:
    train_data.iloc[:,col] = train_data.iloc[:,col].map(lambda x: x.strip())
    if col != 14:
        test_data.iloc[:,col] = test_data.iloc[:,col].map(lambda x: x.strip())

# 1.2.2 對字符數據進行編碼
from sklearn.preprocessing import MinMaxScaler
min_max_scaler = MinMaxScaler()
data = pd.concat([train_data,test_data],axis=0)
data[['age','fnlwgt' ,'education_num' ,'capital_gain' ,'capital_loss' ,'hours_per_week']]=min_max_scaler.fit_transform(data[['age','fnlwgt' ,'education_num' ,'capital_gain' ,'capital_loss' ,'hours_per_week']])

data.loc[data['workclass']=='?','workclass']='Private'
data.loc[data['occupation']=='?','occupation']='other'

data.loc[data['income']=='<=50K','income']='0'
data.loc[data['income']=='>50K','income']='1'

cols=['workclass', 'education','marital_status', 'occupation', 'relationship', 'race', 'sex', 'native_country']
for col in cols:
    tmp=pd.get_dummies(data[col],prefix=col)
    data=pd.concat([data,tmp],axis=1)
    data=data.drop(col,axis=1)

train_data = data[0:train_data.shape[0]]
test_data = data[train_data.shape[0]:]

train_encoded_data = np.array(train_data.drop(columns='income'))
test_encoded_data = np.array(test_data.drop(columns='income'))

# 2.2.數據標準化
train_mean = np.mean(X_train,axis=0).reshape(1, -1)
train_std = np.std(X_train,axis=0).reshape(1,-1)

# 將指定列規格化爲正態分佈,以使模型更容易地瞭解數據分佈。
X_train = np.divide(np.subtract(X_train,train_mean), train_std)

# 3.邏輯迴歸模型實現
# 計算輸入的sigmoid
def _sigmoid(z):
    result = np.clip(1 / (1.0 + np.exp(-z)), 1e-6, 1-1e-6)
    return result

# get_prob: 在給定權重和偏差的情況下,找出模型預測輸出1的概率
def get_prob(X, w, b):
    y = _sigmoid(X.dot(w)+b)
    return y

# infer: 如果概率>爲0.5,則輸出1,否則輸出0。
def infer(X, w, b):
    y = np.round(get_prob(X, w, b))
    return y

# _crossentropy: 計算模型輸出和真實標籤之間的交叉熵。
def _crossentropy(y_pred, y_label):
#     y_label = int(y_label)
#     loss = np.sum(np.nan_to_num(-y_label*np.log(y_pred)-(1-y_label)*np.log(1-y_pred)))
    Y = np.float_(y_label)
    P = np.float_(y_pred)
    loss = -np.sum(Y * np.log(P) + (1 - Y) * np.log(1 - P))
    return loss

# _computeLoss : 計算輸入爲X, Y, w的損失函數L(w) 
def _computeLoss(y_pred, Y_label, lamda, w):
    loss = 0
    for i in range(len(y_pred)):
        loss += _crossentropy(y_pred[i], Y_label[i]) + lamda * np.sum(np.square(w))
#         loss += (y_pred[i] - int(Y_label[i]))**2
    return loss

# _gradient_regularization : 通過數學推導損失函數
def _gradient_regularization(X, Y, w, b, lamda):
    #print(X.shape[0])
    pred_error = np.ones(X.shape[0])
    for i in range(X.shape[0]):
        pred_error[i] = (Y[i] - w.dot(X[i]) - b) * (-1)
    w_grad = -np.mean(np.multiply(pred_error.T, X.T), 1) + lamda*w
    b_grad = -np.mean(pred_error)
    return w_grad,b_grad

# train_dev_split: 按照 dev_size 的比例分割數據,用於使用交叉驗證時的情況
def train_dev_split(X, y, dev_size=0.2):
    train_len = int(round(len(X)*(1-dev_size)))
    return X[0:train_len], y[0:train_len], X[train_len:None], y[train_len:None]

# _shuffle:打亂一列原來的順序
def _shuffle(X, Y):
    randomsize = np.arange(len(X))
    np.random.shuffle(randomsize)
    return (X[randomsize], Y[randomsize])

# accuracy:精確度計算
def accuracy(Y_pred, Y_label):
    Y_label = list(map(int,Y_label))
    acc = np.sum(Y_pred == Y_label)/len(Y_label)
    return acc

# 4.劃分訓練集和驗證集
X, y = train_encoded_data, np.array(train_data['income'])
X_train,y_train, X_val, y_val = train_dev_split(X, y) 


# 5.訓練過程
max_iter = 30
batch_size = 25
lr = 0.1

# 正則項係數
lamda = 0.001 

w = np.ones(len(X_train[0]))
b = 0

train_acc = []
loss_train = []

step = 1

for epoch in range(max_iter):
    # 打亂每次訓練的數據
    X_train, y_train = _shuffle(X_train, y_train)
    
    w_grad = np.ones(len(X_train[0]))
    b_grad = 0
    
    # 邏輯迴歸按批次訓練
    for idx in range(int(np.floor(len(y_train)/batch_size))):
        X = X_train[idx*batch_size:(idx+1)*batch_size]
        Y = y_train[idx*batch_size:(idx+1)*batch_size]
        Y = list(map(int,Y))
        
        # 計算梯度損失
        w_grad, b_grad = _gradient_regularization(X, Y, w, b, lamda)
        
        # 梯度更新
        w -= lr / np.sqrt(step) * w_grad
        b -= lr / np.sqrt(step) * b_grad
        
        step += 1
    
    # print(w[0], b)    
    # 在每個epoch訓練中記錄下訓練誤差 以及驗證集中的誤差用於畫圖數據
    y_train_pred = get_prob(X_train, w, b)
    Y_train_pred = np.round(y_train_pred)
    loss_train.append(_computeLoss(y_train_pred, y_train, lamda, w)/len(X_train))
    train_acc.append(accuracy(Y_train_pred, y_train))
    
#     if epoch%5 == 0:
    print('epoch {}, the loss is : {}, the acc is : {}'.format(epoch+1, loss_train[epoch], train_acc[epoch]))

# 6.驗證集測試結果
y_val_pred = get_prob(X_val, w, b)
Y_val_pred = np.round(y_train_pred)
loss_val = _computeLoss(y_val_pred, y_val, lamda, w)/len(X_val)
val_acc = accuracy(Y_val_pred, y_val)
print('validation data, the loss is : {}, the acc is : {}'.format(loss_val, val_acc))

# 7.測試集測試
Y_test_pred = infer(test_encoded_data, w, b)
Y_test_pred = list(map(int,Y_test_pred))

# 8.保存預測結果到文件
predict_result_file = open('./predict_result.csv','w',newline='')
writer = csv.writer(predict_result_file)
writer.writerow(('id','label'))
for i in range(len(Y_test_pred)):
    writer.writerow([i+1, Y_test_pred[i]])
predict_result_file.close()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章