CDA营销项目

《产品营销模型之建置及预测》赛题说明

最终成绩:0.8225

背景:
A公司有一款在线服务的P产品,公司的营销通路是100%的网络媒介。A公司希望提供30天免费的P产品后,期望顾客能正式签约购买P产品之服务。但A公司发现‚每隔1~2天便对数以万计的顾客发送电子营销文宣,不但购买率低下,甚至造成诸多客诉。同时,客户之预期获利是以人工经验评估之,没有量化或模型工具之协助,不晓得到底应该使用广告全投放还是机器学习模型来做投放?

目标:
A公司希望发掘用户购买产品的行为习惯,建立产品精准营销模型,对有意向的客户进行精准营销,增加收入,减少开支。

评分标准:
我们通过混淆矩阵(Confusion matrix)来评价分类模型的准确率。准确率越高,说明正确预测出响应营销效果越好。

提交结果:
选手以训练数据为基础,建立产品营销模型,并上传一个测试结果的档案results.csv,文档中只有两个字段,分别是客户ID以及预测客户是否会购买(Predicted_Results)的结果。

字段说明
在这里插入图片描述

代码

"""准备工具"""
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
#查看缺失值
import missingno as msno
#时间模块
import time
from sklearn.model_selection import train_test_split,GridSearchCV
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report,roc_auc_score,accuracy_score
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier 
import xgboost
from sklearn.naive_bayes import GaussianNB
import gc
import warnings
warnings.filterwarnings('ignore')
#解决显示中文错误
import matplotlib as mpl
mpl.rcParams['font.sans-serif'] = [u'SimHei']
mpl.rcParams['axes.unicode_minus'] = False
pd.set_option('display.max_columns',None)
pd.set_option('display.max_rows',None)
"""写入文件"""
train_data = pd.read_csv('df_training.csv',na_values='?',names=['客户ID','产品使用分数','用户地区','性别','年龄','使用累计时间','点数余额','产品服务使用量','是否为使用信用卡付月费','是否为活跃用户','估计薪资','购买与否'],header=0)

ID不是特征不使用,购买与否为要预测的标签,查看缺失值,判断是否为离散型数据

