共享单车租赁量预测
一个项目最重要的可能不是代码,而是项目的流程和实际项目情况
首先这个项目的意义是什么,对使用量的预测,能够帮助企业精确投放,来优化客户体验,节约成本。不做没有意义的投放,这就是实际的需求。
这是一个关于自行车租赁预测的题目,相当于国内的ofo,摩拜单车 通过对数据的预测,可以观测到共享单车在某个时间段的租赁数量,如果预测值和实际租赁值存在很大差异,就应该去调查情况,从而保证共享单车的正常运营
适用场景:
回归
场景,需要对数据进行分析处理
import pandas as pd;
import numpy as np
import pylab
import calendar
import numpy as np
import pandas as pd
import seaborn as sn # matplotlib更高级封装的库
from scipy import stats
import missingno as msno #缺失值可视化处理
from datetime import datetime
import matplotlib.pyplot as plt
import warnings
from sklearn.model_selection import GridSearchCV
pd.options.mode.chained_assignment = None # 避免pandas报错
warnings.filterwarnings("ignore") # 忽略警告
%matplotlib inline
一、检视数据信息
1.帮助我们查看字段的特征和字段的名称
2.查看是否存在所谓的缺失值
3.数据的分布状态
本应用train和test两个数据集,因为kaggle上test数据上需要上网验证效果,所以在这里只使用train进行处理,所有数据都是每个月的前20天的信息
df=pd.read_csv("./input_data/train.csv")
查看样本的所有数据,能够查看数据字段进行分析
第一点,需要对datetime进行处理,
第二点, casual + register = count
可以通过info方法,查看数据类型,是否有
缺失值
等信息
可以看出,用车量是casual 和registered 的总和
df.describe()主要查看数据分布状态,可以更好的对数据进行分析,注意下面的mean均值,方差std
在进行数据分析之前,对数据进行切分,只查看训练集进行数据分析
from sklearn.model_selection import train_test_split
train_df, test_df = train_test_split(df)#将数据集进行切分,训练集和测试集比例为7.5:2.5
查看训练集信息
二、数据处理
其实算法的选择会比较单一和硬性,但是数据的处理可能和经验有关,留下有用的数据,
去掉垃圾数据
,对于模型的准确度来说是很重要的!
为了能够统一设置数据集,将训练集和测试集设置名称,将进行拼接成整体
all_df统一设置, 后续做预处理时,
需要对训练集和测试集统一处理
因为我们真实状态下观察样本信息时,只能通过训练集观察,如果观察测试集数据,现实工程中不可行,而且会影响模型预测精度
test_df["traintest"]='test';
train_df["traintest"]='train';
all_df=pd.concat((train_df,test_df))#拼接到一起处理
datetime字段比较复杂,将它进行切分处理
date 为日期
month 为英文
monthnum 为中文
lambda表达式,是一种匿名函数,返回值、参数: 方法体
日期的处理可以说是一个典型了!!基本上对于日期时间的处理都可以用这种方法!!
daynum:为每月第几天
hour: 为小时
weekday: 为周几
all_df["daynum"]=all_df.datetime.apply(lambda x : int(x.split()[0].split('-')[2]))
all_df["hour"] = all_df.datetime.apply(lambda x : int(x.split()[1].split(":")[0]))
all_df["weekday"] = all_df.date.apply(
lambda dateString : calendar.day_name[datetime.strptime(dateString,"%Y-%m-%d").weekday()])
根据小时用车辆对数据进行分析
通过图像可以看出,0-6点用车人数少,7-10点用车人数多,11-15为低谷,16-20点为高峰,21-24用车人数少
数据分层典型处理方法
# 数据分层 1.可以简化模型运算 2.更好的对数据分布情况进行分析计算
def hour_section(hour):
if hour>=0 and hour<=6:
return 0
elif hour>=7 and hour<=10:
return 1
elif hour>=11 and hour<=15:
return 2
elif hour>=16 and hour<=20:
return 3
else :return 4
创建一个新的字段,用于表示用车时间段
all_df["hour_section"]=all_df.hour.apply(hour_section)
三、数据降噪
对数据是否有噪音进行查看
只针对训练集进行降噪,为了更好拟合数据,让模型进度更优
因为测试集就代表未来的数据信息,而未来的数据信息中必定包含噪音,所以不对测试集进行降噪处理
新图
箱形图(Box-plot)又称为盒须图、盒式图或箱线图,是一种用作显示一组数据分散情况资料的统计图。
因形状如箱子而得名。在各种领域也经常被使用,常见于品质管理。它主要用于反映原始数据分布的特征,还可以进行多组数据分布特征的比 较。箱线图的绘制方法是:先找出一组数据的最大值、最小值、中位数和两个四分位数;然后, 连接两个四分位数画出箱子;再将最大值和最小值与箱子相连接,中位数在箱子中间。
fig, axes = plt.subplots(nrows=2,ncols=2)
fig.set_size_inches(12, 10)
sn.boxplot(data=all_df.loc[all_df.traintest=='train'],y="count",ax=axes[0][0])
sn.boxplot(data=all_df.loc[all_df.traintest=='train'],y="count",x="season",ax=axes[0][1])
sn.boxplot(data=all_df.loc[all_df.traintest=='train'],y="count",x="hour",ax=axes[1][0])
sn.boxplot(data=all_df.loc[all_df.traintest=='train'],y="count",x="workingday",ax=axes[1][1])
axes[0][0].set(ylabel='Count',title="Box Plot On Count")
axes[0][1].set(xlabel='Season', ylabel='Count',title="Box Plot On Count Across Season")
axes[1][0].set(xlabel='Hour Of The Day', ylabel='Count',title="Box Plot On Count Across Hour Of The Day")
axes[1][1].set(xlabel='Working Day', ylabel='Count',title="Box Plot On Count Across Working Day")
查看训练集,观察内部是否存在噪音
查找噪音点(数据点-均值超过该数据标准差的三倍视为噪音),并计算数量
异常点的标准是是看y值离不离群。
outliers=np.abs(all_df.loc[all_df.traintest=='train',["count"]]
-all_df.loc[all_df.traintest=='train',["count"]].mean()) >
(3*all_df.loc[all_df.traintest=='train',["count"]].std()) # 3倍不是硬性规定,是需要根据箱图来去计算的
len(all_df.loc[all_df.traintest=='train'][outliers['count'].values])
109
同样,计算真实数据点个数
goodpoints=np.abs(all_df.loc[all_df.traintest=='train',["count"]]-all_df.loc[all_df.traintest=='train',["count"]].mean()) <=(3*all_df.loc[all_df.traintest=='train',["count"]].std())
len(all_df.loc[all_df.traintest=='train'][goodpoints['count'].values])
8055
只保留训练集中正常样本点和测试集数据,重新构建all_df
查看处理后的数据样本量
四、数据分析
corr()相关系数,列举出重要特征之间的相关性,判断是否进行删除
一般大于0.6才进行删除
corrMatt = all_df.loc[all_df.traintest=='train',["temp","atemp","casual","registered","humidity","windspeed","count"]].corr()
mask = np.array(corrMatt)
mask[np.tril_indices_from(mask)] = False # 通过索引找数据方式
fig,ax= plt.subplots()
fig.set_size_inches(15,8)
# mask 缺少数值的单元格自动隐藏 , vmax 最大值为80%, square = True 所有单元格为方形, annot=True 注释热图
sn.heatmap(corrMatt, mask=mask,vmax=.8, square=True,annot=True) # matplotlib的高级封装
分析季节对用车辆的影响
分析时间对用车辆的影响
查看小时和季节对用车的影响
查看星期对用车的影响
能够看出,周末的用车时段和工作日不同,所以在这里进行数据值修改
def hour_section(hour,weekday):
if weekday not in ['Saturday','Sunday']:
if hour>=0 and hour<=6:
return 0
elif hour>=7 and hour<=10:
return 1
elif hour>=11 and hour<=15:
return 2
elif hour>=16 and hour<=20:
return 3
else :return 4
else: # 周六日用车分析
if hour>=0 and hour <=8 :
return 5
elif hour >=9 and hour <=20:
return 6
else: return 7
添加一项周末对用车的影响
all_df['hour_week_section']=all_df.apply(lambda row: hour_section(row['hour'], row['weekday']), axis=1)
all_df.info()
查看假期占比
五、特征工程
做完这些分析,准备做特征工程,比如归一化,缺失值填充,构造新的特征等。
all_df.info()
使用pandas做onehot操作 需要让大家进行优化处理,修改为使用sklearn.preprocision 中的OneHotEncoder进行处理
all_df=pd.get_dummies(all_df,columns=['season'])
all_df=pd.get_dummies(all_df,columns=['weather'])
数据标准化处理
import sklearn.preprocessing as preprocessing
scaler = preprocessing.StandardScaler()
temp_scale_param = scaler.fit(all_df[['temp']]) # 温度
all_df['temp_scaled'] = scaler.fit_transform(all_df[['temp']], temp_scale_param)
scaler = preprocessing.StandardScaler()
atemp_scale_param = scaler.fit(all_df[['atemp']]) # 体感温度
all_df['atemp_scaled'] = scaler.fit_transform(all_df[['atemp']], atemp_scale_param)
scaler = preprocessing.StandardScaler()
humidity_scale_param = scaler.fit(all_df[['humidity']]) # 湿度
all_df['humidity_scaled'] = scaler.fit_transform(all_df[['humidity']], atemp_scale_param)
scaler = preprocessing.StandardScaler()
humidity_scale_param = scaler.fit(all_df[['windspeed']]) # 风速
all_df['windspeed_scaled'] = scaler.fit_transform(all_df[['windspeed']], atemp_scale_param)
对时间进行处理分析
import datetime
def date_diff(date):
first_new_year=str(date[0:4])+"-01-01 00:00:00"
next_new_year=str(int(date[0:4])+1)+"-01-01 00:00:00"
date = datetime.datetime.strptime(date, '%Y-%m-%d %H:%M:%S')
first_new_year = datetime.datetime.strptime(first_new_year, '%Y-%m-%d %H:%M:%S')
next_new_year = datetime.datetime.strptime(next_new_year, '%Y-%m-%d %H:%M:%S')
if (abs((date-first_new_year).days)) > (abs ((date-next_new_year).days)):
return (abs((date-next_new_year).days))
else:return (abs((date-first_new_year).days))
all_df['date_newyear_num']=all_df.datetime.apply(date_diff)
scaler = preprocessing.StandardScaler()
date_newyear_num_scale_param = scaler.fit(all_df[['date_newyear_num']])
all_df['date_newyear_num_scaled'] = scaler.fit_transform(all_df[['date_newyear_num']], date_newyear_num_scale_param)
独热编码处理
all_df=pd.get_dummies(all_df,columns=['month'])
all_df=pd.get_dummies(all_df,columns=['hour'])
all_df=pd.get_dummies(all_df,columns=['weekday'])
all_df=pd.get_dummies(all_df,columns=['hour_workingday'])
all_df=pd.get_dummies(all_df,columns=['hour_week_section'])
all_df.columns.values
array(['datetime', 'holiday', 'workingday', 'temp', 'atemp', 'humidity',
'windspeed', 'casual', 'registered', 'count', 'traintest', 'date',
'monthnum', 'daynum', 'hour_section', 'temp_int', 'season_1',
'season_2', 'season_3', 'season_4', 'weather_1', 'weather_2',
'weather_3', 'weather_4', 'temp_scaled', 'atemp_scaled',
'humidity_scaled', 'windspeed_scaled', 'date_newyear_num',
'date_newyear_num_scaled', 'month_April', 'month_August',
'month_December', 'month_February', 'month_January', 'month_July',
'month_June', 'month_March', 'month_May', 'month_November',
'month_October', 'month_September', 'hour_0', 'hour_1', 'hour_2',
'hour_3', 'hour_4', 'hour_5', 'hour_6', 'hour_7', 'hour_8',
'hour_9', 'hour_10', 'hour_11', 'hour_12', 'hour_13', 'hour_14',
'hour_15', 'hour_16', 'hour_17', 'hour_18', 'hour_19', 'hour_20',
'hour_21', 'hour_22', 'hour_23', 'weekday_Friday',
'weekday_Monday', 'weekday_Saturday', 'weekday_Sunday',
'weekday_Thursday', 'weekday_Tuesday', 'weekday_Wednesday',
'hour_workingday_0_0', 'hour_workingday_0_1',
'hour_workingday_10_0', 'hour_workingday_10_1',
'hour_workingday_11_0', 'hour_workingday_11_1',
'hour_workingday_12_0', 'hour_workingday_12_1',
'hour_workingday_13_0', 'hour_workingday_13_1',
'hour_workingday_14_0', 'hour_workingday_14_1',
'hour_workingday_15_0', 'hour_workingday_15_1',
'hour_workingday_16_0', 'hour_workingday_16_1',
'hour_workingday_17_0', 'hour_workingday_17_1',
'hour_workingday_18_0', 'hour_workingday_18_1',
'hour_workingday_19_0', 'hour_workingday_19_1',
'hour_workingday_1_0', 'hour_workingday_1_1',
'hour_workingday_20_0', 'hour_workingday_20_1',
'hour_workingday_21_0', 'hour_workingday_21_1',
'hour_workingday_22_0', 'hour_workingday_22_1',
'hour_workingday_23_0', 'hour_workingday_23_1',
'hour_workingday_2_0', 'hour_workingday_2_1',
'hour_workingday_3_0', 'hour_workingday_3_1',
'hour_workingday_4_0', 'hour_workingday_4_1',
'hour_workingday_5_0', 'hour_workingday_5_1',
'hour_workingday_6_0', 'hour_workingday_6_1',
'hour_workingday_7_0', 'hour_workingday_7_1',
'hour_workingday_8_0', 'hour_workingday_8_1',
'hour_workingday_9_0', 'hour_workingday_9_1',
'hour_week_section_0', 'hour_week_section_1',
'hour_week_section_2', 'hour_week_section_3',
'hour_week_section_4', 'hour_week_section_5',
'hour_week_section_6', 'hour_week_section_7'], dtype=object)
all_df.to_csv("feature_engine.csv")
数据集划分,方便以后查看信息
X=all_df.loc[all_df.traintest=='train',feature_columns].values # 训练集特征
y_casual=all_df.loc[all_df.traintest=='train'].casual.apply(lambda x: np.log1p(x)).values
y_regstered=all_df.loc[all_df.traintest=='train'].registered.apply(lambda x: np.log1p(x)).values
y_all=all_df.loc[all_df.traintest=='train','count'].values # 训练集标签
X_test=all_df.loc[all_df.traintest=='test',feature_columns].values # 测试集特征
X_date=all_df.loc[all_df.traintest=='test','datetime'].values
y_test=all_df.loc[all_df.traintest=='test','count'].values # 测试集标签
将数据信息进行保存处理
all_df.loc[all_df.traintest=='train',feature_columns].to_csv("X.csv")
all_df.loc[all_df.traintest=='train'].casual.apply(lambda x: np.log1p(x)).to_csv("y_casual.csv")
all_df.loc[all_df.traintest=='train'].registered.apply(lambda x: np.log1p(x)).to_csv("y_regstered.csv")
all_df.loc[all_df.traintest=='train','count'].apply(lambda x: np.log1p(x)).to_csv("y_all.csv")
all_df.loc[all_df.traintest=='test',feature_columns].to_csv("X_test.csv")
all_df.loc[all_df.traintest=='test','datetime'].to_csv("X_date.csv")
六、模型创建及评测
L1正则化, alpha正则项系数选择是最小值,证明L1正则化方式不适合该模型进行精度计算
from sklearn.linear_model import Lasso, Ridge
lasso = Lasso()
param_grid = {'alpha': [1, 0.5, 0.1, 0.01, 0.0001]}
model1 = GridSearchCV(lasso, param_grid=param_grid, cv=10)
model1.fit(X, y_all)
print(model1.best_params_)
print(model1.score(X_test, y_test))
{'alpha': 0.0001}
0.7663301412909473
L2正则,线性回归整体效果不理想
ridge = Ridge()
param_grid = {'alpha': [1, 0.5, 0.1, 0.01, 0.0001]}
model2 = GridSearchCV(ridge, param_grid=param_grid, cv=10)
model2.fit(X, y_all)
print(model2.best_params_)
print(model2.score(X_test, y_test))
{'alpha': 1}
0.7660617181719144
使用集成学习处理算法
集成学习运算效率会非常慢 一个算法将近半小时的时间(4核八线程, 12G内存条)
随机森林效果明显很好
from sklearn.ensemble import RandomForestRegressor
rf = RandomForestRegressor()
param_grid = {
'n_estimators': [50, 100, 200, 500],
# 'max_depth': [2, 3, 4],
}
model3 = GridSearchCV(rf, param_grid=param_grid, cv=10)
model3.fit(X, y_all)
print(model3.best_params_)
print(model3.score(X_test, y_test))
{'n_estimators': 500}
0.8537900349049669
GBDT 梯度提升树的处理, 效果也不错,不过还是可以继续调参
from sklearn.ensemble import GradientBoostingRegressor
gbdt = GradientBoostingRegressor()
param_grid = {
'n_estimators': [50, 100, 200, 500],
# 'max_depth': [2, 3, 4]
}
model4 = GridSearchCV(gbdt, param_grid=param_grid, cv=10)
model4.fit(X, y_all)
print(model4.best_params_)
print(model4.score(X_test, y_test))
{'n_estimators': 500}
0.8407082355311021
Adaboost这种模型预测该算法不可行,精度不能达到实际要求
from sklearn.ensemble import AdaBoostRegressor
ab = AdaBoostRegressor()
param_grid = {
'n_estimators': [50, 100, 200, 500],
# 'max_depth': [2, 3, 4]
}
model5 = GridSearchCV(ab, param_grid=param_grid, cv=10)
model5.fit(X, y_all)
print(model5.best_params_)
print(model5.score(X_test, y_test))
{'n_estimators': 100}
0.5593182730057247
总结,最后,会选择随机森林和梯度提升树进行比较,调参得到最好的模型进行处理
字段分析
人为分析每个字段的含义,之间存在的关联,在数据分析时可以更好的体现数据之间的关联性
字段处理(数据挖掘) 日期处理
本身字段没有使用价值,可以对字段进行拆分或者合并的方式,将字段拆解成更多有利于分析的信息
噪音处理
噪音肯定会影响最终的判断结果,需要将训练集的噪音进行去除,依据 样本-均值和标准差之间的关系
数据分析
分析每个字段和标签之间的关系,以及字段之间是否存在关联
数据预处理
离散值进行onehot处理,连续值进行标准化处理
应用处理
尽可能使用多种模型进行预算,同时使用网格搜索配合大量参数进行拟合,选出最优参数
代码在这呢!!
链接:https://pan.baidu.com/s/1z249OLF58lapp_aV2kCgUQ
提取码:lent
复制这段内容后打开百度网盘手机App,操作更方便哦