解密大数据大数据数据结构和算法分析

大型商场销售预测

2018-03-30  本文已影响51人  彭健平6点30
屏幕快照 2018-03-30 12.42.58.png 屏幕快照 2018-03-30 12.25.16.png 屏幕快照 2018-03-30 12.43.13.png

分为以下几个阶段探讨这个问题

%matplotlib inline
# 忽略警告提示
import warnings
warnings.filterwarnings('ignore')
import pandas as pd
import numpy as np

加载数据

train=pd.read_csv('Train_UWu5bXk.csv')
test=pd.read_csv('Test_u94Q5KV.csv')

探索数据

train.shape,test.shape
((8523, 12), (5681, 11))

训练数据有8523行,12列,测试数据有5681行,11列数据

#训练集和测试集合并到一起处理
all_data=pd.concat([train,test],ignore_index=True)
#查看数据统计描述信息
all_data.describe()
#查看前5列
all_data.head()
#查看数据类型
all_data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 14204 entries, 0 to 14203
Data columns (total 12 columns):
Item_Fat_Content             14204 non-null object
Item_Identifier              14204 non-null object
Item_MRP                     14204 non-null float64
Item_Outlet_Sales            8523 non-null float64
Item_Type                    14204 non-null object
Item_Visibility              14204 non-null float64
Item_Weight                  11765 non-null float64
Outlet_Establishment_Year    14204 non-null int64
Outlet_Identifier            14204 non-null object
Outlet_Location_Type         14204 non-null object
Outlet_Size                  10188 non-null object
Outlet_Type                  14204 non-null object
dtypes: float64(4), int64(1), object(7)
memory usage: 1.3+ MB

#查看缺失值情况
all_data.isnull().sum().sort_values(ascending=False).head()
Item_Outlet_Sales       5681
Outlet_Size             4016
Item_Weight             2439
Outlet_Type                0
Outlet_Location_Type       0
dtype: int64

清洗数据

1、处理缺失值:商品重量

由于每种商品的重量应该是相同的,所以用商品的重量均值补插缺失的值

item_avg_weighttt=all_data.groupby(['Item_Identifier'])['Item_Weight'].mean()
item_avg_weighttt['FDS02']
miss_bool = all_data ['Item_Weight'].isnull()
all_data.loc[miss_bool,'Item_Weight']=all_data.loc[miss_bool,'Item_Identifier'].apply(lambda x : item_avg_weighttt[x])

print (sum(all_data.Item_Weight.isnull()))
0

2、缺失值处理:商店大小

#用随机森林插补缺失值,用商店类型特征
print (all_data.Outlet_Size.value_counts())
all_data.Outlet_Type.value_counts()
Medium    4655
Small     3980
High      1553
Name: Outlet_Size, dtype: int64





Supermarket Type1    9294
Grocery Store        1805
Supermarket Type3    1559
Supermarket Type2    1546
Name: Outlet_Type, dtype: int64
def number_Outlet_Size(x):
    if x =='Medium':
        return 1
    elif x=='Small':
        return 2
    elif x=='High':
        return 3
    else:
        return x
def number_Outlet_Type(x):
    if x=='Supermarket Type1':
        return 1
    elif x=='Supermarket Type2':
        return 2
    elif x=='Supermarket Type3':
        return 3
    elif x=='Grocery Store':
        return 4
    else :
        return x
all_data['Outlet_Size']=all_data['Outlet_Size'].map(number_Outlet_Size)
all_data['Outlet_Type']=all_data['Outlet_Type'].map(number_Outlet_Type)
print (all_data.Outlet_Size.value_counts())
all_data.Outlet_Type.value_counts()
1.0    4655
2.0    3980
3.0    1553
Name: Outlet_Size, dtype: int64





