背着锄头的互联网农民

0%

Kaggle:预测未来销售(Predict Future Sales)

本文记录了Kaggle上Predict Future Sales问题的探索过程。

基础特征

数据主要有三个特征:shop_id, item_id, item_cnt_day。因为题目要求预测月份的销量情况,需要将训练数据中的按天销量改为按月销量,这里可以使用group_by或者pivot_table函数进行聚合。

1
2
3
4
5
6
7
8
9
10
11
12
train_data = pd.read_csv('./data/sales_train.csv')
#删除异常数据
train_data = train_data.drop(train_data[train_data.item_price < 0].index | train_data[train_data.item_price >= 100000].index)
train_data = train_data.drop(train_data[train_data.item_cnt_day < 0].index | train_data[train_data.item_cnt_day >= 1000].index)

train_data1 = pd.pivot_table(train_data, index=['shop_id','item_id','date_block_num'], values=['item_cnt_day'], aggfunc=[np.sum],fill_value=0).reset_index();
train_data1.columns = train_data1.columns.droplevel().map(str)
train_data1 = train_data1.reset_index(drop=True).rename_axis(None, axis=1)
train_data1.columns.values[0]="shop_id";
train_data1.columns.values[1]="item_id";
train_data1.columns.values[2]="month_id";
train_data1.columns.values[3]="item_cnt_month";

数据增强

根据上面shop_id, item_id, month_id三个特征来预测精度,在实际测试中只能得到rmse=7左右的精度,后来经过参考其他文章发现原因是上线的数据只包含了商店真正销售过的商品每月销量,但是如果商店该月没有销售该商品,则上面的数据中则没有该条数据。而实际上这时候该商店该月该商品的销售量应该等于0,这样更能体现商品、商店、销量的关系,引入这些数据后,rmse降到2.7左右。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
matrix = []
cols = ['month_id','shop_id','item_id']
for i in range(34):
sales = train_data[train_data.date_block_num==i]
matrix.append(np.array(list(product([i], sales.shop_id.unique(), sales.item_id.unique())), dtype='int16'))
matrix = pd.DataFrame(np.vstack(matrix), columns=cols)
matrix['month_id'] = matrix['month_id'].astype(np.int8)
matrix['shop_id'] = matrix['shop_id'].astype(np.int8)
matrix['item_id'] = matrix['item_id'].astype(np.int16)
matrix.sort_values(cols, inplace=True)
print(matrix.info())

train_data1 = pd.pivot_table(train_data, index=['shop_id','item_id','date_block_num'], values=['item_cnt_day'], aggfunc=[np.sum],
fill_value=0).reset_index();
train_data1.columns = train_data1.columns.droplevel().map(str)
train_data1 = train_data1.reset_index(drop=True).rename_axis(None, axis=1)
train_data1.columns.values[0]="shop_id";
train_data1.columns.values[1]="item_id";
train_data1.columns.values[2]="month_id";
train_data1.columns.values[3]="item_cnt_month";

#合并matrix和train_data1数据
train_data1 = pd.merge(matrix, train_data1, on=["shop_id", "item_id", "month_id"], how='left')
train_data1['item_cnt_month'] = (train_data1['item_cnt_month'].fillna(0).astype(np.float16))
train_data1["month_id1"] = train_data1["month_id"] % 12;
print(train_data1.info())

销量优化

其他文章中有一个比较trick的优化措施,是限定训练数据中每月每个商品最大的销量是20,该优化可以将rmse减少到1.1左右。

1
train_data1['item_cnt_month'] = (train_data1['item_cnt_month'].fillna(0).clip(0,20).astype(np.float16))

增加其他特征

