1. 案例背景
通过数据预测下一次营销活动时,响应活动的会员名单和具体概率。
数据:
order.xlsx表: sheet1为训练集,sheet2为预测集
特征变量数:13
数据条数:训练集39999条,预测集8843条
NA值:有
异常值:有
13个特征变量:
age:年龄(整数型变量)
total_pageviews:总页面浏览量(整数型变量)
edu:教育程度(分类型变量,值域[1,10])
edu_ages:受教育年限(整数型变量)
user_level:用户等级(分类变量,值域[1,7])
industry:用户企业划分(分类型变量,值域[1,15])
value_level:用户价值度分类(分类型变量,值域[1,6])
act_level:用户活跃度分类(分类型变量,值域[1,5])
sex:性别(0或1)
blue_money:蓝券金额(整数型变量)
red_money:红券金额(整数型变量)
work_hours:工作时间长度(整数型变量)
region:地区(分类型变量,值域[1,41])
2. 案例技术
数据预处理:二值化标志转换OneHotEncoder、基于方差分析的特征选择的数据降维SelectPercentile结合f_classif
数据建模:管道方法Pipe、交叉检验cross_val_score配合StratifiedKFold和自定义得分计算方法、集成分类算法AdaBoostClassifier
主要用的库:time、Numpy、Pandas、Sklearn
技术应用重点:通过管道方法将多个数据处理环节结合起来,形成处理管道对象,针对对象做交叉检验得到不同参数下的检验结果
3. 案例过程
步骤1:导入库
""" OneHotEncoder:将分类变量和顺序变量转换为二值化标志变量 StratifiedKFold,cross_val_score:交叉验证,前者用来将数据分为训练集和测试集;后者用来交叉检验。 StratifiedkFold 能结合样本标签做数据集分割,而不是完全的随机选择和分割 SelectPercentile,f_classif:前者用来做特征选择的数量控制,后者用来确定特征选择的得分计算标准 AdaBoostClassifier:集成算法,用来做分类模型训练 Pipeline:将不同的环节结合起来(本案例中,将特征选择和集成算法结合起来形成一个”管道对象“,然后针对该对象 训练不同参数下交叉检验的结果) """ import time import numpy as np import pandas as pd from sklearn.preprocessing import OneHotEncoder # 导入二值化标志转化库 from sklearn.model_selection import StratifiedKFold, cross_val_score # 导入交叉检验算法 from sklearn.feature_selection import SelectPercentile, f_classif # 导入特征选择方法 from sklearn.ensemble import AdaBoostClassifier # 导入集成算法 from sklearn.pipeline import Pipeline # 导入Pipeline库 from sklearn.metrics import accuracy_score # 准确率指标
步骤2:数据基本审查(基本状态审查,缺失值审查,类样本均衡审查)
set_summary():
1. 在format函数中,df的形状由于记录训练集 X 的特征数量,因此最后减 1。
2. head():显示指定数量(N)的前N条数据。
3. describe():显示数据最小值,均值,标准差,25%,50%,75%分位数,最大值。
4. dtypes():显示所有列的数据类型。(为后面的数据类型转换做准备)
na_summary():
1. df.isnull().any():判断指定轴是否含有缺失值。
2. df.count():统计每个特征非NA记录数。
3. na_lines返回一个包含True/False的列表,使用sum()方法统计缺失值的数量。
def set_summary(df): """ 查看数据 :return: """ print('Data Overview') print('Records: {0} Dimension{1}'.format(df.shape[0], (df.shape[1]-1))) # 打印数据集 X 的形状 print('-' * 30) print(df.head(2)) # 打印前两条数据 print('-' * 30) print('Data DESC') print(df.describe()) # 打印数据描述信息 print('Data Dtypes') print(df.dtypes) # 打印数据类型 print('-' * 60) def na_summary(df): """ 查看数据的缺失 :param df: :return: """ na_cols = df.isnull().any(axis=0) # 每一列是否有缺失值 print('NA Cols:') print(na_cols) # 查看具有缺失值的列 print('valid records for each Cols:') print(df.count()) # 每一列非NA的记录数 na_lines = df.isnull().any(axis=1) # 每一行是否有缺失值 print('Total number of NA lines is: {0}'.format(na_lines.sum())) # 查看缺失值的行总记录数 print('-' * 30) def label_summary(df): """ 查看每个类的样本量分布 :param df: :return: """ print('Label sample count:') print(df['value_level'].groupby(df['respone']).count()) # 以response为分类汇总维度对value_level列计数统计 print('-' * 60)
步骤3:数据预处理
type_con():转换目标列的数据为特定数据类型
1. items():以列表返回可遍历的(键, 值) 元组数组。
2. DataFrame.astype():将特定的列数据类型转换为另一种数据类型。不仅如此,还可以使用Python字典一次更改多个列类型。字典中的键与列名相对应,字典中的值与希望列属于的新数据类型相对应。
def type_con(df): """ 转换目标列的数据为特定数据类型 :param df: :return: """ val_list = {'edu': 'int32', 'user_level': 'int32', 'industry': 'int32', 'value_level': 'int32', 'act_level': 'int32', 'sex': 'int32', 'region': 'int32'} # 字典:定义要转换的列及其数据类型(key:列名,velue:新数据类型) for var, type in val_list.items(): df[var] = df[var].astype(type) print('Data Dtypes:') print(df.dtypes) return df
na_replce():将NA值替换
def na_replace(df): """ 将NA值使用自定义方法得替换 :param df: :return: """ na_rules = {'age': df['age'].mean(), 'total_pageviews': df['total_pageviews'].mean(), 'edu': df['edu'].median(), # median():中值 'edu_ages': df['edu_ages'].median(), 'user_level': df['user_level'].median(), 'industry': df['industry'].median(), 'act_level': df['act_level'].median(), 'sex': df['sex'].median(), 'red_money': df['red_money'].median(), 'region': df['region'].median() } df = df.fillna(na_rules) # 使用指定方法填充缺失值 print('Check NA exists:') print(df.isnull().any().sum()) # 查看是否还有缺失值 return df
symbol_con():将分类和顺序变量转换为二值化的标志变量
该函数做二值化的标志转换,主要用于将分类变量和顺序变量转换为二值化变量,值域为 0 和 1。
在转换过程中,由于涉及训练集(及测试集)和预测集两种状态,训练集需要使用转换对象 fit 方法训练,然后使用训练好的模型分别对训练集和预测集做转换,因此需要区分不同阶段。
具体实现过程:
定义需转换的列形成数据框 df_con
定义无需转换的列形成数据矩阵(数据框的值,通过values获得) df_org
df_org 是 Numpy矩阵而非 Pandas 数据框,接下来使用 Numpy 方法做数据矩阵合并,原因是 OneHotEncoder 转换后的对象也是 Numpy 矩阵
接下来根据train的状态做判断:
为True时,用OneHotEncoder方法建立转换对象enc,然后用fit方法做训练,接着用transform方法做转换 (这里fit和transform方法分开操作是enc对象要在fit之后传给预测集使用) 最后将未转换的数据与转换后的数据合并。
为False时,直接用训练阶段获得的对象enc做transform,然后将结果合并。
def symbol_con(df, enc_object=None, train=True): """ 将分类和顺序变量转换为二值化的标志变量 :param df: :param enc_object: :param train: :return: """ convert_cols = ['edu', 'user_level', 'industry', 'value_level', 'act_level', 'sex', 'region'] # 选择要做标志转换的列(教育程度,用户等级,用户企业划分,用户价制度划分,用户活跃度划分,性别,地区) df_con = df[convert_cols] # 选择要做标志转换的数据 df_org = df[['age', 'total_pageviews', 'edu_ages', 'blue_money', 'red_money', 'work_hours']].values # 设置不做标志转换的列(df.column.values:以array形式返回指定column的所有取值) if train == True: # 如果数据处于训练阶段 enc = OneHotEncoder() # 建立标志转换模型对象 enc.fit(df_con) # 训练模型 df_con_new = enc.transform(df_con).toarray() # 转换数据并输出为数组格式 new_matrix = np.hstack(df_con_new, df_con) # 将未转换的数据与转换后的数据合并 return new_matrix, enc else: df_con_new = enc_object.transform(df_con).toarray() # 使用训练阶段获得转换对象转换数据并输出数组格式 new_matrix = np.hstack((df_con_new, df_org)) # 将未转换的数据与转换的数据合并 return new_matrix
1. enc_transform:Sklearn的标志转换对象,该对象只有应用fit方法后才形成,因此训练阶段为空;在预测集应用阶段,直接使用该参数传入训练集时的对象即可。
2. train:判断是否为训练阶段,训练阶段为True,预测阶段为False。根据不同的状态判断是否需要做 fit,并返回不同的参数对象。
get_best_model():获得最佳模型参数
在该函数中,通过交叉检验的方法,自定义几种不同的检验指标,从中找到比较合适的参数。