1    9294
4    1805
3    1559
2    1546
Name: Outlet_Type, dtype: int64
x=all_data.loc[all_data['Outlet_Size'].notnull(),['Outlet_Type']]
y=all_data.loc[all_data['Outlet_Size'].notnull(),['Outlet_Size']]
z=all_data.loc[all_data['Outlet_Size'].isnull(),['Outlet_Type']]
import matplotlib.pyplot as plt
import seaborn as sns
sns.barplot(x='Outlet_Size',y='Item_Outlet_Sales',hue='Outlet_Type',data=all_data)
<matplotlib.axes._subplots.AxesSubplot at 0x11b559f60>
output_21_1.png
# #决策树
# #DecisionTreeClassifier
from sklearn.datasets import load_iris
from sklearn import tree
clf = tree.DecisionTreeClassifier()
clf = clf.fit(x,y)
pred=clf.predict(z)
all_data.loc[all_data['Outlet_Size'].isnull(),['Outlet_Size']]=pred
print ('处理后商店大小的分布:'\
       ,all_data['Outlet_Size'].value_counts())
all_data['Outlet_Size'].isnull().sum()
处理后商店大小的分布: 2.0    7996
1.0    4655
3.0    1553
Name: Outlet_Size, dtype: int64
0

sns.barplot(x='Outlet_Size',y='Item_Outlet_Sales',hue='Outlet_Type',data=all_data)
<matplotlib.axes._subplots.AxesSubplot at 0x11c052390>
output_24_1.png
all_data['Outlet_Size'].value_counts(normalize=True)
2.0    0.562940
1.0    0.327725
3.0    0.109335
Name: Outlet_Size, dtype: float64
#查看商店大小的平均销售额
all_data.pivot_table(values='Item_Outlet_Sales',index='Outlet_Size')
# #构建一个决策树来插补缺失值,特征用商店类型
# size_train=all_data[['Outlet_Size','Outlet_Type']]
# size_train=pd.get_dummies(size_train)
# known_size=size_train[size_train.Outlet_Size.notnull()].as_matrix()
# unknown_size=size_train[size_train.Outlet_Size.isnull()].as_matrix()
# y=known_size[:,0]
# x=known_size[:,1:]
# test_size=unknown_size[:,1::]

# #决策树
# #DecisionTreeClassifier
# from sklearn.datasets import load_iris
# from sklearn import tree
# clf = tree.DecisionTreeClassifier()
# clf = clf.fit(x, y)
# pred=clf.predict(test_size)
# all_data.loc[(all_data.Outlet_Size.isnull()),'Outlet_Size']=pred
# #检查
# all_data.Outlet_Size.isnull().value_counts()

特征工程和EDA

1、创建一个表示销售量的变量

查看商店类型的平均销售额

all_data.pivot_table(values='Item_Outlet_Sales',index='Outlet_Type')

显示它们之间有显着的差异[图片上传中...(output_93_1.png-76053b-1522385784103-0)]

Item_Visibility

将Item_Visibility中为0的商品调整为每个商店中的平均值

#visibility_avg=all_data.pivot_table(values='Item_Visibility',index='Item_Identifier')
visibility_avg=all_data.groupby(['Item_Identifier'])['Item_Visibility'].mean()
miss_bool=(all_data['Item_Visibility']==0)
print ("Item_Visibility值等于0的数量",sum(miss_bool))
all_data.loc[miss_bool,'Item_Visibility']=\
all_data.loc[miss_bool,'Item_Identifier'].apply(lambda x :visibility_avg[x])
print ("处理后Item_Visibility值等于0的数量",sum(all_data['Item_Visibility']==0))


Item_Visibility值等于0的数量 879
处理后Item_Visibility值等于0的数量 0
#计算每个商品的销售量
all_data['Item_Sales_Vol']=all_data.Item_Outlet_Sales/all_data.Item_MRP

2、创建一个新变量

利用Item_Identifier创建一个新变量

all_data['Item_Type_Combined']=all_data['Item_Identifier'].apply(lambda x :x[0:2])
#将她们重新命名
all_data['Item_Type_Combined']=all_data['Item_Type_Combined'].map({'FD':'Food',
                                                                  'NC':'Non-Consumable',
                                                                  'DR':'Drinks'})
all_data['Item_Type_Combined'].value_counts()
Food              10201
Non-Consumable     2686
Drinks             1317
Name: Item_Type_Combined, dtype: int64

修改Item_Fat_Content的类别

print ("打印原始类别:",all_data['Item_Fat_Content'].value_counts())
all_data['Item_Fat_Content']=all_data['Item_Fat_Content'].replace({'LF':'Low Fat',
                                                                  'reg':'Regular',
                                                                  'low fat':'Low Fat'})