直观上理解,每个商店每个商品的当月销量应该和上个月的销量有关系,另外可能相关的特征包括:该商品上个月在所有商店的总销量,该商店上个月的总销量,商品类型,商品上个月平均价格等,增加完这些特征后rmse达到1.0左右。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
train_data2 = pd.pivot_table(train_data, index=['shop_id','item_id','date_block_num'], values=['item_cnt_day'], aggfunc=[np.sum],
fill_value=0).reset_index();
train_data2.columns = train_data2.columns.droplevel().map(str)
train_data2 = train_data2.reset_index(drop=True).rename_axis(None, axis=1)
train_data2.columns.values[0]="shop_id";
train_data2.columns.values[1]="item_id";
train_data2.columns.values[2]="month_id";
train_data2.columns.values[3]="item_cnt_month1";
train_data2["month_id"] = train_data2["month_id"] + 1;

item_price1 = pd.pivot_table(train_data, index=['item_id','date_block_num'], values=['item_price'], aggfunc=[np.mean], fill_value=
0).reset_index();
item_price1.columns = item_price1.columns.droplevel().map(str)
item_price1 = item_price1.reset_index(drop=True).rename_axis(None, axis=1)
item_price1.columns.values[0]="item_id";
item_price1.columns.values[1]="month_id";
item_price1.columns.values[2]="item_mean_price1";
item_price1["month_id"] = item_price1["month_id"] + 1;

shop_cnt = pd.pivot_table(train_data1, index=['shop_id','month_id'], values=['item_cnt_month'], aggfunc=[np.mean], fill_value=0).r
eset_index();
shop_cnt.columns = shop_cnt.columns.droplevel().map(str)
shop_cnt = shop_cnt.reset_index(drop=True).rename_axis(None, axis=1)
shop_cnt.columns.values[0]="shop_id";
shop_cnt.columns.values[1]="month_id";
shop_cnt.columns.values[2]="shop_cnt_month1";
shop_cnt["month_id"] = shop_cnt["month_id"] + 1;

item_cnt = pd.pivot_table(train_data1, index=['item_id','month_id'], values=['item_cnt_month'], aggfunc=[np.mean], fill_value=0).r
eset_index();
item_cnt.columns = item_cnt.columns.droplevel().map(str)
item_cnt = item_cnt.reset_index(drop=True).rename_axis(None, axis=1)
item_cnt.columns.values[0]="item_id";
item_cnt.columns.values[1]="month_id";
item_cnt.columns.values[2]="item_total_month1";
item_cnt["month_id"] = item_cnt["month_id"] + 1;


combined_data = train_data1.append(test_data);
#合并上述的五个特征到训练集中
combined_data = pd.merge(combined_data, train_data2, on = ['shop_id', 'item_id','month_id'], how = 'left')
combined_data["item_cnt_month1"].fillna(0, inplace=True)

combined_data = pd.merge(combined_data, item_price1, on = ['item_id','month_id'], how = 'left')
combined_data["item_mean_price1"].fillna(0, inplace=True)

combined_data = pd.merge(combined_data, shop_cnt, on = ['shop_id','month_id'], how = 'left')
combined_data["shop_cnt_month1"].fillna(0, inplace=True)

combined_data = pd.merge(combined_data, item_cnt, on = ['item_id', 'month_id'], how = 'left')
combined_data["item_total_month1"].fillna(0, inplace=True)

combined_data = pd.merge(combined_data, item_data, on = ['item_id'], how = 'left')
combined_data["item_category_id"].fillna(0, inplace=True)

模型训练

这里使用xgboost模型进行训练,实际中可使用交叉验证或者验证集+早停技术避免过拟合。

1
2
model = xgb.XGBRegressor(max_depth=4, colsample_btree=0.1, learning_rate=0.1, n_estimators=32, min_child_weight=2);
model.fit(X_train, y_train)

总结

针对问题首先寻找可以利用的所有数据,数据中可能包含着特征和目标的关系。然后根据对问题的理解寻找特征,尽可能的多加一些特征验证效果。验证效果时候先优化训练集误差,如果训练集误差比较大说明模型是高偏差的,这时候应该增加能描述其他关系的数据、增加特征、增加模型复杂度来减少偏差。如果训练集误差减不下去,这时候应用到训练集上面必然也是无效的。当训练集误差减下去后,如果在测试集上有过拟合问题,再使用一些措施比如减少模型复杂度、减少特征、正则化等来避免过拟合。