train_data.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6000 entries, 0 to 5999
Data columns (total 12 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   客户ID         6000 non-null   int64  
 1   产品使用分数       4165 non-null   float64
 2   用户地区         4167 non-null   object 
 3   性别           4156 non-null   object 
 4   年龄           4179 non-null   float64
 5   使用累计时间       4207 non-null   float64
 6   点数余额         4232 non-null   float64
 7   产品服务使用量      4188 non-null   float64
 8   是否为使用信用卡付月费  4118 non-null   float64
 9   是否为活跃用户      4181 non-null   float64
 10  估计薪资         4161 non-null   float64
 11  购买与否         6000 non-null   int64  
dtypes: float64(8), int64(2), object(2)
memory usage: 562.6+ KB

这里认为nunique值大于15为连续性变量,反之则为离散变量

con = []  #收集连续型数据
dis = []  #收集离散型数据
for col in train_data.columns[1:-1]:
    print(col)
    print(train_data[col].value_counts())
    print('缺失值比例',train_data[col].isnull().sum()/train_data.shape[0])
    if train_data[col].nunique() > 15:
        print('连续型')
        con.append(col)
    else:
        print('离散型')
        dis.append(col)
    print()

先处理离散型数据,统一将空值填充为一个不影响的值,独热后将该列的独热列删除

data = train_data.copy()
data = data.fillna('999')  #用xxx代表空值,便于独热后区分
hot_col = ['area','sex','time','service','monthly','active']  #独热时的名字

#将每一列进行独热编码,删除掉‘999’的独热列
area_hot = pd.get_dummies(data[dis[0]],prefix=hot_col[0])
area_hot = area_hot.drop('area_999',axis=1) #删
sex_hot = pd.get_dummies(data[dis[1]],prefix=hot_col[1])
sex_hot = sex_hot.drop('sex_999',axis=1) #删
time_hot = pd.get_dummies(data[dis[2]],prefix=hot_col[2])
time_hot = time_hot.drop('time_999',axis=1) #删
service_hot = pd.get_dummies(data[dis[3]],prefix=hot_col[3])
service_hot = service_hot.drop('service_999',axis=1) #删
monthly_hot = pd.get_dummies(data[dis[4]],prefix=hot_col[4])
monthly_hot = monthly_hot.drop('monthly_999',axis=1) #删
active_hot = pd.get_dummies(data[dis[5]],prefix=hot_col[5])
active_hot = active_hot.drop('active_999',axis=1) #删

数据格式转化,字符数据数值化

for col in dis[2:]:
    data[col] = data[col].astype('float32')
for i in con:
    data[i] = data[i].astype('float32')

# 可以使用LabelEncoder
data['用户地区'] = data['用户地区'].replace('Taipei',0)
data['用户地区'] = data['用户地区'].replace('Taichung',1)
data['用户地区'] = data['用户地区'].replace('Tainan',2)
data['用户地区'] = data['用户地区'].astype('float32')
data['性别'] = data['性别'].replace('Male',0)
data['性别'] = data['性别'].replace('Female',1)
data['性别'] = data['性别'].astype('float32')

对离散型数据进行缺失值填充,利用xgboost,用其他所有列对该列进行预测

for i in range(len(dis)):
    start = time.time()
    print('当前特征列为:%s'%(dis[i]))
    print('第一步:构造特征与标签--------------------')
    res = data[dis[i]]
    y_train = res[res!=999]
    
    #将其余的独热编码后的列和连续型数据组合在一起来做训练
    com = [area_hot,sex_hot,time_hot,service_hot,monthly_hot,active_hot,data[con],data[dis[i]]]
    df = pd.concat(com,axis=1)
    #分为训练测试集
    x_train = df[df[dis[i]]!=999].iloc[:,:-1]
    x_test = df[df[dis[i]]==999].iloc[:,:-1]
    
    print('第二步:建模与预测填充--------------------')
    xgb = xgboost.XGBClassifier()
    xgb.fit(x_train,y_train)
    y_res = xgb.predict(x_test)
    data[dis[i]][data[dis[i]]==999] = y_res
    end = time.time()
    print('运行时间:%s'%(end-start))
    print()
for i in range(len(con)):
    start = time.time()
    print('当前特征列为:%s'%(con[i]))
    print('第一步:构造特征与标签--------------------')
    res = data[con[i]]
    y_train = res[res!=999]

    com = [area_hot,sex_hot,time_hot,service_hot,monthly_hot,active_hot,data[con]]
    df = pd.concat(com,axis=1)
    x_train = df[df[con[i]]!=999].drop(con[i],axis=1)
    x_test = df[df[con[i]]==999].drop(con[i],axis=1)
    
    print('第二步:建模与预测填充--------------------')
    xgb = xgboost.XGBClassifier()
    xgb.fit(x_train,y_train)
    res_y = xgb.predict(x_test)
    data[con[i]][data[con[i]]==999] = res_y
    end = time.time()
    print('运行时间:%s'%(end-start))

上面一步将离散型数据填充完成,接下来用离散型数据填充连续性数据

for i in range(len(con)):
    start = time.time()
    print('当前特征列为:%s'%(con[i]))
    print('第一步:构造特征与标签--------------------')
    res = data[con[i]]
    y_train = res[res!=999]

    com = [area_hot,sex_hot,time_hot,service_hot,monthly_hot,active_hot,data[con]]
    df = pd.concat(com,axis=1)
    x_train = df[df[con[i]]!=999].drop(con[i],axis=1)
    x_test = df[df[con[i]]==999].drop(con[i],axis=1)
    
    print('第二步:建模与预测填充--------------------')
    xgb = xgboost.XGBClassifier()
    xgb.fit(x_train,y_train)
    res_y = xgb.predict(x_test)
    data[con[i]][data[con[i]]==999] = res_y
    end = time.time()
    print('运行时间:%s'%(end-start))

利用matplotlib,seaborn,pyechars可视化工具,查看各特征的分布,查看各特征与标签之前的关系,查看特征与特征之间的关系

"""查看各特征是否有异常值"""
for i in range(len(data.columns)):
    plt.figure(figsize=(10,58))
    plt.subplot(len(data.columns),1,i+1)
    sns.boxplot(data[data.columns[i]])

年龄有异常值,对年龄大于60的数据进行单独查看,图中显示异常的部分只占总体的 3.9%,从数据上看,年龄符合人类正常寿命
"""离散型特征与标签"""
for i in range(len(dis)):
    sns.catplot(x=dis[i],y='购买与否',data=data,kind='bar',aspect=2.5)

用户地区,性别,使用累计时间,产品服务用量,是否为活跃用户对标签有比较明显的区分
"""连续型数据分箱查看与标签之间的关系"""
for i in range(len(con)):
    name = '%s_10'%(con[i])
    data[name] = pd.cut(data[con[i]],bins=10)
    t = data.groupby(name,as_index=False)[['购买与否']].count().groupby(name,as_index=False)[['购买与否']].sum()
    print(t)    
    sns.catplot(x=name,y='购买与否',data=t,kind='point',aspect=2.5)
    plt.xticks(rotation=30)
    plt.show()
   
产品使用分数,年龄对标签有比较明显的区分
"""查看相关系数"""
plt.figure(figsize=(16,16))
sns.heatmap(data.iloc[:,:-4].corr(),annot=True)

使用XGBOOST建模预测

"""选择比较好的特征"""
data_t = data[['用户地区','性别','使用累计时间','产品服务使用量','是否为活跃用户','产品使用分数','年龄','购买与否']]

"""划分数据集"""
x_train,x_test,y_train,y_test = train_test_split(data_t.iloc[:,:-1],data_t.iloc[:,-1],test_size=0.2,random_state=42)

"""利用网格搜索搜索超参数"""
xgb = xgboost.XGBClassifier()
gs = GridSearchCV(xgb,{'max_depth':[2,4,6,7,9,10],'n_estimators':[50,100,150,200],'learning_rate':[1,0.1,0.01,0.001],'n_jobs':[10]},cv=10,refit=True)
gs.fit(x_train,y_train)
pre = gs.predict(x_test)
print(gc.best_params_)
print(accuracy_score(y_test,g))

{'learning_rate': 0.1, 'max_depth': 2, 'n_estimators': 150, 'n_jobs': 10}
0.8225
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Weidong He.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值