2018天池比赛首战落幕

 

印象盐城·数创未来大数据竞赛 - 盐城汽车上牌量预测

 

从本次经历来看这份成绩我还是满意的。

 

毕竟我并没有像那些大佬们从数据的行列之间进行关联性分析,独立性检验之类的专业技术流操作。我只是个机器学习的小浪花。

2018天池比赛首战落幕_第1张图片

通过这次比赛,我明白了要更多的联系社会实际生活的话,还是需要时间序列这块的理论知识和技能手段作支撑才能走的更远。

接下来分享一下大佬做比赛的思路流程,我只是复现。

 

 

寒武纪の盐城车牌预测数据初探 之 三

麻婆豆腐

 

 

 

第一步 导入数据

#调包侠

importpandas as pd

importmatplotlib.pyplot as plt

 

#第一步导入数据

dir ='data/'

train =pd.read_table(dir + 'train_20171215.txt',engine='python')

test_A =pd.read_table(dir + 'test_A_20171225.txt',engine='python')

sample_A =pd.read_table(dir + 'sample_A_20171225.txt',engine='python',header=None)

 

先查看数据traintest_A的数据样式

print("train.info():")

print(train.info())

print("test_A.info():")

print(test_A.info())

 

train.info():

RangeIndex: 4773entries, 0 to 4772

Data columns (total 4columns):

date           4773 non-null int64

day_of_week    4773 non-null int64

brand          4773 non-null int64

cnt            4773 non-null int64

dtypes: int64(4)

memory usage: 149.2KB

None

test_A.info():

RangeIndex: 276entries, 0 to 275

Data columns (total 2columns):

date           276 non-null int64

day_of_week    276 non-null int64

dtypes: int64(2)

memory usage: 4.4 KB

None

这里呈现给我们的train和test中字段形式并不一样,test中缺少了品牌即brand和需要预测的数量cnt(这个是合理的,因为需要预测)

通过对题目的阅读,第一赛季只需要预测量而不需要预测具体品牌的量,这样可以理解为,无论白猫还是黑猫,在一起就是两只猫。之后,数据类型是int64,即这个题目给我们的都是数值型的数据。

其中date根据题目,为脱敏数据,brand和cnt也是脱敏,但是dayofweek的值是真是反应星期的数值,首先观察一下这个唯一一个相对而言是真实值的值的形式

 

print(train['day_of_week'].unique())

print(test_A['day_of_week'].unique())

[3 4 5 6 7 1 2]

[4 5 6 1 2 3 7]

dow(dayofweek)的范围是1-7,可以理解为对应的周一到周日,也就是monday到sunday。

 

 

 

第二步:找出目标值(即需要我们预测的值)

这里,我们需要去观察目标值的范围变化,看一下目标值的大体趋势如何,首先以箱型图去观察一下目标值的变化。

箱形图有5个参数: 
下边缘(Q1),表示最小值; 
下四分位数(Q2),又称“第一四分位数”,等于该样本中所有数值由小到大排列后第25%的数字; 
中位数(Q3),又称“第二四分位数”等于该样本中所有数值由小到大排列后第50%的数字; 
上四分位数(Q4),又称“第三四分位数”等于该样本中所有数值由小到大排列后第75%的数字; 
上边缘(Q5),表述最大值。 
第三四分位数与第一四分位数的差距又称四分位间距。

功能:

1.为了反映原始数据的分布情况,比如数据的聚散情况和偏态。看看《统计学》这本书的插图 

2..箱型图有个功能就是可以检测这组数据是否存在异常值。.箱型图有个功能就是可以检测这组数据是否存在异常值。

plt.boxplot(train['cnt'])

plt.show()

根据这个图,结合1所示的例子,大概可以估计出数据是右偏分布,以正态分布的角度观察,异常值存在于大于1000的地方,之后,绘制一个分布图,观察一下数据的分布。

importseaborn as sns

color =sns.color_palette()

sns.set_style('darkgrid')

from scipyimport stats

fromscipy.stats import norm, skew

 

sns.distplot(train['cnt'],fit=norm)

源代码,但是自己就是得不到结果(下图是大佬原图)

通过绘制分布图,可以看出来数据分布确实符合右偏分布,这里大概初步了解数据的分布尺度在 0 到 2000 左右,且在0-500/1000的数量最密集。

 

第三步:找出与目标最相关的变量X(即非目标值中找到与目标最相关的值)

因为数据本身与时间相关,所以我们可以绘制一下随脱敏时间和星期的变化

