Kaggle商店销售预测

项目说明:

在这个项目中,我们需要根据不同商店的各商品在2013/01-2015/10中的日常销售数据来预测这些商店的各商品在2015年11月的销售数据(是根据日销售量来预测月销售量)。

项目评估要求

  1. 将均方根误差(RMSE)作为评估提交的度量指标;
  2. 真实销售量被限制在[0,20]范围以内。

Kaggle一共提供了5个文件,具体信息如下:

image.png

数据字段说明:

  • ID - 表示测试集中的(Shop,Item)元组的Id
  • shop_id - 商店的唯一标识符
  • item_id - 商品的唯一标识符
  • item_category_id - 商品类别的唯一标识符
  • item_cnt_day - 销售的产品数量。
  • item_price - 商品的当前价格
  • date - 日期格式为dd / mm / yyyy
  • date_block_num - 一个连续的月号,用于方便。2013年1月是0,- 2013年2月是1,...,2015年10月是33
  • item_name - 商品名称
  • shop_name - 商店名称
  • item_category_name - 商品类别的名称

其他说明:

1.0 数据概览

#设置jupyter可以多行输出
from IPython.core.interactiveshell import InteractiveShell 
InteractiveShell.ast_node_interactivity = 'all' #默认为'last'

#jupyter绘图魔术方法
%matplotlib notebook

#导入相关库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from dateutil.parser import parse
import warnings
warnings.filterwarnings("ignore")
import os
print(os.listdir())

output:

['.ipynb_checkpoints', 'items.csv', 'item_categories.csv', 'Predict Future Sales-Copy1.ipynb', 'Predict Future Sales.ipynb', 'predict sale.csv', 'predict sale_1.1.csv', 'predict sale_1.csv', 'predict sale_2.csv', 'sales_train_v2.csv', 'sample_submission.csv', 'shops.csv', 'test.csv']
item_categories = pd.read_csv('item_categories.csv')
items = pd.read_csv('items.csv')
shop = pd.read_csv('shops.csv')
train = pd.read_csv('sales_train_v2.csv')
test = pd.read_csv('test.csv')
def eda(data):
    print("----------Top-5- Record----------")
    print(data.head(3))
    print("-----------Information-----------")
    print(data.info(null_counts=True))
    print("----------Shape of Data----------")
    print(data.shape)
    print("---------------------------------")
eda(train)
eda(test)

output:

----------Top-5- Record----------
         date  date_block_num  shop_id  item_id  item_price  item_cnt_day
0  02.01.2013               0       59    22154       999.0           1.0
1  03.01.2013               0       25     2552       899.0           1.0
2  05.01.2013               0       25     2552       899.0          -1.0
-----------Information-----------
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2935849 entries, 0 to 2935848
Data columns (total 6 columns):
date              2935849 non-null object
date_block_num    2935849 non-null int64
shop_id           2935849 non-null int64
item_id           2935849 non-null int64
item_price        2935849 non-null float64
item_cnt_day      2935849 non-null float64
dtypes: float64(2), int64(3), object(1)
memory usage: 134.4+ MB
None
----------Shape of Data----------
(2935849, 6)
---------------------------------
----------Top-5- Record----------
   ID  shop_id  item_id
0   0        5     5037
1   1        5     5320
2   2        5     5233
-----------Information-----------
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 214200 entries, 0 to 214199
Data columns (total 3 columns):
ID         214200 non-null int64
shop_id    214200 non-null int64
item_id    214200 non-null int64
dtypes: int64(3)
memory usage: 4.9 MB
None
----------Shape of Data----------
(214200, 3)
---------------------------------
items[:3]
item_categories[:3]
shop[:3]

output:


item_name   item_id item_category_id
0   ! ВО ВЛАСТИ НАВАЖДЕНИЯ (ПЛАСТ.) D   0   40
1   !ABBYY FineReader 12 Professional Edition Full...   1   76
2   ***В ЛУЧАХ СЛАВЫ (UNV) D    2   40

item_category_name  item_category_id
0   PC - Гарнитуры/Наушники 0
1   Аксессуары - PS2    1
2   Аксессуары - PS3    2

