淘宝婴儿用品销售数据分析之预测

之前对淘宝婴儿用品销售数据集做了基本的业务指标探索性分析。这里还是以这个数据集为例,进行后续的相关性探索。通过分析两个问题,熟悉机器学习算法建模流程。

两个预测问题:

  1. 根据孩子的信息(年龄、性别等)预测用户会购买什么样的商品;
  2. 根据父母的购买行为预测孩子的年龄。

分析流程:

  • 提出问题
  • 理解数据

包括:采集数据,导入数据,查看数据集信息,理解字段含义,查看是否有缺失值

  • 预处理/数据清洗

包括:选择子集、列名重命名、缺失值处理、类型转换、重复值处理、异常值处理、数据排序等

  • 特征提取

包括:对不同类型的数据做特征提取,如,数值型直接使用;分类型可能需要进行one-hot编码;字符串型可能需要做一些提取工作等

  • 特征选择/特征降维

特征选择的好坏,会直接影响模型的预测性能。这个过程涉及到特征工程的知识,相关学习可以参考以下两篇博文:

  1. 机器学习之特征工程
  2. 使用sklearn做特征工程
  • 建立模型

选择合适的机器学习算法,用训练集和算法得到机器学习模型,并用测试集来评估得到的模型。

字段含义:

  • user_id:用户id
  • auction_id:购买行为编号
  • cat_id:商品种类ID
  • cat1:商品属于哪个类别
  • property:商品属性
  • buy_mount:购买数量
  • day:购买时间
  • birthday:出生日期
  • gender:性别(0 男性;1 女性)

问题1:根据孩子的信息预测用户会购买什么样的商品

一、提出问题

问题一:根据孩子的信息(年龄、性别等)预测用户会购买什么样的商品。
首先确定特征和标签是什么,特征是年龄age和性别gender,标签是预测出商品类别cat1

二、理解数据

下载并导入数据后,查看数据集信息:

1
2
3
4
fileName1 = './(sample)sam_tianchi_mum_baby_trade_history.csv'
fileName2 = './(sample)sam_tianchi_mum_baby.csv'
trade_data = pd.read_csv(fileName1)
baby_data = pd.read_csv(fileName2)
1
trade_data.info()
1
baby_data.info()

三、数据预处理

  • 以婴儿信息表为主,合并两个数据集。
1
2
combined_data = pd.merge(trade_data,baby_data,on='user_id',how='right')
combined_data.head()

查看合并后的数据集信息:

1
combined_data.info()
  • 处理重复数据

发现有3个user_id重复出现,删除:

1
2
combined_data.drop_duplicates(subset='user_id',inplace=True)
combined_data.info()
  • 处理缺失值

发现property商品属性这个字段有2条缺失。可以看到每个商品的属性都有多个,以逗号连接。这里采取删除的处理方式:

1
2
combined_data.dropna(inplace=True)
combined_data.info()

现在所有字段都不为空,总共951条数据。

  • 数据类型转换

将购买商品日期和婴儿出生日期转换为时间格式:

1
2
combined_data['day'] = combined_data['day'].astype('str')
combined_data['birthday'] = combined_data['birthday'].astype('str')
1
2
combined_data['day'] = pd.to_datetime(combined_data['day'],format='%Y-%m-%d')
combined_data['birthday'] = pd.to_datetime(combined_data['birthday'],format='%Y-%m-%d')
  • 处理异常值

性别gender字段除了0(男),1(女)之外,还存在2的情况,这应该是用户不愿意透露婴儿的性别信息,这部分值只有26个,故删除这部分数据:

1
combined_data['gender'].value_counts()
1
2
combined_data = combined_data[combined_data['gender']<2]
combined_data['gender'].value_counts()

到目前为止,总共925条数据。

四、特征提取

  • 计算婴儿年龄,并进行分段,增加age列和age_group

增加年龄列,年龄的计算通过购买日期的年份减去出生日期的年份得到:

1
2
combined_data['age'] = (combined_data['day'].dt.year - combined_data['birthday'].dt.year)
combined_data['age'].describe()

发现年龄有异常大的值28岁,将其删去:

1
2
combined_data = combined_data[combined_data['age'] < 28]
combined_data['age'].describe()

这里只有一个异常大值,所以最终剩下924条数据。然后删除销售时间day字段和出生日期birthday字段:

1
combined_data.drop(['day','birthday'],axis=1,inplace=True)

将年龄进行分组,总共分为5个年龄组,增加年龄组列:

1
2
3
4
5
6
7
bin_labels = ['G0','G1','G2','G3','G4'] 
#年龄段标签
bin_edges = [-3,0,1,3,6,12]
combined_data['age_group'] = pd.cut(combined_data['age'], bin_edges, labels=bin_labels)
combined_data['age_group'] = combined_data['age_group'].astype('str')
# 确认所有年龄都被分到正确区间
combined_data['age_group'].isnull().sum()