plt.plot(train['date'],train['cnt'])

plt.show()

 

结合箱图和分布图,可以确定,密集区域集中中500,之后我们以具体的数字反应意思刚才的图的信息。

print(train['cnt'].describe())

 

count   4773.000000

mean     380.567358

std      252.720918

min       12.000000

25%      221.000000

50%      351.000000

75%      496.000000

max     2102.000000

Name: cnt, dtype: float64

2)预测结果以mean square error作为评判标准,具体公式如下:
 

这里,可以以统计数据去确定一下,这些统计数据,在评测函数的指标。

fromsklearn.metrics import mean_squared_error

train['25%']= 221

train['50%']= 351

train['75%']= 496

train['median']= train['cnt'].median()

train['mean']= train['cnt'].mean()

print(mean_squared_error(train['cnt'],train['25%']))

print(mean_squared_error(train['cnt'],train['50%']))

print(mean_squared_error(train['cnt'],train['75%']))

print(mean_squared_error(train['cnt'],train['median']))

print(mean_squared_error(train['cnt'],train['mean']))

 

89316.2231301

64728.7100356

77179.1761995

64728.7100356

63854.4813732

可以大概看出来,由于存在异常点较多,导致统计量在时间轴上的表现并不是那么理想。现在还可以用的信息,只剩下了星期了,救命稻草之星期信息。

开始对星期信息统计,分别分析周一周五的分布情况

 

monday =train[train['day_of_week']==1]

plt.plot(range(len(monday)),monday['cnt'])

plt.show()

很明显了,可以把1-5和6,7分为两组去分析

简单分析一下按照星期的评测分数

res =train.groupby(['day_of_week'],as_index=False).cnt.mean()

xx =train.merge(res,on=['day_of_week'])

print(xx.head())

print('mse:',mean_squared_error(xx['cnt_x'],xx['cnt_y']))

mse明显小于之前的结果,所以这里暂时可以估计,以星期去统计分布。

 

# 因为第一赛季只是预测与时间相关的cnt的数量

# 所以可以对数据以datdow进行数据合并

train =train.groupby(['date','day_of_week'],as_index=False).cnt.sum()

plt.plot(train['day_of_week'],train['cnt'],'*')

plt.show()

这样很明显,看到在合并品牌之后,观察星期的分布情况,这样的观察,是观察周1-7的cnt的分布情况,可以初步认为距离密集区域较远的为异常数据。

for i inrange(7):

    tmp = train[train['day_of_week']==i+1]

    plt.subplot(7, 1, i+1)

    plt.plot(tmp['date'],tmp['cnt'],'*')

plt.show()

从上往下分别是1,2,3,4,5,6,7这样就很清楚的看见了。

训练集和测试集的分布

这样,我们首先要做的就是线下的验证机,模拟线上的数据。

此时的数据就是按星期聚类之后的数据集。

xx_train =train[train['date']<=756]

xx_test =train[train['date']>756]

print('testshape',xx_test.shape)

print('trainshape',xx_train.shape)

方案零:均值大法(原始数据验证)

# 线下统计每周的均值数据,不加权

xx_train =xx_train.groupby(['day_of_week'],as_index=False).cnt.mean()

xx_result =pd.merge(xx_test,xx_train,on=['day_of_week'],how='left')

print('xx_resultshape',xx_result.shape)

print(xx_result)

print(mean_squared_error(xx_result['cnt_x'],xx_result['cnt_y']))

查看周一到周日的情况,其mse得分如下所示

for i inrange(7):

    tmp =xx_result[xx_result['day_of_week']==i+1]

print('%d'%(i+1),mean_squared_error(tmp['cnt_x'],tmp['cnt_y']))

感觉好差,所以要进一步优化结果

查看一下我们划分的线下数据的方差情况,说明数据的波动很明显,又是是周日的数据,根据前面的图,可以看出,数据中的异常点分布,看起来规律并不明显。而且,周日的数据本身就存在缺失,这种情况下。根据图分布可以看出来。

方案一:加权平均大法

    这个方案主要是采取历史纪录*一个权值(可选函数为反比例函数,指数函数和简单的递减函数)

    最后以之前分析的星期为周期,进行权重融合,求得最后结果。

def xx(df):

  df['w_cnt'] = (df['cnt'] * df['weight']).sum() / sum(df['weight'])

  return df

 

xx_train =train[train['date']<=756]

xx_train['weight'] =((xx_train['date'] + 1) / len(xx_train)) ** 6

