营销响应预测模型是针对营销活动展开的,通常在做会员营销之前,通过营销响应预测模型分析找到可能响应活动的会员特征以及整体响应的用户比例、数量和可能带来的销售额。这对会员营销之前的有关策略制定的辅助价值非常明显。
营销响应预测模型的实施主要采用分类算法,常用的算法包括:逻辑回归、支持向量机、随机森林等。
本次分析的输入源数据来源自《python数据分析与数据化运营》第五章的order.xlsx。其中,sheet1为训练集数据,sheet2为测试集数据。数据概况如下:
~特征变量数:13
~数据记录数:sheet1中共39999条,sheet2中共8843条
~是否有na值:有
~是否有异常值:无
以下是源数据的13个特征变量:
~age:年龄,整数型变量
~total_pageviews:总页面浏览量,整数型变量
~edu:教育程度,分类型变量,值域[1,10]
~edu_age:受教育年限,整数型变量。
~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]
~目标变量response:1代表有用户响应,0代表用户未响应。
import time
import numpy as np
import pandas as pd
from sklearn.preprocessing import OneHotEncoder
from sklearn.model_selection import cross_val_score,StratifiedKFold
from sklearn.feature_selection import SelectPercentile,f_classif
from sklearn.ensemble import AdaBoostClassifier
from sklearn.pipeline import Pipeline
from sklearn.metrics import accuracy_score
基本状态的审查包括:基本状态查看、缺失值审查、类样本均衡审查等。通过定义不同的功能函数,来实现以上功能。
(1)基本状态查看
def set_summary(data):
print('Data overview')
print('数据形状是:',data.shape[0],'*',data.shape[1])
print('-'*30)
print(data.head())
print('Data describe:\n')
print(data.describe())
print('Data dtype:\n')
print(data.dtypes)
(2)缺失值审查
#2.查找数据中的缺失值,即na值
def na_summary(data):
#查看缺失列
na_cols=data.isnull().any(axis=0)
print('Na columns:')
print(na_cols)
print('-'*30)
print('每一列的非na值个数:')
print(data.count())
print('-'*30)
na_rows=data.isnull().any(axis=1)
print('具有缺失值的行总数:')
print(na_rows.sum())
print('-'*30)
(3)类样本均衡审查
#3.类均衡审查,查看每个类的样本量分布
def labels_summary(data):
'''查看每个类的样本分布量
:params data:DataFrame
:return:None
'''
print('样本数据分布:')
print(data['value_level'].groupby(data['response']).count())
print('-'*60)
通过数据审查,已了解了数据的基本状态,需要对数据进行一定的预处理,使之更加适合模型的建立。数据的预处理包括了函数变量类型转换和缺失值处理,二值化的标志转换,获得最佳模型参数。
(1)函数变量类型转换
在本分析中,需要将分类和顺序变量数据类型转换为整数型。
def tran_type(data):
'''
转换目标列的数据为特定的数据类型
:params data:DataFrame
:return:类型转换后的DataFrame
'''
var_list={
'edu':'int32',
'user_level':'int32',
'industry':'int32',
'value_level':'int32',
'act_level':'int32',
'sex':'int32',
'region':'int32'}
for var,value in var_list.items():
data[var]=data[var].astype(value)
print('Data types:')
print(data.dtypes)
print('-'*60)
return data
(2)Na值替换,针对不同的列,将缺失值替换为指定数值。在这里采用根据每一列自动指定缺失值的方法。
def na_replace(data):
'''
将数据集中的Na用自定义方法替换
:params data:DataFrame
:return:na值替换后的DataFrame
'''
na_rules={
'age':data['age'].mean(),
'total_pageviews':data['total_pageviews'].mean(),
'edu':data['edu'].median(),
'edu_ages':data['edu_ages'].median(),
'user_level':data['user_level'].median(),
'industry':data['industry'].median(),
'act_level':data['act_level'].median(),
'sex':data['sex'].median(),
'red_money':data['red_money'].mean(),
'region':data['region'].median()
}
data=data.fillna(na_rules)
print('检查Na值的存在:')
print(data.isnull().any(axis=0))
print('-'*30)
return data
(3)二值化的标志转换
二值化的标志转换,主要用于将分类变量和顺序变量转换为二值化的标志0和1的值域的变量。在转换过程中,由于涉及训练集和测试集两种状态,训练集需要使用转换对象的fit方法训练,然后使用训练好的模型分别对训练集和测试集做转换,因此需要划分不同阶段。
def symbol_change(data,enc_object=None,train=True):
'''
将分类和顺序变量转化为二值化的标志变量
:params data:DataFrame
:enc_object:sklearn的标志转换对象,训练阶段设置为None,预测阶段使用从训练阶段获取的转换结果
:train:是否为训练阶段的判断状态,如果是训练阶段,则为True,否则为False
:return:转换后的DataFrame、标志转换对象(如果是训练阶段)
'''
col_change=['edu','user_level','industry','value_level','act_level','sex','region']
col_origion=['age','total_pageviews','edu_ages','blue_money','red_money','work_hours']
data_change=data[col_change]
data_origion=data[col_origion].values
if train==True:
enc=OneHotEncoder()
enc.fit(data_change)
data_change_new=enc.transform(data_change).toarray()
new_matrix=np.hstack((data_change_new,data_origion))
return new_matrix,enc
else:
data_change_new=enc_object.transform(data_change).toarray()
new_matrix=np.hstack((data_change_new,data_origion))
return new_matrix
(4)获得最佳模型参数
用于按照指定的参数训练方法得到每次交叉检验不同评估指标的分类模型结果。交叉检验是做模型效果评估的最佳方法,分类模型中一般都会使用该方法。在该模型中,自定义几种不同的检验指标,然后对模型的不同参数做训练并得到不同评估指标的结果,通过每次的输出结果以及运行时间的评估,从中找到比较合适的参数。
在该模型中,采用了sklearn中的Pipeline模块,Pipeline为一个复合评估器,用于将多个具有上下逻辑环节的过程连接起来形成一个复合对象。
Pipeline中只有一个参数:step,该参数是一个名称和模型对象组成的元祖的列表。在这个列表中,不同的元祖之间具有明确的先后关系,并且最后一个元祖一定是一个评估算法。
当使用Pipe对象时,可应用的方法包括fit、predict、fit_predict
、fit_transform等,当对其使用predict(以及包含predict的其他方法,比如predict_proba、fit_predict等)会自动调用最后一个评估器的predict方法做预测。
def get_best_model(X,y):
'''
结合交叉验证得到不同参数下的分类模型结果
X:输入变量X(特征变量)
y:输出变量y(目标变量)
return 特征选择模型对象
'''
transform=SelectPercentile(f_classif,percentile=50)
model_adaboost=AdaBoostClassifier()
#建立由特征选择和分类模型构成的“管道对象”
model_pipe=Pipeline(steps=[('ANOVA',transform),('model_adaboost',model_adaboost)])
#设置交叉检验次数
cv=StratifiedKFold(5)
#设置模型参数列表
n_estimators=[20,50,80,100]
score_methods=['accuracy','f1','precision','recall','roc_auc']
mean_list=[]
std_list=[]
for parameter in n_estimators:
t1=time.time()
score_list=[]
print('set parameter:%s' %parameter)
for score_method in score_methods:
model_pipe.set_params(model_adaboost__n_estimators=parameter)
score_tmp=cross_val_score(model_pipe,X,y,scoring=score_method,cv=cv)
score_list.append(score_tmp)
score_matrix=pd.DataFrame(np.array(score_list),index=score_methods)
score_mean=score_matrix.mean(axis=1).rename('mean')
score_std=score_matrix.std(axis=1).rename('std')
#将原始详细数据和均值、标准差合并
score_pd=pd.concat([score_matrix,score_mean,score_std],axis=1)
mean_list.append(score_mean)
std_list.append(score_std)
print(score_pd.round(2))
print('-'*60)
t2=time.time()
print('time:',str(t2-t1))
print(mean_list)
print(std_list)
mean_matrix=np.array(mean_list).T
std_matrix=np.array(std_list).T
print(mean_matrix)
print(std_list)
mean_pd=pd.DataFrame(mean_matrix,index=score_methods,columns=n_estimators)
std_pd=pd.DataFrame(std_matrix,index=score_methods,columns=n_estimators)
print('Mean values for each parameter:')
print(mean_pd)
print('std values for each parameter:')
print(std_pd)
print('-'*60)
return transform
在该函数的实现中,先要做数据降维,目的是降低数据计算量。这里使用的SelectPercentile方法结合f_classif评估器选择特征最明显的50%数量的特征。然后采用AdaBoostClassifier方法建立分类模型对象。
(1)数据导入
data=pd.read_excel('order.xlsx',sheetname=0)
X=data.drop('response',axis=1)
y=data['response']
(2)基本状态查看
set_summary(data)
na_summary(data)
labels_summary(data)
(3)数据预处理
X_t1=na_replace(X)
X_t2=tran_type(X_t1)
X_new,enc=symbol_change(X_t2,enc_object=None,train=True)
通过数据预处理后的数据基本状态如下:
检查Na值的存在:
age False
total_pageviews False
edu False
edu_ages False
user_level False
industry False
value_level False
act_level False
sex False
blue_money False
red_money False
work_hours False
region False
dtype:bool
Data types:
age float64
total_pageviews float64
edu int32
edu_ages float64
user_level int32
industry int32
value_level int32
act_level int32
sex int32
blue_money int64
red_money float64
work_hours int64
region int32
dtype: object
(4)分类模型训练
transform=get_best_model(X_new,y)
#应用特征选择对象选择要参与建模的特征变量
transform.fit(X_new,y)
#获得具有显著性特征的特征变量
X_final=transform.transform(X_new)
#从打印参数均值和标准差信息中确定参数并建立分类模型对象
final_model=AdaBoostClassifier(n_estimators=100)
#训练对象
final_model.fit(X_final,y)
(5)新数据集预测
#新数据集预处理
new_data=pd.read_excel('order.xlsx',sheetname=1)
final_response=new_data['final_response']
new_X=new_data.drop('final_response',axis=1)
set_summary(new_X)
na_summary(new_X)
new_X_t1=na_replace(new_X)
new_X_t2=tran_type(new_X_t1)
new_X_t3=symbol_change(new_X_t2,enc_object=enc,train=False)
new_X_final=transform.transform(new_X_t3)
#输出预测值及预测概率
predict_labels=pd.DataFrame(final_model.predict(new_X_final),columns=['labels'])
predict_labels_pro=pd.DataFrame(final_model.predict_proba(new_X_final),columns=['pro1','pro2'])
predict_pd=pd.concat([new_data,predict_labels,predict_labels_pro],axis=1)
print('predict info:')
print(predict_pd.head())
print('-'*30)
#将预测结果与实际结果做比较
accuracy_score=accuracy_score(final_response,predict_labels)
print('final accuracy:')
print(accuracy_score)
将预测结果与实际结果进行了对比:
final accuracy:
0.862490105168
输出结果为0.862490105168,该结果与跟做交叉检验时非常一致,说明该模型具有较强的鲁棒性。
注:以上分析案例摘自宋天龙所著《Python数据分析与数据化运营》