sklearn之线性回归实现—阿里云天池二手车交易价格预测赛

最近整理了线性回归的原理代码实现,想要用实际数据来测试模型,正好看到阿里云天池数据赛正在进行二手车交易价格预测算法赛,正好能用线性回归模型进行预测,就在这里分享一下代码。

一、赛题介绍

赛题以预测二手车的交易价格为任务,该数据来自某交易平台的二手车交易记录,总数据量超过40w,包含31列变量信息,其中15列为匿名变量。其中抽取15万条作为训练集,5万条作为测试集A,5万条作为测试集B。

特征如下:
在这里插入图片描述
二、数据预处理

数据预处理是跑模型之前最重要的一步,做好预处理,模型也就成功了一半。

import pandas as pd 
import numpy as np 
data=pd.read_csv('./train.csv',encoding='big5') #读取训练集
data=data.iloc[:,2:] #只取有用字段

为了方便读取数据,我将原始数据中price(价格)字段移到最后一列。

x_data=data.iloc[:,:28] #取特征字段
y_data=data.iloc[:,28] #取目标值price字段
x=np.array(x_data.values.tolist()) #将数据展开成二维数据
y=np.array(y_data.values.tolist()) #将数据展开成二维数据

在进行预处理之前,先做特征分析,看看各个特征的分布。
查看数据的特征字段名称:

data.columns #查看数据的特征字段名称

在这里插入图片描述
查看该特征数据分布:

from scipy import stats
vatt='kilometer'
stats.mode(data[vatt]) #查看该特征众数
data[vatt].describe() #查看该特征数据分布

在这里插入图片描述
作特征数据分布图:

import seaborn as sns
sns.distplot(data[vatt]) #该特征分布图

在这里插入图片描述
与Y值做散点图:

import matplotlib.pyplot as plt
var = 'price'
data_x = pd.concat([data[var],data[vatt]], axis=1)
data_x.plot.scatter(x=vatt, y=var, ylim=(0,800)) #与Y值做散点图

在这里插入图片描述
对所有特征数据做归一化,保持特征量纲统一。

mean_x = np.mean(x, axis = 0) 
std_x = np.std(x, axis = 0) 
for i in range(len(x)):
    for j in range(len(x[0])): 
        if std_x[j] != 0:
            x[i][j] = (x[i][j] - mean_x[j]) / std_x[j]

将训练集按8:2比例分为组内训练集与测试集,测试模型训练效果。

import math
x_train_set = x[: math.floor(len(x) * 0.9), :]
y_train_set = y[: math.floor(len(y) * 0.9)]
x_validation = x[math.floor(len(x) * 0.9): , :]
y_validation = y[math.floor(len(y) * 0.9):]

三、线性回归模型代码实现

我尝试直接利用手写线性回归算法代码实现模型训练。

dim = 28+1 #之所以+1是留出误差项b的位置
w = np.ones([dim, 1]) #w就是待学习参数
x_1 = np.concatenate((np.ones([len(x_train_set), 1]), x_train_set), axis = 1).astype(float)
learning_rate = 100 #初始化学习率设置为100
iter_time = 1000 #训练次数为1000次
adagrad = np.zeros([dim, 1]) #adagrad自适应学习率方法
eps = 0.0000000001 #adagrad中防止分母为0的极小值
for t in range(iter_time):
    loss = np.sqrt(np.sum(np.power(np.dot(x_1, w) - y,2)) / len(x_train_set)) #损失函数
    if(t%100==0): #每隔100次输出一次误差值
        print(str(t) + ":" + str(loss))
    gradient = 2 * np.dot(x_1.transpose(), np.dot(x_1, w) - y) ##计算的梯度
    adagrad=adagrad+gradient ** 2 
    w = w - learning_rate * gradient / np.sqrt(adagrad + eps) #更新w的值

结果遇到报错"MemoryError: Unable to allocate 151. GiB for an array with shape (135000, 150000) and data type float64" ,意思就是待训练矩阵过大导致内存不足无法计算。
在尝试尽量缩小训练数据量后,发现计算机最多只能计算数千条数据,我转而求助sklearn包来实现线性回归。

四、sklearn代码实现

sklearn是目前python中十分流行的用来实现机器学习的第三方包,其中包含了多种常见算法如:决策树,逻辑回归、集成算法(如随机森林)等等。

用sklearn实现多元线性回归:

参数 fit_intercept,选择是否需要计算截距,默认为True;
参数 normalize,选择是否需要标准化(中心化),默认为false;

from sklearn import linear_model
reg=linear_model.LinearRegression(fit_intercept=True,normalize=True)
model=reg.fit(x_train_set,y_train_set) #建模
k=reg.coef_ #模型参数w
b=reg.intercept_ #模型截距b
k

