本文代码只讨论核心部分,完整代码上传CSDN 资源并在kaggle 公开:
https://www.kaggle.com/laugoon/homework2
https://download.csdn.net/download/lagoon_lala/19032029
目录
任务介绍
二元分类, 通过个人资料, 预测其年收入是否超过5万美元.
需要用到的 数据集有: train.csv, test_no_label.csv, X_train, Y_train, X_test
其中train.csv, test_no_label.csv为原始数据, X_train, Y_train, X_test为助教处理过.
X_train, X_test : 每行一个样本有510维度, 不必全部使用.
Y_train: label = 0含义为”
提交格式:
测试集27622有个样例
第一行: “id, label”
第二行以后: “id, prediction”
CSV(comma seperated values) format
评分依据为正确率
需要手刻 gradient descent 實作 logistic regression, probabilistic generative model. 也就是不能用套件.
需要达成的 分数:
Public simple baseline(1%): 0.88617
Public strong baseline(1%): 0.89052
如果给助教临时跑, 建议固定random seeds, 不然结果可能有差距.
预测思路
“這個資料集是由 UCI Machine Learning Repository 的 Census-Income (KDD) Data Set 經過一些處理而得來。
在訓練過程中,只有X_train 、Y_train 和X_test 這三個經過處理的檔案會被使用到,train.csv 和test.csv 這兩個原始資料檔則可以提供你一些額外的資訊。”
对率回归
数据准备
下載資料,並且對每個屬性做正規化,處理過後再將其切分為訓練集與發展集(development set)。
新建notebook按照自动生成的代码可以获得文件的 路径:
import os
for dirname, _, filenames in os.walk(‘/kaggle/input’):
for filename in filenames:
print(os.path.join(dirname, filename))
/kaggle/input/ml2020spring-hw2/data/X_train
写预测结果输出的时候遇到一点报错:
Read-only file system: ‘/kaggle/input/ml2020spring-hw2/output_logistic.csv’
查看最开始自动生成代码中的注释
ou can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using “Save & Run All”
更改目录.
根据获得的文件路径, 读取csv保存在 numpy数组
with open(X_train_fpath) as f:
next(f)
X_train = np.array([line.strip(‘\n’).split(‘,’)[1:] for line in f], dtype = float)#strip()表示删除掉数据中的换行符,split(’,’)则是数据中遇到’,’ 就隔开
X_train, Y_train:
(array([[33., 1., 0., …, 52., 0., 1.],
…,
[48., 0., 0., …, 0., 0., 1.]]),
array([1., 0., 0., …, 0., 0., 0.]))
对训练集测试集的X做 标准化.
if train:
X_mean = np.mean(X[:, specified_column] ,0).reshape(1, -1)#reshape(1,-1)转换为行数1, 列数根据行数计算
X_std = np.std(X[:, specified_column], 0).reshape(1, -1)
X[:,specified_column] = (X[:, specified_column] – X_mean) / (X_std + 1e-8)#(x-μ)/σ
X_train, X_mean, X_std = _normalize(X_train, train = True)
X_test, , = normalize(X_test, train = False, specified_column = None, X_mean = X_mean, X_std = X_std)#’‘做变量名合法, 作为无用的临时变量
相关知识
shape[0]:表示矩阵的行数; shape[1]:表示矩阵的列数
https://blog.csdn.net/xiasli123/article/details/102932607
reshape:
https://www.jianshu.com/p/d9df005636a6
python下划线作用:
https://blog.csdn.net/tcx1992/article/details/80105645
将数据分割为 训练集, 发展集
train_size = int(len(X) * (1 – dev_ratio))
return X[:train_size], Y[:train_size], X[train_size:], Y[train_size:]
train_size = X_train.shape[0]#训练集行数
print(‘Size of training set: {}’.format(train_size))
Size of training set: 48830
Size of development set: 5426
Size of testing set: 27622
Dimension of data: 510
工具函数
训练过程中可能重复使用
洗牌
randomize = np.arange(len(X))#arange(len(X))返回0,1…len(X)
np.random.shuffle(randomize)#shuffle()方法将序列的所有元素随机排序
return (X[randomize], Y[randomize])
相关知识: arange, shuffle
https://zhuanlan.zhihu.com/p/266619783
计算sigmoid函数作为概率
用的概率分布是高斯分布, 则P可以代入σ, 即sigmoid函数:
$$ P\left( C_{1} \middle| x \right) = \sigma\left( z \right) \ \sigma\left( z \right)= \frac{1}{1 + exp\left( {- z} \right)} $$
np.clip(1 / (1.0 + np.exp(-z)), 1e-8, 1 – (1e-8))#clip将数限定到范围1e-8和1-(1e-8)中
相关知识: clip, sigmoid函数(详细见上篇文章)
https://blog.csdn.net/weixin_44791964/article/details/100000373
对率回归
使用sigmoid函数作为P时, 输入的z为:
$$ z= {w \cdot x + b}=\sum_i w_ix_i+b $$
_sigmoid(np.matmul(X, w) + b)#matmul矩阵相乘
相关知识: matmul
https://blog.csdn.net/alwaysyxl/article/details/83050137
通过把对率回归函数的结果 四舍五入(round),得到每行X真正的预测值.
np.round(_f(X, w, b)).astype(np.int)
计算预测 精确度
acc = 1 – np.mean(np.abs(Y_pred – Y_label))#误差1/nΣ|y-y|
梯度和损失
參考李宏毅逻辑回归PPT, P12梯度及損失函數計算公式。(在notebook写公式和CSDN一样可用Tex, 很方便)
计算交叉熵作为 损失函数
y hat=1, 属于类别1, y hat=0, 属于类别2,
对以下两个分布(假设均为Bernouli两点分布)做交叉熵. Distribution p:
$$ p\left( {x = 1} \right) = {\hat{y}}^{n}\ p\left( {x = 0} \right) = {1 – \hat{y}}^{n} $$
交叉熵可衡量两个分布接近程度:
$$ H\left( {p,q} \right) = – {\sum_{x}{p\left( x \right)ln\left( {q\left( x \right)} \right)}} $$
代入似然函数可表示为:
$$ – lnL\left( {w,b} \right) = {\sum_{n}{- \left\lbrack {{\hat{y}}^{n}lnf_{w,b}\left( x^{n} \right) + \left( {1 – {\hat{y}}^{n}} \right) ln\left( {1 – f_{w,b}\left( x^{n} \right)} \right)} \right\rbrack}} $$
cross_entropy = -np.dot(Y_label, np.log(y_pred)) – np.dot((1 – Y_label), np.log(1 – y_pred))#log默认以e为底
相关知识:log(), 交叉熵(详细查阅上篇文章)
https://blog.csdn.net/weixin_44383134/article/details/87866307
计算梯度
梯度下降的更新公式
$$ w_{i}\leftarrow w_{i} – \eta{\sum_{n}{- \left( {{\hat{y}}^{n} – f_{w,b}\left( x^{n} \right)} \right)x_{i}^{n}}} $$
该公式中间的因子, 为似然函数lnL对wi的偏微分:
$$ \frac{\partial lnL\left( {w,b} \right)}{\partial w_{i}} =-\sum_{n}{ \left( {{\hat{y}}^{n} – f_{w,b}\left( x^{n} \right)} \right)x_{i}^{n}} $$
y_pred = _f(X, w, b)#对率回归
pred_error = Y_label – y_pred#误差
w_grad = -np.sum(pred_error * X.T, 1)#sum参数axis=1是压缩列,即将每一行的元素相加,将矩阵压缩为一列
b_grad = -np.sum(pred_error)
相关知识: sum(), 损失函数最小化(详见上篇)
https://zhuanlan.zhihu.com/p/85790648
训练
我們使用小批次(batch)梯度下降法來訓練。訓練資料被分為許多小批次,針對每一個小批次,我們分別計算其梯度以及損失,並根據該批次來更新模型的參數。當一次迴圈(循环, 迭代)完成,也就是整個訓練集的所有小批次都被使用過一次以後,我們將所有訓練資料打散並且重新分成新的小批次,進行下一個迴圈,直到事先設定的迴圈數量達成為止。
初始化wb
w = np.zeros((data_dim,)) #zeros第一个参数为形状
b = np.zeros((1,))
相关知识: zeros()的第一个参数shape为整数或tuple, 表示矩阵形状
https://blog.csdn.net/weixin_44805104/article/details/102746080
https://blog.csdn.net/u010852680/article/details/77745468
np.zeros((5,))与np.zeros(5)的效果相同, 都是:
array([0., 0., 0., 0., 0.])
当shape为二元组时, 则第一个数为行数, 第二个为列数, 如np.zeros((5,2))得到:
array([[0., 0.],
[0., 0.],
[0., 0.],
[0., 0.],
[0., 0.]])
计算梯度
w_grad, b_grad = _gradient(X, Y, w, b)
利用梯度下降更新参数w b,学习率随时间(step)减少
w = w – learning_rate/np.sqrt(step) * w_grad
计算Y预测值:
y_train_pred = _f(X_train, w, b)
Y_train_pred = np.round(y_train_pred)
计算精确度:
train_acc.append(_accuracy(Y_train_pred, Y_train))
计算损失值:
train_loss.append(_cross_entropy_loss(y_train_pred, Y_train) / train_size)#/ train_size消除训练集与发展集大小不同带来的影响
print(‘Training loss: {}’.format(train_loss[-1]))#[-1]表示数组中最后一位
Training loss: 0.2713554352464059
Development loss: 0.2896359675026287
Training accuracy: 0.8836166291214418
Development accuracy: 0.8733873940287504
作损失, 精度曲线
plt.plot(train_loss)# x可省略,默认[0,1..,N-1]递增
plt.plot(dev_loss)
plt.title(‘Loss’)
plt.legend([‘train’, ‘dev’])#默认参数: 图例的名称
plt.savefig(‘/kaggle/working/loss.png’)
plt.show()
相关知识: savefig
https://www.cnblogs.com/cgmcoding/p/14244735.html
预测测试集
預測測試集的資料標籤並且存在 output_logistic.csv 中。
predictions = _predict(X_test, w, b)
with open(output_fpath.format(‘logistic’), ‘w’) as f:
f.write(‘id,label\n’)
for i, label in enumerate(predictions):#enumerate列出数据和生成数据下标
f.write(‘{},{}\n’.format(i, label))
筛选最大(显著)的几个weight, 即得到 最有用的特征
ind = np.argsort(np.abs(w))[::-1]#argsort从小到大排序, ::-1从后向前读取
with open(X_test_fpath) as f:
content = f.readline().strip(‘\n’).split(‘,’)
features = np.array(content)
for i in ind[0:10]:
print(features[i], w[i])
相关知识:
argsort
https://blog.csdn.net/qq_38486203/article/details/80967696
分片
https://blog.csdn.net/ITOMG/article/details/88683256
输出的结果:
Not in universe -4.031960278019251
Spouse of householder -1.625403958705141
Other Rel
Original: https://blog.csdn.net/lagoon_lala/article/details/117136745
Author: lagoon_lala
Title: 李宏毅ML作业笔记2: 二分类薪资水平
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/635849/
转载文章受原作者版权保护。转载请注明原作者出处!