print ("调整后的类别:",all_data['Item_Fat_Content'].value_counts())

打印原始类别: Low Fat    9185
Regular    5019
Name: Item_Fat_Content, dtype: int64
调整后的类别: Low Fat    9185
Regular    5019
Name: Item_Fat_Content, dtype: int64

3、对Item_Type进一步归类,创建新的商品分类变量

#将非消耗品标记为low_fat中的单独类别:
all_data.loc[all_data['Item_Type_Combined']=='Non-Consumable','Item_Fat_Content']='Non-edible '
all_data.Item_Fat_Content.value_counts()
Low Fat        6499
Regular        5019
Non-edible     2686
Name: Item_Fat_Content, dtype: int64
#商品的类别可以进一步归类
all_data.Item_Type.describe()
count                     14204
unique                       16
top       Fruits and Vegetables
freq                       2013
Name: Item_Type, dtype: object

第5步:确定商店的运营年限

#年份
all_data['Outlet_Years']=2013-all_data['Outlet_Establishment_Year']
all_data['Outlet_Years'].describe()
# #年份:
# 数据['Outlet_Years'] = 2013  - 数据['Outlet_Establishment_Year']
# 数据[ 'Outlet_Years']。描述()
count    14204.000000
mean        15.169319
std          8.371664
min          4.000000
25%          9.000000
50%         14.000000
75%         26.000000
max         28.000000
Name: Outlet_Years, dtype: float64

这显示运营年限为4-28岁的商店

all_data.Item_Fat_Content.value_counts()
Low Fat        6499
Regular        5019
Non-edible     2686
Name: Item_Fat_Content, dtype: int64

在步骤2中,我们看到有一些非消耗品,并且不应为他们指定脂肪含量。所以我们也可以为这种观察创建一个单独的类别

#Mark non-consumables as separate category in low_fat:
#将非消耗品标记为low_fat中的单独类别:
all_data.loc[all_data['Item_Type_Combined']==\
             'Non-Consumable','Item_Fat_Content']='Non-Edible'
all_data['Item_Fat_Content'].value_counts()
Low Fat       6499
Regular       5019
Non-Edible    2686
Name: Item_Fat_Content, dtype: int64

可视化探索各个变量

1、商店层面的4个因素:Outlet_Type,Outlet_Location_Type,Outlet_Years,Outlet_Size

sns.boxplot(x="Outlet_Type", y="Item_Outlet_Sales", data=all_data,palette='Set3',hue='Outlet_Type')

<matplotlib.axes._subplots.AxesSubplot at 0x11cb1fa20>

[图片上传失败...(image-9515d8-1522386628279)]

商店类型因素中,Grocery Store销量最低,type3平均销量最高

sns.boxplot(x="Outlet_Location_Type", y="Item_Outlet_Sales",hue='Outlet_Type', data=all_data,palette='Set3')

<matplotlib.axes._subplots.AxesSubplot at 0x11cd64748>
output_54_1.png

商店类型1有较完整的数据,但在地理位置的表现上,销量并无太大的区别

sns.boxplot(x="Outlet_Years", y="Item_Outlet_Sales", hue='Outlet_Type',data=all_data,palette='Set3')

<matplotlib.axes._subplots.AxesSubplot at 0x11cf99588>
output_56_1.png

商店类型1有较完整的数据,从成立的年数来看,似乎近10年内建立的商店的销售量表现高一点

sns.boxplot(x="Outlet_Size", y="Item_Outlet_Sales",hue='Outlet_Type', data=all_data,palette='Set3')

<matplotlib.axes._subplots.AxesSubplot at 0x11d253940>
output_58_1.png

商店类型1有较完整的数据,从商店大小的区分来看,并无差异

可视化的结果表明:

2、商品层面的因素:Item_Visibility,Item_Weight,Item_MRP,Item_Attribute,Item_Fat_Content,Item_Type(控制商店类型)

sns.lmplot(x='Item_Visibility',y='Item_Outlet_Sales',data=all_data,hue='Outlet_Type')

<seaborn.axisgrid.FacetGrid at 0x11d253c88>
output_62_1.png

商品展示的结果与假设接近,展示越大,平均销量越高

