深度學習 實驗三 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()