模型训练出的参数
预测组内测试集,查看均方误差大小。

y_pred=reg.predict(x_validation)
metrics.mean_squared_error(y_validation, y_pred)

作图查看预测效果,数据集数据量太大,只取前100个预测结果查看拟合效果:

y_pred_p=y_pred[:100] #取预测结果
y_train_set_p=y_validation[:100] #取组内测试集结果
plt.figure(dpi=100)
plt.plot(range(len(y_pred_p)),y_pred_p,'b',label="predict")
plt.plot(range(len(y_train_set_p)),y_train_set_p,'r',label="test")

可以看到预测结果大体上还是和测试集相符的:
在这里插入图片描述
五、比赛得分

将训练的模型用于待预测数据集,输出结果提交到比赛中。

testdata = pd.read_csv('./test.csv', encoding='big5')
test_data = testdata.iloc[:, 2:] 
test_x = np.array(test_data.values.tolist())  # 将其转换为数组
# 下面是Normalize,且必须跟training data是同一种方法进行Normalize
for i in range(len(test_x)): #12 * 471
    for j in range(len(test_x[0])): #18 * 9 
        if std_x[j] != 0:
            test_x[i][j] = (test_x[i][j] - mean_x[j]) / std_x[j]

预测结果:

y_pred_test=reg.predict(test_x)

将结果输出到csv文件中:

import csv
with open('./result.csv', mode='w', newline='') as submit_file:
    csv_writer = csv.writer(submit_file)
    header = ['SaleID', 'price']
    print(header)
    csv_writer.writerow(header)
    for i in range(50000):
        if y_pred_test[i]<0 :
            y_pred_test[i]=0 #如果预测结果小于0,就为0,因为价格不可能小于0
        row = [str(i+150000), y_pred_test[i]]
        csv_writer.writerow(row)
        print(row)

以下为提交结果后获得的误差分数与排名,可以看到和其他人提交的结果还是有很大差距的。
在这里插入图片描述
六、模型优化

面对不佳的预测效果,我回头检查数据发现了一些数据缺失和数据移位的问题,进行数据补齐后重新训练模型,但预测分数没有得到显著提升。

于是我思考基于sklearn优化现有线性回归模型。

(1) 岭回归

岭回归在损失函数中增加了正则项,也叫L2范数,以限制模型参数对异常样本的匹配程度,进而提高模型面对多数正常样本的拟合精度。

from sklearn.linear_model import Ridge,RidgeCV
Lambdas=np.logspace(-0.5,1,5) #构造不同的lambda值

#设置交叉验证的参数,使用均方误差评估
ridge_cv=RidgeCV(alphas=Lambdas,normalize=True,scoring='neg_mean_squared_error',cv=10)
ridge_cv.fit(x_train_set,y_train_set)

#基于最佳lambda值建模
ridge=Ridge(alpha=ridge_cv.alpha_,normalize=True)
ridge.fit(x_train_set,y_train_set)

#输出预测结果
ridge_pred=ridge.predict(x_validation)

#评估模型效果
MSE=metrics.mean_squared_error(y_validation,ridge_pred)
print(MSE)

提交比赛结果后,模型预测表现没有得到显著提升。在这里插入图片描述
(2)LASSO回归

岭回归无法剔除变量,而LASSO回归模型,将惩罚项由L2范数变为L1范数,可以将一些不重要的回归系数缩减为0,达到剔除变量的目的。

from sklearn.linear_model import Lasso,LassoCV
Lambdas=np.logspace(-0.5,1,2)

#设置交叉验证的参数,使用均方误差评估
lasso_cv=LassoCV(alphas=Lambdas,normalize=True,cv=10,max_iter=10000)
lasso_cv.fit(x_train_set,y_train_set)

#基于最佳lambda值建模
lasso=Lasso(alpha=lasso_cv.alpha_,normalize=True,max_iter=10000)
lasso.fit(x_train_set,y_train_set)

#输出预测结果
lasso_pred=lasso.predict(x_validation)

#评估模型效果
MSE=metrics.mean_squared_error(y_validation,lasso_pred)
print(MSE)

提交比赛结果后,模型预测表现没有得到显著提升。
在这里插入图片描述
至此,线性回归模型在二手车交易价格预测赛中的代码如上。

小记:
1、线性回归在sklearn上实现即方便又快速。
2、我看到二手车交易价格预测赛论坛中,排名靠前的模型都是神经网络实现的,下一步我将用神经网络框架实现价格预测模型,对比现有模型效果。

  • 4
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值