# 看看Item_Outlet_Sales的分布和用log1p处理后的形状
all_data['Item_Outlet_Sales_log']=np.log1p(all_data.Item_Outlet_Sales)
all_data.Item_Outlet_Sales.hist()

<matplotlib.axes._subplots.AxesSubplot at 0x11d89ce10>
output_64_1.png output_65_1.png
all_data.Item_Outlet_Sales_log.hist()
<matplotlib.axes._subplots.AxesSubplot at 0x11da2f828>

[图片上传失败...(image-41865-1522386628280)]

步骤6:分类变量进行编码

由于scikit-learn仅接受数值变量,因此我将所有类别的名义变量转换为数字类型.此外,我还希望将Outlet_Identifier作为变量。于是我创建了一个与Outlet_Identifier相同的新变量“Outlet”并对其进行了编码。Outlet_Identifier应保持原样,因为它将在提交文件中被要求。

建模和优化

已经处理好数据。开始制作预测模型,我会通过4个模型来预测,包括线性回归,决策树、随机森林、xgboost

现在开始制作一个基准模型,基准模型是不需要预测模型的模型,
将销售额预测为总体平均销售额

mean_sales=train['Item_Outlet_Sales'].mean()
#定义一个提交的数据框
base1=test[['Item_Identifier','Outlet_Identifier']]
base1['Item_Outlet_Sales']=mean_sales
#到出数据
base1.to_csv('alg_0.csv',index=False)

公开排行榜得分:1773.82513778.

#选择特征
data=all_data[['Item_Outlet_Sales_log','Outlet_Type','Item_Visibility','Outlet_Location_Type',
            'Item_MRP','Item_Type','Outlet_Years','Outlet_Size','Item_Type_Combined']]
#所有定性变量进行One-hot编码
print("one-hot之前",data.shape)
data=pd.get_dummies(data)
print ("one-hot之后",data.shape)
#将Item_Outlet_Sales进行log转化

one-hot之前 (14204, 9)
one-hot之后 (14204, 28)
#分训练和预测数据
train_one=data.loc[data.Item_Outlet_Sales_log.notnull(),:]
test_one=data.loc[data.Item_Outlet_Sales_log.isnull(),:]
train_one['Item_Outlet_Sales_log']=train_one['Item_Outlet_Sales_log'].astype(int)
print (train_one.shape,test_one.shape)
#特征和标签
x=train_one.as_matrix()[:,1:]
y=train_one.as_matrix()[:,0]
(8523, 28) (5681, 28)
test_one_aa=test_one.copy()
test_one_aa.drop(['Item_Outlet_Sales_log'],axis=1,inplace=True)
predictors=[x for x in train_one.columns if x not in 'Item_Outlet_Sales_log']
# #取出所有float64类型的特征
# numeric_cols=test_one_aa.columns[test_one_aa.dtypes=='float64']
# numeric_cols

线性回归模型

from sklearn.linear_model import LinearRegression  
regr = LinearRegression().fit(train_one[predictors],train_one['Item_Outlet_Sales_log'] )  

LinearRegression(copy_X=True, fit_intercept=True, n_jobs=1, normalize=False)
pred=regr.predict(test_one_aa)
coef1 = pd.Series(regr.coef_, predictors).sort_values()
coef1.plot(kind='bar', title='Model Coefficients')

#rmse(pred*x_test.Item_MRP,x_test.Item_Outlet_Sales)
print(pred)
output_78_1.png
#创建用于上传评分的测试结果 
base1=test[['Item_Identifier','Outlet_Identifier']]
base1['Item_Outlet_Sales']=np.expm1(pred)
#导出数据
base1.to_csv('alg_20.csv',index=False)

公开排行榜得分:1613

随机森林模型

from sklearn.ensemble import RandomForestRegressor
rf = RandomForestRegressor()
rf.fit(train_one[predictors],train_one['Item_Outlet_Sales_log'])
pred=rf.predict(test_one_aa)

coef1 = pd.Series(rf.feature_importances_,predictors).sort_values()
coef1.plot(kind='bar', title='Model Coefficients')