对年龄组列进行one-hot编码,并将创建的虚拟变量添加到数据集:

1
2
ageDf = pd.get_dummies(combined_data['age_group'])
combined_data = pd.concat([combined_data,ageDf],axis=1)

查看数据集是否得到预期效果:

1
combined_data.head(3)

如下图所示:
pred_1

五、特征选择

该问题是根据孩子的信息(年龄、性别等)预测用户会购买什么样的商品。
那么选择的特征为:

  • 特征:年龄区间age_group或者年龄age,性别gender
  • 标签:商品种类cat1

特征以选择年龄区间age_group和性别gender为例:

1
2
3
# 特征选择
train_features_2 = pd.concat([combined_data['gender'],ageDf],axis=1)
train_labels_2 = combined_data['cat1']

六、构建模型

  • 拆分数据集为训练集和测试集

训练集用于训练模型,测试集用于验证模型:

1
2
3
4
from sklearn.model_selection import train_test_split
train_X_2, test_X_2, train_y_2, test_y_2 = train_test_split(train_features_2,train_labels_2,test_size=.2)
#输出数据集大小
print ('原始数据集特征:',train_features_2.shape, '训练数据集特征:',train_X_2.shape , '测试数据集特征:',test_X_2.shape)print ('原始数据集标签:',train_labels_2.shape, '训练数据集标签:',train_y_2.shape , '测试数据集标签:',test_y_2.shape)

打印结果为:
pred_5

  • 建立模型,训练和验证

这里选择梯度增强算法:

1
2
3
4
# 梯度增强 
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import accuracy_score
model = GradientBoostingClassifier()
  • 训练模型,并用测试集验证:
1
2
3
model.fit(train_X_2, train_y_2)
test_pred = model.predict(test_X_2)
accuracy_score(test_pred,test_y_2)

问题2:根据父母的购买行为预测孩子的年龄

首先确定特征和标签是什么,现在能非常确定的是预测标签是年龄组age_group;而对于特征则是不确定有哪些。

与问题1的相同之处

理解数据、数据预处理步骤与问题1相同。

与问题1的不同之处

  1. 在第四步特征提取中,增添了对商品属性property的处理,因为商品属性也是购买行为的特征之一。

商品属性property字段是字符型,每个商品具有多个大类别属性以及大类别属性下的具体属性。每对属性数字,表示大类别属性下的具体属性,即大类别属性 : 具体属性;每对属性数字用;隔开,如下图红框中所示。

pred_2

处理方式

  • 先按分号划分字符串,得到每个商品具有的所有属性对;
  • 再按冒号划分每个属性对,保留每个商品含有的具体属性。

首先按属性值将property拆分成多行,并将新的列命名为new_property:

1
2
3
new_prop = combined_data['property'].str.split(';',expand=True).stack().reset_index(level=1,drop=True).rename('new_property')
combined_data = combined_data.drop('property',axis=1).join(new_prop)
combined_data.head()

如图所示:
pred_3

然后,再拆分每个属性对,提取出其中的具体属性;为此定义一个函数:

1
2
3
4
5
6
# 定义函数,提取具体属性
def getTitle(property):
str1=property.split( ':' )[1]
#strip() 方法用于移除字符串头尾指定的字符(默认为空格)
str2=str1.strip()
return str2

调用函数,提取具体属性,并将提取后的特征连接到原数据集上:

1
2
3
4
5
#存放提取后的特征
propDf = pd.DataFrame()
#map函数:对Series每个数据应用自定义的函数计算
propDf['property'] = combined_data['new_property'].map(getTitle)
combined_data = pd.concat([combined_data,propDf],axis=1)

对数据集进行去重处理,同一个商品若具有多条相同商品属性则删除:

1
combined_data.drop_duplicates(['cat1','property'],inplace=True)

最终得到2690条数据,提取具体属性之后的结果:
pred_4

  1. 第五步中特征选择不同

这里是将所有的字段都作为特征输入,包括提取后的property字段,而标签为年龄组:

1
2
train_features_1 = combined_data[['user_id','cat_id','gender','auction_id','cat1','property']]
train_labels_1 = combined_data['age_group']

总结

机器学习建模分析的流程与业务指标分析的流程大同小异。特别注意的是机器学习的模型效果很大程度取决于特征工程,特征工程做得好,即便模型简单,参数不优,也能获得很好的性能。本文主要以呈现机器学习算法分析流程为目标,特征工程工作做得相对简单,得到的模型准确率并不高,待后续深入学习这块知识后再作改进。

-------------完-------------