对银行客户复购频率的进行三分类预测。根据客户信息(包括基础客户画像信息、产品购买行为信息以及第三方客户画像补充信息)预测客户复购行为,对客户信息数据进行预处理,通过特征选择和特征工程不断构建新特征,提高模型性能,通过随机森林建模预测客户复购频率,并根据客户平均价值(低频1、中频3、高频5),在独立样本上检验预测准确性(加权准确性),识别黏性客户,分析其需求,并向他们推送新产品,进行客户关系管理
比赛用到的数据都是脱敏的,代码分享在下面:
# loading packages
#载入工具包
import os
import pandas as pd #数据处理和分析工具包
import numpy as np #科学运算包
# plotting packages
%matplotlib inline
#类似Matlab的绘图工具包
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimSun', 'Times New Roman'] # 汉字字体集
plt.rcParams['font.size'] = 10 # 字体大小
plt.rcParams['axes.unicode_minus'] = False
import matplotlib.cm as cm
import matplotlib.colors as clrs
import seaborn as sns
from sklearn import metrics
from sklearn.preprocessing import LabelEncoder
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.model_selection import cross_val_score
# load data
x1train = pd.read_csv('X1_train.csv')
x2train = pd.read_csv('X2_train.csv')
x3train = pd.read_csv('X3_train.csv')
ytrain=pd.read_csv('y_train.csv')
xtrain=[x1train,x2train,x3train]
x1test = pd.read_csv('X1_test.csv')
x2test = pd.read_csv('X2_test.csv')
x3test = pd.read_csv('X3_test.csv')
xtest=[x1test,x2test,x3test]
# check the data
for i in xtrain:
print(i.dtypes)
print("Size of the dataset (row, col): ", i.shape) #显示数据行,列数
print("\nFirst 5 rows\n", i.head(n=5)) #查看前五行
print("--------------------------------")
for i in xtest:
print(i.dtypes)
print("Size of the dataset (row, col): ", i.shape) #显示数据行,列数
print("\nFirst 5 rows\n", i.head(n=5)) #查看前五行
print("--------------------------------")
#train data processing
newB1=[]
for i in x2train['B1']:
newB1.append(int(i[0:4]))
x2train['B1']=newB1
print(x2train.head())
for i in xtrain:
for h in i.columns:
if h != '客户编号':
if i[h].dtypes==object:
i[h]=pd.factorize(i[h])[0]
else:
if np.var(i[h])<=1:
xe=i.drop([h],axis=1,inplace=True)
#print(i[h].isnull().sum())
se=i.dropna(axis=1,how='all',inplace=True)
re=i.fillna(i.mean(),inplace=True)
print("--------------------------------")
print(i.head(n=100))
for i in xtrain:
for h in i.columns:
print(i[h].isnull().sum())
mv_x2train=x2train.groupby('客户编号',as_index=False)[x2train.columns].mean()
print(mv_x2train)
freq=x2train['客户编号'].value_counts()
print(freq)
mv_x2train['freq']=freq
print(mv_x2train)
final=pd.merge(ytrain,mv_x2train,how='left')
pe=final.fillna(0,inplace=True)
print(final.head())
print('jjjjjjjjnbbbbbbbzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz')
X1train = x1train.drop(['客户编号','A11','A12','A19'],1)#,'A5','A9','A11','A12','A19'
X2train = final.drop(['客户编号','复购频率','B8','B10','B13','B14','B15','B16','B19'],1)#,'B8','B10','B13','B14','B15','B16','B19'
X3train = x3train.drop(['客户编号','C2','C5','C8','C10','C13','C29','C31','C33','C37','C42','C48','C49'],1)#,'C2','C5','C8','C10','C13','C29','C31','C33','C37','C42','C48','C49'
Xtrain_1=[X1train,X2train,X3train]
X_train=pd.concat(Xtrain_1,axis=1)
print(X_train.columns)
Xtrain=[X1train,X2train,X3train,X_train]
Ytrain=ytrain.drop('客户编号',1)
for i in Xtrain:
cm = np.corrcoef(i.values.T)
hm = sns.heatmap(cm, cbar=True, square=False, fmt='.3f', annot=True, annot_kws={'size':1}, yticklabels=i.columns, xticklabels=i.columns)
plt.show()
#test data processing
newB2=[]
for i in x2test['B1']:
newB2.append(int(i[0:4]))
x2test['B1']=newB2
print(x2test.head())
for i in xtest:
for h in i.columns:
if h != '客户编号':
if i[h].dtypes==object:
i[h]=pd.factorize(i[h])[0]
#print(i[h].isnull().sum())
setest=i.dropna(axis=1,how='all',inplace=True)
retest=i.fillna(i.mean(),inplace=True)
print("--------------------------------")
print(i.head(n=100))
for i in xtest:
for h in i.columns:
print(i[h].isnull().sum())
mv_x2test=x2test.groupby('客户编号',as_index=False)[x2test.columns].mean()
print(mv_x2test)
freqtest=x2test['客户编号'].value_counts()
print(freq)
mv_x2test['freq']=freqtest
print(mv_x2test)
finaltest=pd.merge(x1test['客户编号'],mv_x2test,how='left')
petest=finaltest.fillna(0,inplace=True)
print(finaltest.head())
print('jjjjjjjjnbbbbbbbzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz')
X1test = x1test.drop(['客户编号'],1)#,'A5','A9','A11','A12','A19'
X2test = finaltest.drop(['客户编号'],1)#,'B8','B10','B13','B14','B15','B16','B19'
X3test = x3test.drop(['客户编号'],1)#,'C2','C5','C8','C10','C13','C29','C31','C33','C37','C42','C48','C49'
Xtest_1=[X1test,X2test,X3test]
X_test=pd.concat(Xtest_1,axis=1)
print(X_test.columns)
Xtest=[X_test]
for i in Xtest:
cmtest = np.corrcoef(i.values.T)
hmtest= sns.heatmap(cm, cbar=True, square=False, fmt='.3f', annot=True, annot_kws={'size':1}, yticklabels=i.columns, xticklabels=i.columns)
plt.show()
#模型参数选择
def para_tune1(para, X, Y):
clf = RandomForestClassifier(n_estimators=para) # n_estimators 设置为 para
score = np.mean(cross_val_score(clf, X, Y, scoring='accuracy'))
return score
def accurate_curve1(para_range, X, Y, title):
score = []
for para in para_range:
score.append(para_tune1(para, X, Y))
plt.figure()
plt.title(title)
plt.xlabel('Paramters')
plt.ylabel('Score')
plt.grid()
plt.plot(para_range, score, 'o-')
return plt
def para_tune2(para, X, Y):
clf = RandomForestClassifier(n_estimators=300, max_depth=para)
score = np.mean(cross_val_score(clf, X, y, scoring='accuracy'))
return score
def accurate_curve2(para_range, X, Y, title):
score = []
for para in para_range:
score.append(para_tune2(para, X, Y))
plt.figure()
plt.title(title)
plt.xlabel('Paramters')
plt.ylabel('Score')
plt.grid()
plt.plot(para_range, score, 'o-')
return plt
for i in Xtrain:
x = pd.DataFrame(i)
y = Ytrain
g = accurate_curve1([2, 10, 50, 100, 150, 200, 250], x, y, 'n_estimator tuning')
h = accurate_curve2([2, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100], x, y, 'max_depth tuning')
#pre-model
for i in Xtrain:
x = pd.DataFrame(i)
print(x.head(5))
y = Ytrain
print(y.head(5))
print('划分训练集测试集...')
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.8)
# 随机森林
model_rf = RandomForestClassifier(n_estimators=150,criterion='gini',max_depth=10, max_features='auto',random_state=1)
#tree_param_grid = { 'min_samples_split': list(range(1,50)),'n_estimators':list((80,100,200,300,600))}
#model_rf = GridSearchCV(RandomForestClassifier(),param_grid=tree_param_grid, cv=3)
model_rf.fit(x_train, y_train)
#先指定算法,然后把想找的参数写成字典传给param_grid,cv是交叉验证次数
print('随机森林分类...')
pre = model_rf.predict(x_test)
print('准确率:', accuracy_score(pre, y_test))
#模型预测--输出概率值
pre_p = model_rf.predict_proba(x_test)
print(pre_p)
print("-----------------------------------------------------------------------")
#可视化特征重要性
feature_importances = model_rf.feature_importances_
# 创建特征名列表
feature_names = list(i.columns)
# 创建一个DataFrame,包含特征名和其重要性得分
feature_importances_df = pd.DataFrame({'feature': feature_names, 'importance': feature_importances})
# 对特征重要性得分进行排序
feature_importances_df = feature_importances_df.sort_values('importance', ascending=False)
# 颜色映射
colors = plt.cm.viridis(np.linspace(0, 1, len(feature_names)))
# 可视化特征重要性
fig, ax = plt.subplots(figsize=(10, 6))
ax.barh(feature_importances_df['feature'], feature_importances_df['importance'], color=colors)
ax.invert_yaxis() # 翻转y轴,使得最大的特征在最上面
ax.set_xlabel('特征重要性', fontsize=12) # 图形的x标签
ax.set_title('随机森林特征重要性可视化',fontsize=16)
for n,p in enumerate(feature_importances_df['importance']):
ax.text(p + 0.01, n, str(round(p, 3)), va='center', fontname='Times New Roman', fontsize=10)
# # 设置图形样式
# plt.style.use('default')
ax.spines['top'].set_visible(False) # 去掉上边框
ax.spines['right'].set_visible(False) # 去掉右边框
# ax.spines['left'].set_linewidth(0.5)#左边框粗细
# ax.spines['bottom'].set_linewidth(0.5)#下边框粗细
# ax.tick_params(width=0.5)
# ax.set_facecolor('white')#背景色为白色
# ax.grid(False)#关闭内部网格线
plt.show()
#model
li=[]
for i in X_train.columns:
if i !="freq":
if i in X_test.columns:
li.append(i)
else:
li.append('freq')
x_train=X_train
x_test=X_test[li]
y_train=Ytrain
# 随机森林
model_rf_test = RandomForestClassifier(n_estimators=100,criterion='gini',max_depth=None,min_samples_leaf=1000, max_features='auto',random_state=1)
#tree_param_grid = { 'min_samples_split': list(range(1,50)),'n_estimators':list((80,100,200,300,600))}
#model_rf = GridSearchCV(RandomForestClassifier(),param_grid=tree_param_grid, cv=3)
model_rf_test.fit(x_train, y_train)
print('随机森林分类...')
y_pre_test = model_rf_test.predict(x_test)
print(y_pre_test)
rebuy=pd.DataFrame(y_pre_test,columns=['复购频率'])
rebuy.to_excel('predict.xlsx',index=0)
#模型评价
class ClassEval():
def __init__(self, preds,y_tests):
self.pre = preds
self.y_test = y_tests
self.C2 = None
'''计算混淆矩阵'''
def confusion_matrix(self):
self.C2 = metrics.confusion_matrix(self.y_test,self.pre, labels=[1,0])
return self.C2/len(self.pre)*100
'''绘制混淆矩阵热图'''
def C2_heatmap(self):
self.confusion_matrix()
#绘图
sns.set()
f, ax = plt.subplots(figsize=(8, 7))
TX = sns.heatmap(self.C2, annot=True, ax=ax, cmap="Spectral_r", fmt=".20g") # 热力图
#标题设置
ax.set_title("Confusion Matrix")
ax.set_xlabel("Predict")
ax.set_ylabel("Answer")
print("混淆矩阵")
'''计算准确率'''
def get_acc(self):
self.confusion_matrix()
print(type(self.C2))
#计算
acc = np.trace(self.C2)/self.C2.sum()
return acc
'''计算精准率'''
def get_precision(self):
self.confusion_matrix()
Precision = []
i = 0
for row in self.C2:
TP = row[i]
TP_FP = 0
for col in row:
TP_FP += col
Precision.append(TP/TP_FP)
i+=1
return Precision;
'''计算召回率'''
def get_Recall(self):
self.confusion_matrix()
Recall = []
i = 0
TP_FN = np.sum(self.C2, axis=0)
for row in self.C2:
TP = row[i]
Recall.append(TP/TP_FN[i])
i+=1
return Recall
'''计算F1指数'''
def get_F1(self):
self.confusion_matrix()
Precision = self.get_precision()
Recall = self.get_Recall()
F1 = []
for i in range(len(Precision)):
F1.append(2*Precision[i]*Recall[i] / (Precision[i] + Recall[i]))
return F1
'''计算kappa系数'''
def get_kappa(self):
self.confusion_matrix()
kappa = metrics.cohen_kappa_score(np.array(self.predict_label_list).astype(np.int16),np.array(self.answer_label_list).astype(np.int16))
return kappa
THRESHOLD = [.05, .10, .15] # threshold column
for i in Xtrain:
x = pd.DataFrame(i)
print(x.head(5))
y = Ytrain
print(y.head(5))
print('划分训练集测试集...')
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.8)
y_tests = np.where(y_test>1, 1, 0)
print(len(y_tests))
# 随机森林
model_rf = RandomForestClassifier(n_estimators=100,criterion='gini',max_depth=None,min_samples_leaf=1000, max_features='auto',random_state=1)
for h in THRESHOLD:
model_rf.fit(x_train, y_train)
preds = np.where(model_rf.predict_proba(x_test)[:,2] > h, 1, 0) # if prob > threshold, predict 1
print(len(preds))
RF_data = ClassEval(preds, y_tests)
# RF_data.C2_heatmap()
print("精确度",RF_data.get_acc())
print("精准率",RF_data.get_precision())
print("召回率",RF_data.get_Recall())
print("混淆矩阵",RF_data.confusion_matrix())
文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib
文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang
文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些
文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器
文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距
文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器
文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn
文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios
文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql
文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...
文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120
文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数