本次学习记录的数据集为Predict Future Sales。地址链接
一.数据描述
目标:
将获得每日历史销售数据。 任务是在测试集上预测每个商店中出售的产品总数。 请注意,商店和产品清单每个月都会略有变化。
属性特征:
ID - 表示测试集中的(商店,商品)元组的id
shop_id - 表示商店的唯一id
item_id - 表示商品的唯一id
item_category_id - 商品类别的唯一id
item_cnt_day - 销售的产品数量(预测的目标值)。
item_price - 商品的当前价格
date - 商店经营销售的日期
date_block_num - 年份中月份的编号。January 2013 为0, February 2013 为1,…, October 2015 为33
item_name - 商品名称
shop_name - 商店名称
item_category_name - 商品类别名称
评价指标:
root mean squared error (RMSE)
二.导入库
import numpy as np
import pandas as pd
import time
import sys
import gc
import pickle
from itertools import product
from sklearn.preprocessing import LabelEncoder
import seaborn as sns
import matplotlib.pyplot as plt
from xgboost import XGBRegressor
from xgboost import plot_importance
pd.set_option('display.max_rows', 500)
pd.set_option('display.max_columns', 100)
def plot_features(booster, figsize):
fig, ax = plt.subplots(1,1,figsize=figsize)
return plot_importance(booster=booster, ax=ax)
三.读取数据
items = pd.read_csv('./competitive-data-science-predict-future-sales/items.csv')
shops = pd.read_csv('./competitive-data-science-predict-future-sales/shops.csv')
cats = pd.read_csv('./competitive-data-science-predict-future-sales/item_categories.csv')
train = pd.read_csv('./competitive-data-science-predict-future-sales/sales_train.csv')
# set index to ID to avoid droping it later
test = pd.read_csv('./competitive-data-science-predict-future-sales/test.csv').set_index('ID')# 设置下标
四.数据分析
异常值处理
plt.figure(figsize=(10,4))
plt.xlim(-100, 3000)
sns.boxplot(x=train_df.item_cnt_day)
plt.show()
plt.figure(figsize=(10,4))
plt.xlim(train.item_price.min(), train.item_price.max()*1.1)
sns.boxplot(x=train.item_price)
plt.show()
根据箱线图,去除离异值。并且item_price有负值,需要处理
train = train[train.item_price<100000]
train = train[train.item_cnt_day<1001]
负值处理使用相应具有同样数据性质的中位数所代替。
print(train[train.item_price<0])
date date_block_num shop_id item_id item_price item_cnt_day
484683 15.05.2013 4 32 2973 -1.0 1.0
商店/分类/物品预处理
几家商店是彼此重复的(根据其名称)。 需要处理。
# print(shops[shops.duplicated(subset='shop_name',keep=False)])# 查看重复值
print(shops)
shop_name shop_id
0 !Якутск Орджоникидзе, 56 фран 0
1 !Якутск ТЦ "Центральный" фран 1
2 Адыгея ТЦ "Мега" 2
3 Балашиха ТРК "Октябрь-Киномир" 3
4 Волжский ТЦ "Волга Молл" 4
5 Вологда ТРЦ "Мармелад" 5
6 Воронеж (Плехановская, 13) 6
7 Воронеж ТРЦ "Максимир" 7
8 Воронеж ТРЦ Сити-Парк "Град" 8
9 Выездная Торговля 9
10 Жуковский ул. Чкалова 39м? 10
11 Жуковский ул. Чкалова 39м² 11
12 Интернет-магазин ЧС 12
13 Казань ТЦ "Бехетле" 13
14 Казань ТЦ "ПаркХаус" II 14
15 Калуга ТРЦ "XXI век" 15
16 Коломна ТЦ "Рио" 16
17 Красноярск ТЦ "Взлетка Плаза" 17
18 Красноярск ТЦ "Июнь" 18
19 Курск ТЦ "Пушкинский" 19
20 Москва "Распродажа" 20
21 Москва МТРЦ "Афи Молл" 21
22 Москва Магазин С21 22
23 Москва ТК "Буденовский" (пав.А2) 23
24 Москва ТК "Буденовский" (пав.К7) 24
25 Москва ТРК "Атриум" 25
26 Москва ТЦ "Ареал" (Беляево) 26
27 Москва ТЦ "МЕГА Белая Дача II" 27
28 Москва ТЦ "МЕГА Теплый Стан" II 28
29 Москва ТЦ "Новый век" (Новокосино) 29
30 Москва ТЦ "Перловский" 30
31 Москва ТЦ "Семеновский" 31
32 Москва ТЦ "Серебряный Дом" 32
33 Мытищи ТРК "XL-3" 33
34 Н.Новгород ТРЦ "РИО" 34
35 Н.Новгород ТРЦ "Фантастика" 35
36 Новосибирск ТРЦ "Галерея Новосибирск" 36
37 Новосибирск ТЦ "Мега" 37
38 Омск ТЦ "Мега" 38
39 РостовНаДону ТРК "Мегацентр Горизонт" 39
40 РостовНаДону ТРК "Мегацентр Горизонт" Островной 40
41 РостовНаДону ТЦ "Мега" 41
42 СПб ТК "Невский Центр" 42
43 СПб ТК "Сенная" 43
44 Самара ТЦ "Мелодия" 44
45 Самара ТЦ "ПаркХаус" 45
46 Сергиев Посад ТЦ "7Я" 46
47 Сургут ТРЦ "Сити Молл" 47
48 Томск ТРЦ "Изумрудный Город" 48
49 Тюмень ТРЦ "Кристалл" 49
50 Тюмень ТЦ "Гудвин" 50
51 Тюмень ТЦ "Зеленый Берег" 51
52 Уфа ТК "Центральный" 52
53 Уфа ТЦ "Семья" 2 53
54 Химки ТЦ "Мега" 54
55 Цифровой склад 1С-Онлайн 55
56 Чехов ТРЦ "Карнавал" 56
57 Якутск Орджоникидзе, 56 57
58 Якутск ТЦ "Центральный" 58
59 Ярославль ТЦ "Альтаир" 59
# Якутск Орджоникидзе, 56
train.loc[train.shop_id == 0, 'shop_id'] = 57
test.loc[test.shop_id == 0, 'shop_id'] = 57
# Якутск ТЦ "Центральный"
train.loc[train.shop_id == 1, 'shop_id'] = 58
test.loc[test.shop_id == 1, 'shop_id'] = 58
# Жуковский ул. Чкалова 39м²
train.loc[train.shop_id == 10, 'shop_id'] = 11
test.loc[test.shop_id == 10, 'shop_id'] = 11
print(cats)
item_category_name item_category_id
0 PC - Гарнитуры/Наушники 0
1 Аксессуары - PS2 1
2 Аксессуары - PS3 2
3 Аксессуары - PS4 3
4 Аксессуары - PSP 4
5 Аксессуары - PSVita 5
6 Аксессуары - XBOX 360 6
7 Аксессуары - XBOX ONE 7
8 Билеты (Цифра) 8
9 Доставка товара 9
10 Игровые консоли - PS2 10
11 Игровые консоли - PS3 11
12 Игровые консоли - PS4 12
13 Игровые консоли - PSP 13
14 Игровые консоли - PSVita 14
15 Игровые консоли - XBOX 360 15
16 Игровые консоли - XBOX ONE 16
17 Игровые консоли - Прочие 17
18 Игры - PS2 18
19 Игры - PS3 19
20 Игры - PS4 20
21 Игры - PSP 21
22 Игры - PSVita 22
23 Игры - XBOX 360 23
24 Игры - XBOX ONE 24
25 Игры - Аксессуары для игр 25
26 Игры Android - Цифра 26
27 Игры MAC - Цифра 27
28 Игры PC - Дополнительные издания 28
29 Игры PC - Коллекционные издания 29
30 Игры PC - Стандартные издания 30
31 Игры PC - Цифра 31
32 Карты оплаты (Кино, Музыка, Игры) 32
33 Карты оплаты - Live! 33
34 Карты оплаты - Live! (Цифра) 34
35 Карты оплаты - PSN 35
36 Карты оплаты - Windows (Цифра) 36
37 Кино - Blu-Ray 37
38 Кино - Blu-Ray 3D 38
39 Кино - Blu-Ray 4K 39
40 Кино - DVD 40
41 Кино - Коллекционное 41
42 Книги - Артбуки, энциклопедии 42
43 Книги - Аудиокниги 43
44 Книги - Аудиокниги (Цифра) 44
45 Книги - Аудиокниги 1С 45
46 Книги - Бизнес литература 46
47 Книги - Комиксы, манга 47
48 Книги - Компьютерная литература 48
49 Книги - Методические материалы 1С 49
50 Книги - Открытки 50
51 Книги - Познавательная литература 51
52 Книги - Путеводители 52
53 Книги - Художественная литература 53
54 Книги - Цифра 54
55 Музыка - CD локального производства 55
56 Музыка - CD фирменного производства 56
57 Музыка - MP3 57
58 Музыка - Винил 58
59 Музыка - Музыкальное видео 59
60 Музыка - Подарочные издания 60
61 Подарки - Атрибутика 61
62 Подарки - Гаджеты, роботы, спорт 62
63 Подарки - Мягкие игрушки 63
64 Подарки - Настольные игры 64
65 Подарки - Настольные игры (компактные) 65
66 Подарки - Открытки, наклейки 66
67 Подарки - Развитие 67
68 Подарки - Сертификаты, услуги 68
69 Подарки - Сувениры 69
70 Подарки - Сувениры (в навеску) 70
71 Подарки - Сумки, Альбомы, Коврики д/мыши 71
72 Подарки - Фигурки 72
73 Программы - 1С:Предприятие 8 73
74 Программы - MAC (Цифра) 74
75 Программы - Для дома и офиса 75
76 Программы - Для дома и офиса (Цифра) 76
77 Программы - Обучающие 77
78 Программы - Обучающие (Цифра) 78
79 Служебные 79
80 Служебные - Билеты 80
81 Чистые носители (шпиль) 81
82 Чистые носители (штучные) 82
83 Элементы питания 83
根据上面两个数据集,要分析文字内容,获取有效信息,根据翻译,可以得知:
shop_name 开头是城市
item_category_name 代表类型和其子类型
生成城市特征
shops.loc[shops.shop_name == 'Сергиев Посад ТЦ "7Я"', 'shop_name'] = 'СергиевПосад ТЦ "7Я"'#该数据城市名有空格
shops['city'] = shops['shop_name'].map(lambda x: x.split(' ')[0])
print(shop['city'])
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 Химки
55 Цифровой
56 Чехов
57 Якутск
58 Якутск
59 Ярославль
去除城市的符号
shops.loc[shops.city=='!Якутск','city'] = 'Якутск'
shops['city_code'] = LabelEncoder().fit_transform(shops['city'])#编码
shops = shops[['shop_id','city_code']]#重新构建特征
构建商品分类特征
cats['subtype'] = cats['split'].map(lambda x: x[1].strip() if len(x) > 1 else x[0].strip())#取出小分类,若无则用大分类
print(cats['subtype'] )
[PC , Гарнитуры/Наушники]
1 [Аксессуары , PS2]
2 [Аксессуары , PS3]
3 [Аксессуары , PS4]
4 [Аксессуары , PSP]
5 [Аксессуары , PSVita]
6 [Аксессуары , XBOX 360]
7 [Аксессуары , XBOX ONE]
8 [Билеты (Цифра)]
9 [Доставка товара]
10 [Игровые консоли , PS2]
11 [Игровые консоли , PS3]
12 [Игровые консоли , PS4]
13 [Игровые консоли , PSP]
14 [Игровые консоли , PSVita]
15 [Игровые консоли , XBOX 360]
16 [Игровые консоли , XBOX ONE]
17 [Игровые консоли , Прочие]
18 [Игры , PS2]
19 [Игры , PS3]
20 [Игры , PS4]
21 [Игры , PSP]
22 [Игры , PSVita]
23 [Игры , XBOX 360]
24 [Игры , XBOX ONE]
25 [Игры , Аксессуары для игр]
26 [Игры Android , Цифра]
27 [Игры MAC , Цифра]
28 [Игры PC , Дополнительные издания]
29 [Игры PC , Коллекционные издания]
30 [Игры PC , Стандартные издания]
31 [Игры PC , Цифра]
32 [Карты оплаты (Кино, Музыка, Игры)]
33 [Карты оплаты , Live!]
34 [Карты оплаты , Live! (Цифра)]
35 [Карты оплаты , PSN]
36 [Карты оплаты , Windows (Цифра)]
37 [Кино , Blu, Ray]
38 [Кино , Blu, Ray 3D]
39 [Кино , Blu, Ray 4K]
40 [Кино , DVD]
41 [Кино , Коллекционное]
42 [Книги , Артбуки, энциклопедии]
43 [Книги , Аудиокниги]
44 [Книги , Аудиокниги (Цифра)]
45 [Книги , Аудиокниги 1С]
46 [Книги , Бизнес литература]
47 [Книги , Комиксы, манга]
48 [Книги , Компьютерная литература]
49 [Книги , Методические материалы 1С]
50 [Книги , Открытки]
51 [Книги , Познавательная литература]
52 [Книги , Путеводители]
53 [Книги , Художественная литература]
54 [Книги , Цифра]
55 [Музыка , CD локального производства]
56 [Музыка , CD фирменного производства]
57 [Музыка , MP3]
58 [Музыка , Винил]
59 [Музыка , Музыкальное видео]
60 [Музыка , Подарочные издания]
61 [Подарки , Атрибутика]
62 [Подарки , Гаджеты, роботы, спорт]
63 [Подарки , Мягкие игрушки]
64 [Подарки , Настольные игры]
65 [Подарки , Настольные игры (компактные)]
66 [Подарки , Открытки, наклейки]
67 [Подарки , Развитие]
68 [Подарки , Сертификаты, услуги]
69 [Подарки , Сувениры]
70 [Подарки , Сувениры (в навеску)]
71 [Подарки , Сумки, Альбомы, Коврики д/мыши]
72 [Подарки , Фигурки]
73 [Программы , 1С:Предприятие 8]
74 [Программы , MAC (Цифра)]
75 [Программы , Для дома и офиса]
76 [Программы , Для дома и офиса (Цифра)]
77 [Программы , Обучающие]
78 [Программы , Обучающие (Цифра)]
79 [Служебные]
80 [Служебные , Билеты]
81 [Чистые носители (шпиль)]
82 [Чистые носители (штучные)]
83 [Элементы питания]
发现类型之间存在空格,需要除去并编码。
cats['type'] = cats['split'].map(lambda x:x[0].strip())
cats['type_code'] = LabelEncoder().fit_transform(cats['type'])
cats['subtype'] = cats['split'].map(lambda x: x[1].strip() if len(x) > 1 else x[0].strip())
print(cats['subtype'] )
0 Гарнитуры/Наушники
1 PS2
2 PS3
3 PS4
4 PSP
5 PSVita
6 XBOX 360
7 XBOX ONE
8 Билеты (Цифра)
9 Доставка товара
10 PS2
11 PS3
12 PS4
13 PSP
14 PSVita
15 XBOX 360
16 XBOX ONE
17 Прочие
18 PS2
19 PS3
20 PS4
21 PSP
22 PSVita
23 XBOX 360
24 XBOX ONE
25 Аксессуары для игр
26 Цифра
27 Цифра
28 Дополнительные издания
29 Коллекционные издания
30 Стандартные издания
31 Цифра
32 Карты оплаты (Кино, Музыка, Игры)
33 Live!
34 Live! (Цифра)
35 PSN
36 Windows (Цифра)
37 Blu
38 Blu
39 Blu
40 DVD
41 Коллекционное
42 Артбуки, энциклопедии
43 Аудиокниги
44 Аудиокниги (Цифра)
45 Аудиокниги 1С
46 Бизнес литература
47 Комиксы, манга
48 Компьютерная литература
49 Методические материалы 1С
50 Открытки
51 Познавательная литература
52 Путеводители
53 Художественная литература
54 Цифра
55 CD локального производства
56 CD фирменного производства
57 MP3
58 Винил
59 Музыкальное видео
60 Подарочные издания
61 Атрибутика
62 Гаджеты, роботы, спорт
63 Мягкие игрушки
64 Настольные игры
65 Настольные игры (компактные)
66 Открытки, наклейки
67 Развитие
68 Сертификаты, услуги
69 Сувениры
70 Сувениры (в навеску)
71 Сумки, Альбомы, Коврики д/мыши
72 Фигурки
73 1С:Предприятие 8
74 MAC (Цифра)
75 Для дома и офиса
76 Для дома и офиса (Цифра)
77 Обучающие
78 Обучающие (Цифра)
79 Служебные
80 Билеты
81 Чистые носители (шпиль)
82 Чистые носители (штучные)
83 Элементы питания
Name: subtype, dtype: object
cats['subtype_code'] = LabelEncoder().fit_transform(cats['subtype'])
cats = cats[['item_category_id','type_code','subtype_code']]#重新构造数据集
# print(items['item_name'])
items.drop(['item_name'], axis=1, inplace=True)#认为商品名称没有作用
月份销售分析
print(len(list(set(test.item_id) - set(test.item_id).intersection(set(train.item_id)))), len(list(set(test.item_id))), len(test))
363 5100 214200
找到test 里面有363新的id,训练集的总的商品数5100 ,总共的商品-商店组合数214200
matrix = []
cols = ['date_block_num','shop_id','item_id']
for i in range(34):
sales = train[train.date_block_num == i]#分开各个月份的销售额,date_block_num与ID联动,用来区分每个月
matrix.append(np.array(list(product([i], sales.shop_id.unique(), sales.item_id.unique())),dtype='int16'))#product产生相应的商品-商店对
matrix = pd.DataFrame(np.vstack(matrix), columns=cols)#按行融合,构造与test相同的集合
matrix['date_block_num'] = matrix['date_block_num'].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)
date_block_num shop_id item_id
114910 0 2 19
117150 0 2 27
120623 0 2 28
118316 0 2 29
114602 0 2 32
... ... ... ...
10768788 33 59 22162
10768978 33 59 22163
10769644 33 59 22164
10771170 33 59 22166
10770465 33 59 22167
train['revenue'] = train['item_price'] * train['item_cnt_day']#计算利润
group = train.groupby(['date_block_num','shop_id','item_id']).agg({'item_cnt_day': ['sum']})#groupby聚合,agg统计计算
group.columns = ['item_cnt_month']
group.reset_index(inplace=True)#重设置下标索引
print(group)
date_block_num shop_id item_id item_cnt_month
0 0 2 27 1.0
1 0 2 33 1.0
2 0 2 317 1.0
3 0 2 438 1.0
4 0 2 471 2.0
... ... ... ... ...
1609118 33 59 22087 6.0
1609119 33 59 22088 2.0
1609120 33 59 22091 1.0
1609121 33 59 22100 1.0
1609122 33 59 22102 1.0
date_block_num可用来聚集训练集数据,使得训练集往测试集靠拢。用不了的数据特征可以来改变训练集的结构,往训练集靠拢;或者以人工定义的方式插入测试集的特征。
matrix = pd.merge(matrix, group, on=cols, how='left')#同时存在三个key的值才能合并
matrix['item_cnt_month'] = (matrix['item_cnt_month']
.fillna(0)
.clip(0,20) # 小于0的设为0,大于20的设为20,大于20的设为20,总共34
.astype(np.float16))
print(matrix)
date_block_num shop_id item_id item_cnt_month
0 0 2 19 0.0
1 0 2 27 1.0
2 0 2 28 0.0
3 0 2 29 0.0
4 0 2 32 0.0
... ... ... ... ...
10913799 33 59 22162 0.0
10913800 33 59 22163 0.0
10913801 33 59 22164 0.0
10913802 33 59 22166 0.0
10913803 33 59 22167 0.0
测试集分析
test['date_block_num'] = 34
test['date_block_num'] = test['date_block_num'].astype(np.int8)#给test集合增加date_block_num特征第34个月份
test['shop_id'] = test['shop_id'].astype(np.int8)
test['item_id'] = test['item_id'].astype(np.int16)
matrix = pd.concat([matrix, test], ignore_index=True, sort=False, keys=cols)#必须要三个相同的列才能作为合并
matrix.fillna(0, inplace=True) # 34 month
date_block_num shop_id item_id item_cnt_month
0 0 2 19 0.0
1 0 2 27 1.0
2 0 2 28 0.0
3 0 2 29 0.0
4 0 2 32 0.0
... ... ... ... ...
11127999 34 45 18454 0.0
11128000 34 45 16188 0.0
11128001 34 45 15757 0.0
11128002 34 45 19648 0.0
11128003 34 45 969 0.0
商店、商品、类别
同样地,需要将各个数据集合并起来,以及构造出来的特征。
matrix = pd.merge(matrix, shops, on=['shop_id'], how='left')
matrix = pd.merge(matrix, items, on=['item_id'], how='left')
matrix = pd.merge(matrix, cats, on=['item_category_id'], how='left')
matrix['city_code'] = matrix['city_code'].astype(np.int8)
matrix['item_category_id'] = matrix['item_category_id'].astype(np.int8)
matrix['type_code'] = matrix['type_code'].astype(np.int8)
matrix['subtype_code'] = matrix['subtype_code'].astype(np.int8)
目标值处理
均值化处理特征
对item_cnt_month进行操作
group = matrix.groupby(['date_block_num']).agg({'item_cnt_month': ['mean']})
group.columns = [ 'date_avg_item_cnt' ]
group.reset_index(inplace=True)
date_block_num date_avg_item_cnt
0 0 0.347168
1 1 0.324463
2 2 0.355469
3 3 0.275391
4 4 0.265137
5 5 0.283203
6 6 0.276855
7 7 0.316650
8 8 0.308105
9 9 0.290039
10 10 0.303223
11 11 0.411377
12 12 0.311279
13 13 0.307373
14 14 0.300049
15 15 0.255615
16 16 0.268799
17 17 0.273438
18 18 0.254639
19 19 0.290527
20 20 0.272217
21 21 0.280273
22 22 0.311279
23 23 0.444092
24 24 0.317383
25 25 0.278076
26 26 0.274414
27 27 0.243042
28 28 0.259521
29 29 0.264160
30 30 0.259277
31 31 0.288086
32 32 0.263672
33 33 0.258545
34 34 0.000000
matrix = pd.merge(matrix, group, on=['date_block_num'], how='left')
matrix['date_avg_item_cnt'] = matrix['date_avg_item_cnt'].astype(np.float16)
matrix = lag_feature(matrix, [1], 'date_avg_item_cnt')#增加一行date_num最后的平均值,为上个data_num的值
matrix.drop(['date_avg_item_cnt'], axis=1, inplace=True)#删除均值类,变成具有标注后的列
同理,继续按照不同的聚合来产生均值来增加特征。
group = matrix.groupby(['date_block_num', 'item_id']).agg({'item_cnt_month': ['mean']})
print(group)
group.columns = [ 'date_item_avg_item_cnt' ]
group.reset_index(inplace=True)
matrix = pd.merge(matrix, group, on=['date_block_num','item_id'], how='left')
matrix['date_item_avg_item_cnt'] = matrix['date_item_avg_item_cnt'].astype(np.float16)
matrix = lag_feature(matrix, [1,2,3,6,12], 'date_item_avg_item_cnt')
group = matrix.groupby(['date_block_num', 'item_id']).agg({'item_cnt_month': ['mean']})
group.columns = [ 'date_item_avg_item_cnt' ]
group.reset_index(inplace=True)
matrix = pd.merge(matrix, group, on=['date_block_num','item_id'], how='left')
matrix['date_item_avg_item_cnt'] = matrix['date_item_avg_item_cnt'].astype(np.float16)
matrix = lag_feature(matrix, [1,2,3,6,12], 'date_item_avg_item_cnt')
matrix.drop(['date_item_avg_item_cnt'], axis=1, inplace=True)
group = matrix.groupby(['date_block_num', 'shop_id']).agg({'item_cnt_month': ['mean']})
group.columns = [ 'date_shop_avg_item_cnt' ]
group.reset_index(inplace=True)
matrix = pd.merge(matrix, group, on=['date_block_num','shop_id'], how='left')
matrix['date_shop_avg_item_cnt'] = matrix['date_shop_avg_item_cnt'].astype(np.float16)
matrix = lag_feature(matrix, [1,2,3,6,12], 'date_shop_avg_item_cnt')
matrix.drop(['date_shop_avg_item_cnt'], axis=1, inplace=True)
group = matrix.groupby(['date_block_num', 'item_category_id']).agg({'item_cnt_month': ['mean']})
group.columns = [ 'date_cat_avg_item_cnt' ]
group.reset_index(inplace=True)
matrix = pd.merge(matrix, group, on=['date_block_num','item_category_id'], how='left')
matrix['date_cat_avg_item_cnt'] = matrix['date_cat_avg_item_cnt'].astype(np.float16)
matrix = lag_feature(matrix, [1], 'date_cat_avg_item_cnt')
matrix.drop(['date_cat_avg_item_cnt'], axis=1, inplace=True)
group = matrix.groupby(['date_block_num', 'shop_id', 'item_category_id']).agg({'item_cnt_month': ['mean']})
group.columns = ['date_shop_cat_avg_item_cnt']
group.reset_index(inplace=True)
matrix = pd.merge(matrix, group, on=['date_block_num', 'shop_id', 'item_category_id'], how='left')
matrix['date_shop_cat_avg_item_cnt'] = matrix['date_shop_cat_avg_item_cnt'].astype(np.float16)
matrix = lag_feature(matrix, [1], 'date_shop_cat_avg_item_cnt')
matrix.drop(['date_shop_cat_avg_item_cnt'], axis=1, inplace=True)
group = matrix.groupby(['date_block_num', 'shop_id', 'type_code']).agg({'item_cnt_month': ['mean']})
group.columns = ['date_shop_type_avg_item_cnt']
group.reset_index(inplace=True)
matrix = pd.merge(matrix, group, on=['date_block_num', 'shop_id', 'type_code'], how='left')
matrix['date_shop_type_avg_item_cnt'] = matrix['date_shop_type_avg_item_cnt'].astype(np.float16)
matrix = lag_feature(matrix, [1], 'date_shop_type_avg_item_cnt')
matrix.drop(['date_shop_type_avg_item_cnt'], axis=1, inplace=True)
group = matrix.groupby(['date_block_num', 'shop_id', 'subtype_code']).agg({'item_cnt_month': ['mean']})
group.columns = ['date_shop_subtype_avg_item_cnt']
group.reset_index(inplace=True)
matrix = pd.merge(matrix, group, on=['date_block_num', 'shop_id', 'subtype_code'], how='left')
matrix['date_shop_subtype_avg_item_cnt'] = matrix['date_shop_subtype_avg_item_cnt'].astype(np.float16)
matrix = lag_feature(matrix, [1], 'date_shop_subtype_avg_item_cnt')
matrix.drop(['date_shop_subtype_avg_item_cnt'], axis=1, inplace=True)
group = matrix.groupby(['date_block_num', 'city_code']).agg({'item_cnt_month': ['mean']})
group.columns = [ 'date_city_avg_item_cnt' ]
group.reset_index(inplace=True)
matrix = pd.merge(matrix, group, on=['date_block_num', 'city_code'], how='left')
matrix['date_city_avg_item_cnt'] = matrix['date_city_avg_item_cnt'].astype(np.float16)
matrix = lag_feature(matrix, [1], 'date_city_avg_item_cnt')
matrix.drop(['date_city_avg_item_cnt'], axis=1, inplace=True)
group = matrix.groupby(['date_block_num', 'item_id', 'city_code']).agg({'item_cnt_month': ['mean']})
group.columns = [ 'date_item_city_avg_item_cnt' ]
group.reset_index(inplace=True)
matrix = pd.merge(matrix, group, on=['date_block_num', 'item_id', 'city_code'], how='left')
matrix['date_item_city_avg_item_cnt'] = matrix['date_item_city_avg_item_cnt'].astype(np.float16)
matrix = lag_feature(matrix, [1], 'date_item_city_avg_item_cnt')
matrix.drop(['date_item_city_avg_item_cnt'], axis=1, inplace=True)
group = matrix.groupby(['date_block_num', 'type_code']).agg({'item_cnt_month': ['mean']})
group.columns = [ 'date_type_avg_item_cnt' ]
group.reset_index(inplace=True)
matrix = pd.merge(matrix, group, on=['date_block_num', 'type_code'], how='left')
matrix['date_type_avg_item_cnt'] = matrix['date_type_avg_item_cnt'].astype(np.float16)
matrix = lag_feature(matrix, [1], 'date_type_avg_item_cnt')
matrix.drop(['date_type_avg_item_cnt'], axis=1, inplace=True)
group = matrix.groupby(['date_block_num', 'subtype_code']).agg({'item_cnt_month': ['mean']})
group.columns = [ 'date_subtype_avg_item_cnt' ]
group.reset_index(inplace=True)
matrix = pd.merge(matrix, group, on=['date_block_num', 'subtype_code'], how='left')
matrix['date_subtype_avg_item_cnt'] = matrix['date_subtype_avg_item_cnt'].astype(np.float16)
matrix = lag_feature(matrix, [1], 'date_subtype_avg_item_cnt')
matrix.drop(['date_subtype_avg_item_cnt'], axis=1, inplace=True)
趋势化处理特征
同样的为增加特征:不同聚合类型的item_price
group = train.groupby(['item_id']).agg({'item_price': ['mean']})
group.columns = ['item_avg_item_price']
group.reset_index(inplace=True)
matrix = pd.merge(matrix, group, on=['item_id'], how='left')
matrix['item_avg_item_price'] = matrix['item_avg_item_price'].astype(np.float16)
group = train.groupby(['date_block_num','item_id']).agg({'item_price': ['mean']})
group.columns = ['date_item_avg_item_price']
group.reset_index(inplace=True)
matrix = pd.merge(matrix, group, on=['date_block_num','item_id'], how='left')
matrix['date_item_avg_item_price'] = matrix['date_item_avg_item_price'].astype(np.float16)
for i in lags:
matrix['delta_price_lag_'+str(i)] = \
(matrix['date_item_avg_item_price_lag_'+str(i)] - matrix['item_avg_item_price']) / matrix['item_avg_item_price']#(每个月商品均值价格-商品均值价格)/商品均值价格 每个月的商品变化趋势
def select_trend(row):
for i in lags:
if row['delta_price_lag_' + str(i)]:
return row['delta_price_lag_' + str(i)]
return 0
matrix['delta_price_lag'] = matrix.apply(select_trend, axis=1)
matrix['delta_price_lag'] = matrix['delta_price_lag'].astype(np.float16)
matrix['delta_price_lag'].fillna(0, inplace=True)
fetures_to_drop = ['item_avg_item_price', 'date_item_avg_item_price']
for i in lags:
fetures_to_drop += ['date_item_avg_item_price_lag_'+str(i)]
fetures_to_drop += ['delta_price_lag_'+str(i)]
matrix.drop(fetures_to_drop, axis=1, inplace=True)
上个月的利润趋势变化
group = train.groupby(['date_block_num','shop_id']).agg({'revenue': ['sum']})
group.columns = ['date_shop_revenue']
group.reset_index(inplace=True)
matrix = pd.merge(matrix, group, on=['date_block_num','shop_id'], how='left')
matrix['date_shop_revenue'] = matrix['date_shop_revenue'].astype(np.float32)
group = group.groupby(['shop_id']).agg({'date_shop_revenue': ['mean']})
group.columns = ['shop_avg_revenue']
group.reset_index(inplace=True)
matrix = pd.merge(matrix, group, on=['shop_id'], how='left')
matrix['shop_avg_revenue'] = matrix['shop_avg_revenue'].astype(np.float32)
matrix['delta_revenue'] = (matrix['date_shop_revenue'] - matrix['shop_avg_revenue']) / matrix['shop_avg_revenue']#月份的变化
matrix['delta_revenue'] = matrix['delta_revenue'].astype(np.float16)
matrix = lag_feature(matrix, [1], 'delta_revenue')
matrix.drop(['date_shop_revenue','shop_avg_revenue','delta_revenue'], axis=1, inplace=True)
特殊的特征
月份
matrix['month'] = matrix['date_block_num'] % 12
天数
days = pd.Series([31,28,31,30,31,30,31,31,30,31,30,31])
matrix['days'] = matrix['month'].map(days).astype(np.int8)
cache = {}
matrix['item_shop_last_sale'] = -1
matrix['item_shop_last_sale'] = matrix['item_shop_last_sale'].astype(np.int8)
for idx, row in matrix.iterrows():
key = str(row.item_id)+' '+str(row.shop_id)
if key not in cache:
if row.item_cnt_month!=0:
cache[key] = row.date_block_num
else:
last_date_block_num = cache[key]
matrix.at[idx, 'item_shop_last_sale'] = row.date_block_num - last_date_block_num
cache[key] = row.date_block_num
cache = {}
matrix['item_last_sale'] = -1
matrix['item_last_sale'] = matrix['item_last_sale'].astype(np.int8)
for idx, row in matrix.iterrows():
key = row.item_id
if key not in cache:
if row.item_cnt_month!=0:
cache[key] = row.date_block_num
else:
last_date_block_num = cache[key]
if row.date_block_num>last_date_block_num:
matrix.at[idx, 'item_last_sale'] = row.date_block_num - last_date_block_num
cache[key] = row.date_block_num
matrix['item_shop_first_sale'] = matrix['date_block_num'] - matrix.groupby(['item_id','shop_id'])['date_block_num'].transform('min')
matrix['item_first_sale'] = matrix['date_block_num'] - matrix.groupby('item_id')['date_block_num'].transform('min')
准备特征
缺省值填充
def fill_na(df):
for col in df.columns:
if ('_lag_' in col) & (df[col].isnull().any()):
if ('item_cnt' in col):
df[col].fillna(0, inplace=True)
return df
matrix = fill_na(matrix)
生成数据
matrix.to_pickle('data.pkl')
del matrix
del cache
del group
del items
del shops
del cats
del train
# leave test for submission
gc.collect();
五.搭建模型
data = pd.read_pickle('data.pkl')
data = data[[
'date_block_num',
'shop_id',
'item_id',
'item_cnt_month',
'city_code',
'item_category_id',
'type_code',
'subtype_code',
'item_cnt_month_lag_1',
'item_cnt_month_lag_2',
'item_cnt_month_lag_3',
'item_cnt_month_lag_6',
'item_cnt_month_lag_12',
'date_avg_item_cnt_lag_1',
'date_item_avg_item_cnt_lag_1',
'date_item_avg_item_cnt_lag_2',
'date_item_avg_item_cnt_lag_3',
'date_item_avg_item_cnt_lag_6',
'date_item_avg_item_cnt_lag_12',
'date_shop_avg_item_cnt_lag_1',
'date_shop_avg_item_cnt_lag_2',
'date_shop_avg_item_cnt_lag_3',
'date_shop_avg_item_cnt_lag_6',
'date_shop_avg_item_cnt_lag_12',
'date_cat_avg_item_cnt_lag_1',
'date_shop_cat_avg_item_cnt_lag_1',
#'date_shop_type_avg_item_cnt_lag_1',
#'date_shop_subtype_avg_item_cnt_lag_1',
'date_city_avg_item_cnt_lag_1',
'date_item_city_avg_item_cnt_lag_1',
#'date_type_avg_item_cnt_lag_1',
#'date_subtype_avg_item_cnt_lag_1',
'delta_price_lag',
'month',
'days',
'item_shop_last_sale',
'item_last_sale',
'item_shop_first_sale',
'item_first_sale',
]]#特征选择
X_train = data[data.date_block_num < 33].drop(['item_cnt_month'], axis=1)
Y_train = data[data.date_block_num < 33]['item_cnt_month']
X_valid = data[data.date_block_num == 33].drop(['item_cnt_month'], axis=1)
Y_valid = data[data.date_block_num == 33]['item_cnt_month']
X_test = data[data.date_block_num == 34].drop(['item_cnt_month'], axis=1)#数据切分
del data
gc.collect()
模型XGB
model = XGBRegressor(
max_depth=8,
n_estimators=1000,
min_child_weight=300,
colsample_bytree=0.8,
subsample=0.8,
eta=0.3,
seed=42)
model.fit(
X_train,
Y_train,
eval_metric="rmse",
eval_set=[(X_train, Y_train), (X_valid, Y_valid)],
verbose=True,
early_stopping_rounds = 10)
生成提交答案
Y_pred = model.predict(X_valid).clip(0, 20)
Y_test = model.predict(X_test).clip(0, 20)
submission = pd.DataFrame({
"ID": test.index,
"item_cnt_month": Y_test
})
submission.to_csv('xgb_submission.csv', index=False)