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 - 商品类别的名称

其他说明:

  • 编程语言:Python
  • 编译工具:jupyter notebook
  • 涉及到的库:pandas,numpy,matplotlib,sklearn,seaborn,datetime,dateutil
  • Kaggle链接:https://www.kaggle.com/c/competitive-data-science-predict-future-sales

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-----------

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-----------

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进行建模预测,可能使用时间序列算法效果会更好。

你可能感兴趣的:(Kaggle商店销售预测)