shop_name   shop_id
0   !Якутск Орджоникидзе, 56 фран   0
1   !Якутск ТЦ "Центральный" фран   1
2   Адыгея ТЦ "Мега"    2

可以看到数据集和训练集都没有缺失数据,所以这里我们主要是对异常值和重复数据进行处理。

2.0 数据处理

由于训练集中,date_block_num,shop_id,item_id都是表示类别的,所以这里只需要对item_price, item_cnt_day进行异常值分析处理。

sns.pairplot(train[['item_price','item_cnt_day']])

output:

image.png

可以看到item_price有一个数值特别大,大于300000,明显游离在外,可以认为这是一个异常值,另外item_cnt_day也有两个值明显偏大,可以一并去掉。

#去除异常值
train = train[train['item_cnt_day']<1000]
train = train[(train.item_price>0) & (train.item_price<300000)]
train.shape

output:

(2935845, 6)

下面利用.drop_duplicates()方法将训练集中的重复数据去除。

train = train.drop_duplicates()
train.shape

output:

(2935839, 6)

现在我们再来观察下训练集和测试集:

train[:3]
test[:3]

output:


date    date_block_num  shop_id item_id item_price  item_cnt_day
0   02.01.2013  0   59  22154   999.0   1.0
1   03.01.2013  0   25  2552    899.0   1.0
2   05.01.2013  0   25  2552    899.0   -1.0

ID  shop_id item_id
0   0   5   5037
1   1   5   5320
2   2   5   5233

我们需要预测的是各商店的各个商品在11月的月销售量,而训练集中的数据是各商店各商品在前面33个月中的日常销售数据,所以我们需要对训练集进行聚合运算,得到各商店各商品每月的销售量。

p_df = train.pivot_table(index=['shop_id','item_id'],columns='date_block_num',values='item_cnt_day',aggfunc='sum').fillna(0.0).reset_index()

然后再增加一个feature,就是将p_df与items数据集合并,增加items_category_id列。

train_cleaned_df = p_df.merge(items[['item_id','item_category_id']],how='inner')
train_cleaned_df[:3]
image.png

其实到这里我们的训练集就处理完了,我们得到了各商店各商品在不同月份的销售量,现在我们对测试集也做这样的处理。

test = test.merge(train_cleaned_df,how='left')
test = test.fillna(0.0)
test
image.png

3.0 建模预测

现在我们就可以直接建模了,我们生成回归器,然后将训练集中的(0-32)33个月的销售数据作为X_train,将第34个月的数据作为X_test。

那么当我们对test进行预测时,我们就是将拟合好的回归器对(1-32)33个月的数据进行预测。

X_train = train_cleaned_df.iloc[:,(train_cleaned_df.columns != 33)].values
y_train = train_cleaned_df.iloc[:,train_cleaned_df.columns==33].values

X_test = test.iloc[:, (test.columns != 'ID') & (test.columns != 0)].values
from sklearn.model_selection import GridSearchCV, cross_val_score
from xgboost import XGBRegressor

xgbrfr = XGBRegressor()
xgbrfr.fit(X_train,y_train)
y_pred = xgbrfr.predict(X_test)
y_pred = list(map(lambda x: min(20,max(x,0)), list(y_pred)))
sub_df = pd.DataFrame({'ID':test.ID,'item_cnt_month': y_pred })
sub_df.to_csv('predict sale_1.1.csv',index=False)

然后将结果提交到Kaggle上。

image.png

成绩还是有一定上升空间的,我们可以对模型进行网格搜索调参,另外我们并对items,shop,item_categories这三个补充文件进行处理,如果进一步研究的话,应该也是能挖掘一些信息的,增加一些新的Feature,我们是使用的是xgboost,我感觉feature还是有点偏少。其实这个数据集非常适合使用时间序列算法AR,MA,ARMA,ARIMA进行建模预测,可能使用时间序列算法效果会更好。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,454评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,553评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,921评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,648评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,770评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,950评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,090评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,817评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,275评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,592评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,724评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,409评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,052评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,815评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,043评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,503评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,627评论 2 350