#创建用于上传评分的测试结果 
base1=test[['Item_Identifier','Outlet_Identifier']]
base1['Item_Outlet_Sales']=np.expm1(pred)
#导出数据
base1.to_csv('alg_3.csv',index=False)
output_78_1.png

公开排行榜得分:1653

支持向量机模型

#支持向量机Support Vector Machines
from sklearn.svm import SVC, LinearSVC
model = SVC()
model.fit(train_one[predictors],train_one['Item_Outlet_Sales_log'])
red=model.predict(test_one_aa)


print (model.support_)


#创建用于上传评分的测试结果 
base1=test[['Item_Identifier','Outlet_Identifier']]
base1['Item_Outlet_Sales']=np.expm1(pred)
#导出数据
base1.to_csv('alg_4.csv',index=False)
[ 178  255  405 ..., 7930 8039 8201]

公开排行榜得分:1653

决策树回归模型

from sklearn import tree
clf = tree.DecisionTreeRegressor()

clf.fit(train_one[predictors],train_one['Item_Outlet_Sales_log'])
red=clf.predict(test_one_aa)

coef1 = pd.Series(clf.feature_importances_,predictors).sort_values()
coef1.plot(kind='bar', title='Model Coefficients')

#创建用于上传评分的测试结果 
base1=test[['Item_Identifier','Outlet_Identifier']]
base1['Item_Outlet_Sales']=np.expm1(pred)
#导出数据
base1.to_csv('alg_5.csv',index=False)
output_88_0.png

公开排行榜得分:1653

from sklearn.cross_validation import train_test_split #2.7python可用

X_train, X_val, y_train, y_val = train_test_split(train_one[predictors], train_one['Item_Outlet_Sales_log'],test_size=0.9, random_state=42)

/Users/zhongyaode/anaconda/lib/python3.6/site-packages/sklearn/cross_validation.py:44: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.
  "This module will be removed in 0.20.", DeprecationWarning)
X_train, X_test, y_train, y_test = train_test_split(train_one[predictors], train_one['Item_Outlet_Sales_log'],test_size=0.2, random_state=42)
print(X_train.shape, X_test.shape)

(6818, 27) (1705, 27)

xgboost模型

import xgboost  as xgb
import os
import datetime
from datetime import datetime


#模型参数设置
xlf = xgb.XGBRegressor(max_depth=10, 
                        learning_rate=0.1, 
                        n_estimators=10, 
                        silent=True, 
                        objective='reg:linear', 
                        nthread=-1, 
                        gamma=0,
                        min_child_weight=1, 
                        max_delta_step=0, 
                        subsample=0.85, 
                        colsample_bytree=0.7, 
                        colsample_bylevel=1, 
                        reg_alpha=0, 
                        reg_lambda=1, 
                        scale_pos_weight=1, 
                        seed=1440, 
                        missing=None)

xlf.fit(X_train, y_train, eval_metric='rmse', verbose = True, eval_set = [(X_test, y_test)],early_stopping_rounds=100)

xgb_start=datetime.now()
xgb_end=datetime.now()
xgb.plot_importance(xlf)

# 计算 auc 分数、预测
# pre_data = xgboost.DMatrix(X_test, y_test)
# predict=bst.predict(test_one_aa)



predss = xlf.predict(test_one_aa)

#创建用于上传评分的测试结果 
base1=test[['Item_Identifier','Outlet_Identifier']]
base1['Item_Outlet_Sales']=np.expm1(predss)
#导出数据
base1.to_csv('alg_6.csv',index=False)
[0] validation_0-rmse:5.71174
Will train until validation_0-rmse hasn't improved in 100 rounds.
[1] validation_0-rmse:5.14637
[2] validation_0-rmse:4.64377
[3] validation_0-rmse:4.18711
[4] validation_0-rmse:3.7774
[5] validation_0-rmse:3.41
[6] validation_0-rmse:3.07942
[7] validation_0-rmse:2.78631
[8] validation_0-rmse:2.52036
[9] validation_0-rmse:2.28272
output_88_0.png

公开排行榜得分:2702
额得分这么低

以上是分析和建模过程,直接用Item_Outlet_Sales作为标签表现不好,可以试试别的方法

参考 一

参考 二

来一起学吧
上一篇 下一篇

猜你喜欢

热点阅读