xx_train =xx_train.groupby(['day_of_week'],as_index=False).apply(xx).reset_index()

xx_test =train[train['date']>756]

print('test shape',xx_test.shape)

print('trainshape',xx_train.shape)

# #

from sklearn.metrics importmean_squared_error

# # 这里是加权的方案

xx_train =xx_train.groupby(['day_of_week'],as_index=False).w_cnt.mean()

 

xx_result =pd.merge(xx_test,xx_train,on=['day_of_week'],how='left')

print('xx_resultshape',xx_result.shape)

print(xx_result)

print(mean_squared_error(xx_result['cnt'],xx_result['w_cnt']))

test shape (276, 3)

train shape (756, 6)

xx_result shape (276,4)

     date day_of_week   cnt        w_cnt

0     757            6  314   419.121951

1     758            1 3309  2593.503011

2     759            2 1948  2615.940149

3     760            3 1722  2285.466506

4     761            4 1520  1839.909973

5     762            5 2232  1928.241036

6     763            6  497   419.121951

7     764            1 2037  2593.503011

8     765            2 2246  2615.940149

9     766            3 1447  2285.466506

10    767            4 1478  1839.909973

11    768            5 1631  1928.241036

12    769            6  128   419.121951

13    770            1 2102  2593.503011

14    771           2  2114  2615.940149

15    772            3 1964  2285.466506

16    773            4 1427  1839.909973

17    774            5 1416  1928.241036

18    775            6  319   419.121951

19    776            1 2147  2593.503011

20    777            2 1925  2615.940149

21    778            3 1668  2285.466506

22    779            4 1692  1839.909973

23    780            5 1517  1928.241036

24    781            6  381   419.121951

25    782            1 2327  2593.503011

26    783           2  1926 2615.940149

27    784            3 1387  2285.466506

28    785            4 1533  1839.909973

29    786            5 1946  1928.241036

..    ...         ...   ...          ...

246  1003            4 1618  1839.909973

247  1004           5  2259 1928.241036

248  1005            6  426   419.121951

249  1006            1 2203  2593.503011

250  1007            2 2344  2615.940149

251  1008            3 2392  2285.466506

252  1009            4 1870  1839.909973

253  1010            5 1772  1928.241036

254  1011            6  610   419.121951

255  1012            1 2437  2593.503011

256  1013            2 2326  2615.940149

257  1014            3 1954  2285.466506

258  1015            4 1569  1839.909973

259  1016           5  1777 1928.241036

260  1017            6  442   419.121951

261  1018            1 2476  2593.503011

262  1019            2 1934  2615.940149

263  1020            3 2048  2285.466506

264  1021            4 1586  1839.909973

265  1022           5  2268 1928.241036

266  1023            6  506   419.121951

267  1024            1 3439  2593.503011

268  1025            2 3208  2615.940149

269  1026            3 2277  2285.466506

270  1027            4 2144  1839.909973

271  1028            5 2519  1928.241036

272  1029            6  195   419.121951

273  1030            2 4003  2615.940149

274  1031            3 2513  2285.466506

275  1032            4 1306  1839.909973

 

[276 rows x 4columns]

828419.30779

 

可以发现,加权后的结果好于直接均值的效果,其思想考虑了近期影响大于远期影响。其实这个线下分数,只能算是一个开始,只要是模型的线下,理论应该会好于这个结果。

 

根据预测结果估计,可以预测到,每条数据的偏差应该在1000左右,其实这样而言,明显是差别很大。(⊙﹏⊙)接下来,要采取一些方案处理一下原始数据。

暂时这样吧,大概的两个过程是这样,应该还可以优化,如果有问题和意见可以留言,一起改善。 现在看起来,需要补充一下数据,对周日的数据补充一下。暂时思路吧。80多万的mse,说明每条数据平均和真实值的差距在1000左右。

 

在大佬的思路支撑下,我就按照大佬的数据处理思路,对data和day_of_week,在日期上按照星期进行训练数据的聚类。

XGBT线下测试成绩是最好的,但是能力有限并没有解决模型不能测试的问题。

最后采用了lgm+gbdt的方法进行优化,从结果上有了不小的提升。

这次比赛自己收获了一些心得,期待以后能走的更远。

为了方便大家 数据集百度网盘的链接

链接: https://pan.baidu.com/s/14clDc4O71L76rduwIeEZQA 提取码: gm1y 

你可能感兴趣的:(比赛记录)