实验二:线性回归与逻辑斯蒂分类实验
- 实验目的和要求
- 掌握线性回归的基本原理。
- 掌握逻辑斯蒂分类的基本原理。
- 学会使用Python语言实现线性回归算法。
- 学会使用Python语言实现逻辑斯蒂分类。
- 实验原理及内容
- 使用线性回归对房屋价格(数据集:题目1数据.txt)进行预测,需要使用前350行作为训练,351-414行作为测试数据,并对测试数据输出评价指标R方和残差平方和。
- 先用sklearn实现线性回归;
- 再用最小二乘或梯度下降法实现(参考书上代码)。
- 选用随机种子42:np.random.seed(42)
提示:先把数据复制到文本文件,保存为data.txt,在用np.loadtxt()函数进行读取,示例代码如下
import numpy as np a = np.loadtxt("data.txt")
注意data1.xlsx中数据的最后一列是y值,其它列是属性。
数据的话是形如以下内容的格式,如需要下载,就用百度云的此链接下载1QKjs0kBSa9e_DUbivwwaLQ 提取码:jpl4
32 84.87882 10 24.98298 121.54024 37.9
19.5 306.5947 9 24.98034 121.53951 42.2
13.3 561.9845 5 24.98746 121.54391 47.3
13.3 561.9845 5 24.98746 121.54391 54.8
5 390.5684 5 24.97937 121.54245 43.1
7.1 2175.03 3 24.96305 121.51254 32.1
34.5 623.4731 7 24.97933 121.53642 40.3
20.3 287.6025 6 24.98042 121.54228 46.7
31.7 5512.038 1 24.95095 121.48458 18.8
可以看到给出的数据都是用制表符tab键隔开,且数据给的很规矩,用loadtxt不会报错,所以照着书抄一遍代码即可完成。
第一题是非常简单的线性回归,首先将数据读入,并把训练数据和测试数据划分好,可以看到一共414行数据
data = np.loadtxt("E:/progress/B21030826/python/data.txt")
print(data.shape)
# 划分训练集和测试集
x_train = data[:350, :-1] # 0~349,取除了最后一位
y_train = data[:350, -1] # 0~349,取最后一位
x_test = data[350:415, :-1] # 350~414
y_test = data[350:415, -1] # 取最后一位
然后训练模型
# 使用sklearn实现线性回归
model = LinearRegression()
model.fit(x_train, y_train)
最终计算残差平方和和r方完成题目要求
# 计算残差 因为._residues版因版本问题可能无法访问
# 所以先根据模型进行预测
y_pred = model.predict(x_train)
residuals = y_train - y_pred
# 再计算R方和残差平方和
r2 = model.score(x_test, y_test)
rss = np.sum(np.square(residuals))
print("使用sklearn实现线性回归:")
print("R方是:{:.4f}".format(r2))
print("残差平方和是:{:.4f}".format(rss))
接下来使用最小二乘法完成,本质一样不多赘述,直接给出第一题的全部完整代码。
import numpy as np
from sklearn.linear_model import LinearRegression
# 读取数据
data = np.loadtxt("E:/progress/B21030826/python/data.txt")
print(data.shape)
# 划分训练集和测试集
x_train = data[:350, :-1] # 0~349,取除了最后一位
y_train = data[:350, -1] # 0~349,取最后一位
x_test = data[350:415, :-1] # 350~414
y_test = data[350:415, -1] # 取最后一位
print(x_train.shape)
print(x_test.shape)
# 使用sklearn实现线性回归
model = LinearRegression()
model.fit(x_train, y_train)
# 计算残差 因为._residues版因版本问题可能无法访问
# 所以先根据模型进行预测
y_pred = model.predict(x_train)
residuals = y_train - y_pred
# 再计算R方和残差平方和
r2 = model.score(x_test, y_test)
rss = np.sum(np.square(residuals))
print("使用sklearn实现线性回归:")
print("R方是:{:.4f}".format(r2))
print("残差平方和是:{:.4f}".format(rss))
def linreg_martix(x, y):
X_X_T = np.matmul(x, x.T)
X_X_T_1 = np.linalg.inv(X_X_T)
X_X_T_1_X = np.matmul(X_X_T_1, x)
x = np.matmul(X_X_T_1_X, y.T)
return x
# 使用最小二乘法实现线性回归
# 对x进行扩展,加入全1的行
def make_ext(x):
ones = np.ones(1)[:, np.newaxis]
new_x = np.insert(x, 0, ones, axis=0)
return new_x
# 添加偏置项1
x = make_ext(x_train.T)
y = y_train.T
w = linreg_martix(x, y)
print("w =", w)
y_train_predict = w.dot(x)
y_test_predict = w.dot(make_ext(x_test.T))
ssRTrain = sum((y_train - y_train_predict) ** 2)
ssRTest = sum((y_test - y_test_predict) ** 2)
SST = sum((y_test - np.mean(y_test)) ** 2)
rs = 1 - ssRTest / SST
print("使用最小二乘法法实现线性回归:")
print("R方是:{:.4f}".format(rs))
print("残差平方和是:{:.4f}".format(ssRTrain))
运行一下,结果如下:
应该没什么大错
2、编写代码,使用Logistic Regression对训练数据(题目2训练数据.txt)进行模型训练,并针对测试数据(题目2测试数据.txt)输出二分类结果,结果用0-1之间的概率表示,用空格进行分割,分别计算在训练集和验证集(训练数据后20%)的AUC值。
- 数据集说明
该数据集需要通过特征数据分析,来预测二分类的结果。训练数据集中的二分类结果已经给出,为最后一列。 - 数据集信息
本数据集用于估计信用卡的违约概率。其中训练数据包括27997个样本,测试数据包括2001个样本。需要根据训练数据,建立Logistic Regression模型,对测试数据集中的数据预测结果。
结果文件为一个result.txt文件,其中包含2000个0-1之间的实数值,保留两位小数,用逗号分割,例如:
0.1, 0.2, 0.05, 1。 - 数据属性
本数据集供包括23个特征,具体说明如下:
- 第1列: 信用卡的额度
- 第2列: 性别 (1 = male; 2 = female).
- 第3列: 教育 (1 = graduate school; 2 = university; 3 = high school; 4 = others).
- 第4列: 婚姻状态 (1 = married; 2 = single; 3 = others).
- 第5列: 年龄.
- 第6 - 11列: 过去几个月的还款状态(4月到9月),-1,-2代表按时还款,其他代表延迟还款的月份数
- 第12 - 17列: 过去几个月的账单记录
- 第 18 – 23 列: 过去几个月的支付记录
- 最后一列为类别y值,取值为0或1
要求:
(1)使用Sklearn实现
(2)自定义编码使用梯度下降法实现(选做)
数据例子如下,同样百度云链接 链接:170khaDoX5jwchBOhYxsUKw 提取码:d46q
20000 2 2 1 24 2 2 -1 -1 -2 -2 3913 3102 689 0 0 0 0 689 0 0 0 0 1
120000 2 2 2 26 -1 2 0 0 0 2 2682 1725 2682 3272 3455 3261 0 1000 1000 1000 0 2000 1
90000 2 2 2 34 0 0 0 0 0 0 29239 14027 13559 14331 14948 15549 1518 1500 1000 1000 1000 5000 0
50000 2 2 1 37 0 0 0 0 0 0 46990 48233 49291 28314 28959 29547 2000 2019 1200 1100 1069 1000 0
50000 1 2 1 57 -1 0 -1 0 0 0 8617 5670 35835 20940 19146 19131 2000 36681 10000 9000 689 679 0
50000 1 1 2 37 0 0 0 0 0 0 64400 57069 57608 19394 19619 20024 2500 1815 657 1000 1000 800 0
第二题看起来很长啊,但还是非常简单的,照着书上写一遍便是了,首先根据题目要求划分训练集和验证集,可以看到数据还是很标准的制表符隔开,读取也没难度,直接给出代码。
# 读取数据
train_data = np.loadtxt('E:/progress/B21030826/python/题目2训练数据.txt')
test_data = np.loadtxt('E:/progress/B21030826/python/题目2测试数据.txt')
print(train_data.shape)
print(test_data.shape)
# 取出特征和标签
X_train = train_data[:, :-1]
y_train = train_data[:, -1]
X_test = test_data
# 划分训练集和验证集
X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.2)
训练模型
# 训练模型
model = LogisticRegression()
model.fit(X_train, y_train)
计算auc值并输出
# 在训练集和验证集上计算AUC
train_auc = roc_auc_score(y_train, model.predict_proba(X_train)[:, 1])
val_auc = roc_auc_score(y_val, model.predict_proba(X_val)[:, 1])
print('Train AUC:', train_auc)
print('Val AUC:', val_auc)
然后是预测并输出
# 在测试集上进行预测
y_pred = model.predict_proba(X_test)[:, 1]
# 输出结果
with open('E:/progress/B21030826/python/result.txt', 'w') as f:
f.write(','.join([f'{i:.2f}' for i in y_pred]))
运行一下结果输出:
概率输出没问题!万事大吉…………吗?
编程完后发现到处是坑,这里小插一句,此时你可以使用
y_pred=model.predict(X_test)
来获取模型在测试集上的预测结果。这种方法用于在测试集上进行分类预测,返回每个样本的预测标签。对于二分类问题,返回的结果是一个包含预测标签的一维数组。
与
model.predict_proba(X_test)[:, 1]
不同的是,model.predict(X_test)
直接返回预测的类别而不是概率值。该方法基于分类阈值来判断样本属于哪个类别,通常是根据0.5阈值进行判断。该代码具体为什么这么写自己搜。但仔细观察数据可以发现他们都小于0.5,这是什么情况?!
我认为这是因为给出的数据中存在类别特征,就是形如1,2,3这种他需要进行独热编码处理,而其他过大的数也需要进行归一化,还有欠钱的月份如-1,-2,也可以直接合并成0再进行处理,但此时并没有学到独热编码的概念,这是第七章的内容,所以就先给出只进行归一化处理的代码
ok,既然问题找到接下来就让我进行一下数据处理吧 ,首先:
-
对于连续型特征:
- 第一列,第五列和第12到23列进行归一化处理。
-
对于离散型特征:
- 将-1和-2替换为0,表示按时还款。对于其他延迟还款的月份数,保留原始值。
- 使用独热编码将第二列到第四列和第六到第十一列的数据全部处理
- 同时因为第2到第4列分别属于不同的类型特征,而第6到11列才是另一种类型特征,理论上来说要分别进行独热编码不能混淆
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler, OneHotEncoder
# 读取数据
train_data = np.loadtxt('E:/progress/B21030826/python/题目2训练数据.txt')
test_data = np.loadtxt('E:/progress/B21030826/python/题目2测试数据.txt')
print(train_data.shape)
print(test_data.shape)
# 数据处理
# 对连续型特征进行归一化处理(1,5,12-23)
continuous_features = [0, 4, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
scaler = MinMaxScaler()
train_data[:, continuous_features] = scaler.fit_transform(train_data[:, continuous_features])
test_data[:, continuous_features] = scaler.fit_transform(test_data[:, continuous_features])
# 替换-1和-2为0,表示按时还款
train_data[:, 7:23][train_data[:, 7:23] < 0] = 0
test_data[:, 7:23][test_data[:, 7:23] < 0] = 0
print(train_data.shape)
print(test_data.shape)
# 对离散型特征进行独热编码处理(2,3,4,6-11)
# 取出特征和标签
X_train = train_data[:, :-1]
y_train = train_data[:, -1]
X_test = test_data
# 划分训练集和验证集
X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.2)
# 训练模型
model = LogisticRegression()
model.fit(X_train, y_train)
# 在训练集和验证集上计算AUC
train_auc = roc_auc_score(y_train, model.predict_proba(X_train)[:, 1])
val_auc = roc_auc_score(y_val, model.predict_proba(X_val)[:, 1])
print('Train AUC:', train_auc)
print('Val AUC:', val_auc)
# 在测试集上进行预测
y_pred = model.predict_proba(X_test)[:, 1]
# 输出结果
with open('E:/progress/B21030826/python/result.txt', 'w') as f:
f.write(','.join([f'{i:.2f}' for i in y_pred]))
输出结果:
肉眼可见的出现了0.5以上的数据,那么就先到这里吧。
因为是4种类型特征,理论上是要分别进行四次独热编码的,同时因为编码后维度不同会出现一些问题,老是报错,所以就给出个伪代码吧,如果有兴趣的话自己试着改一改,编一编,想看人要是多的话我再改好发出来。
# 不同的类型特征要分别进行处理,不能混淆。
discrete_features = [1, 2, 3, 5, 6, 7, 8, 9, 10]
encoder = OneHotEncoder(sparse=False)
encoded_data = encoder.fit_transform(train_data[:, discrete_features])
train_data[:, discrete_features] = encoded_data
第二问选做一样是抄书上后简单的数据处理就可以了,都是选做了,你不会还要看代码是啥吧,懒得敲可以扫一下书上的二维码下载书上的代码,好了,剩下的就自己做吧 ,帮到你的话还不速速说声谢谢学长!