模型优化:共享单车时租预测
在先前的模型预测过程中,我们已经初步优化了模型的算法,使得预测效果更好了一些,接下来,我们可以通过特征工程构建,进一步优化模型的预测效果。
先对数据进行数据集转化,将一些特征标准化,方便后续操作,首先对时间特征进行统一,在我们的数据集中,时间特征有:date、hour、weekday、month、year。我们利用pandas库里的apply函数对数据进行分割。
DataFrame.apply(func, axis=0, broadcast=False, raw=False, reduce=None, args=(), **kwds)
解释:
1.该函数起作用的是第一个参数,提供一个函数,实现函数的功能。
2.这个函数需要自己实现,函数的传入参数根据axis来定,比如axis = 1,就会把一行数据作为Series的数据结构传入给自己实现的函数中,我们在函数中实现对Series不同属性之间的计算,返回一个结果,则apply函数会自动遍历每一行DataFrame的数据,最后将所有结果组合成一个Series数据结构并返回。
lambda函数,它是只有一个表达式的函数:
lambda arg: (操作表达式,一般包含arg)
split()函数,通过指定分隔符对字符串进行切片,如果参数num有指定值,则分隔num+1个子字符串
str.split( str="", num = string.count (str) )
参数介绍:
str — 分隔符,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等。
num — 分割次数,默认为-1,即分割所有。
返回值是分割后的字符串列表。
下面对数据进行处理:
from datetime import datetime dataDaily["date"] = dataDaily.datetime.apply(lambda x: x.split()[0]) dataDaily["hour"] = dataDaily.datetime.apply(lambda x: x.split()[1].split(":")[0]).astype("int") dataDaily["year"] = dataDaily.datetime.apply(lambda x: x.split()[0].split("-")[0]) dataDaily["weekday"] = dataDaily.date.apply(lambda x: datetime.strptime(x, "%Y-%m-%d").weekday()) dataDaily["month"] = dataDaily.date.apply(lambda x: datetime.strptime(x, "%Y-%m-%d").month)
处理后的结果:
可以看见,所有的时间数据都被统一成一种形式了。
在原始数据集中,我们可以发现,\’season\’,\’weather\’,\’holiday\’,\’workingday\’,\’weekday\’,\’month\’,\’year\’特征是int型数据,但是我们希望他们能成为category(分类类型数据),方便我们后续分析。
我们可以利用astype()函数,将他们转换为分类类型数据。
categoricalFeatureNames=[\'season\',\'weather\',\'holiday\',\'workingday\',\'weekday\',\'month\',\'year\'] for var in categoricalFeatureNames: dataDaily[var]=dataDaily[var].astype(\'category\')
对离散型数据season、weather进行One-Hot编码:
season
季节 1:春天, 2:夏天, 3:秋天, 4:冬天
weather
天气情况 1:无云,少量云,部分多云 2:雾+多云,雾+云散开,雾+少云,雾 3:小雪,小雨+雷暴+散云,小雨+散云 4:暴雨+冰雹+雷暴+雾,雪+雾
dataDaily[[\'season_orig\',\'weather_orig\']]=dataDaily[[\'season\',\'weather\']] dataDaily=pd.get_dummies(dataDaily,columns=[\'season\',\'weather\'],drop_first=True) dataDaily.head()
接下来,绘制count(结果)与其他因素的回归图,对数据进行分析:
#绘制count vs temp ,humidity windspeed,hour的回归图 sn.jointplot(x=\'temp\',y=\'count\',data=dataDaily,kind=\'reg\') sn.jointplot(x=\'humidity\',y=\'count\',data=dataDaily,kind=\'reg\') sn.jointplot(x=\'windspeed\',y=\'count\',data=dataDaily,kind=\'reg\') sn.jointplot(x=\'hour\',y=\'count\',data=dataDaily,kind=\'reg\')
虽然看上去这些自变量与因变量之间不存在线性关系,但是系统还是为我们画出了一条线性回归直线,但是这样数据的精确性就降低了,所以我们尝试利用log函数构造新的特征进行分析,我们对这几个特征的值都取对数。
dataDaily[\'log_temp\']=np.log1p(dataDaily.temp) dataDaily[\'log_windspeed\']=np.log1p(dataDaily.windspeed) dataDaily[\'log_humidity\']=np.log1p(dataDaily.humidity) dataDaily[\'log_hour\']=np.log1p(dataDaily.hour)
接着我们来检测某些特征的异常值,进行处理。
fig,axes=plt.subplots(2,2) fig.set_size_inches(24,12) sn.boxplot(data=dataDaily,y=\'count\',ax=axes[0][0]) sn.boxplot(data=dataDaily,y=\'count\',x=\'season_orig\',ax=axes[0][1]) sn.boxplot(data=dataDaily,y=\'count\',x=\'hour\',ax=axes[1][0]) sn.boxplot(data=dataDaily,y=\'count\',x=\'workingday\',ax=axes[1][1])
count
变量包含许多异常值数据点,这些数据点的分布右偏(因为超出外部四分位数限制的数据点更多)。可以从给出的下面的箱图做出以下推断:
- 1.春季用车数量相对较少,这点从箱形图中位数较低可以看出来。
- 2.
Hour Of The Day
的箱线图中。中位数的值在早上7点-早上8点和下午5点 – 下午6点相对较高。它可以归因于这些时间段的上学的人和上班族。 - 3.从图中可以清楚地看出,大多数离群值主要来自
Working Day
工作日而不是Non Working Day
非工作日。
删除计数列count中的异常值(保留count中与平均值偏差绝对值在3倍标准差以内的标准)对数据集处理,去掉相关项与无用项。
dropFeatures=[\'casual\',\'atemp\',\'datetime\',\'date\',\'registered\',\'count\',\'season_orig\',\'weather_orig\'] X = dataDaily.drop(dropFeatures, axis =1).copy() yLabels = dataDaily["count"] #固定随机种子,分割数据 train_x,test_x,train_y,test_y=train_test_split(X,yLabels,test_size=0.3,random_state=42) #得到训练数据 data=pd.concat([train_x,train_y],axis=1) #去除训练数据中的异常值 print(data.shape) mean=train_y.mean() std=train_y.std() data=data[np.abs(train_y-mean)<=(3*std)] print(data.shape)
下面对数值型特征进行MIn-Max标准化处理,使得模型能对其中的数据进行更好的训练拟合。
#数值特征标准化 numerialFeatureNames=[\'temp\',\'humidity\',\'windspeed\',\'hour\'] #MinMax标准化 from sklearn.preprocessing import MinMaxScaler scaler=MinMaxScaler() scaler.fit(data[numerialFeatureNames]) data[numerialFeatureNames]=scaler.transform(data[numerialFeatureNames]) #标准化后数值型特征的描述性统计量 data.describe()
可以看到,我们对 \’temp\’,\’humidity\’,\’windspeed\’,\’hour\’ 四个特征进行数字特征标准化后,min(最小值):0;max(最大值):1;以及四分位值都已更新。
现在重新建模,看看数据经过预处理后的模型预测效果。
#构造验证集 dataTest=pd.concat([train_x,train_y],axis=1) #目标与数据分离,删除不必要的特征 train_x = data.copy().drop(["count"], axis=1) train_y = data["count"] test_x = dataTest.copy().drop(["count"], axis=1) test_y = dataTest["count"] #重新建模预测需求的自行车数量 #重新训练模型 lModel=LinearRegression() lModel.fit(X=train_x,y=np.log1p(train_y)) preds=lModel.predict(X=test_x) #在验证集上验证 #回归效果RMSLE评估 print(\'NEW RMSLE: \',round(rmsle(test_y,np.expm1(preds)),4)) #查看预测效果 plt.plot(np.expm1(preds))