2023四川省大学生金融科技建模大赛:银行客户复购频率预测-程序员宅基地

技术标签: 科技  python  机器学习  随机森林  金融  

        对银行客户复购频率的进行三分类预测。根据客户信息(包括基础客户画像信息、产品购买行为信息以及第三方客户画像补充信息)预测客户复购行为对客户信息数据进行预处理,通过特征选择和特征工程不断构建新特征,提高模型性能,通过随机森林建模预测客户复购频率,并根据客户平均价值(低频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())    
    

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zbjsmv/article/details/137564590

智能推荐

c# 调用c++ lib静态库_c#调用lib-程序员宅基地

文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib

deepin/ubuntu安装苹方字体-程序员宅基地

文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang

html表单常见操作汇总_html表单的处理程序有那些-程序员宅基地

文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些

PHP设置谷歌验证器(Google Authenticator)实现操作二步验证_php otp 验证器-程序员宅基地

文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器

【Python】matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距-程序员宅基地

文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距

docker — 容器存储_docker 保存容器-程序员宅基地

文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器

随便推点

网络拓扑结构_网络拓扑csdn-程序员宅基地

文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn

JS重写Date函数,兼容IOS系统_date.prototype 将所有 ios-程序员宅基地

文章浏览阅读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

如何将EXCEL表导入plsql数据库中-程序员宅基地

文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql

Git常用命令速查手册-程序员宅基地

文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...

分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120-程序员宅基地

文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120

【C++缺省函数】 空类默认产生的6个类成员函数_空类默认产生哪些类成员函数-程序员宅基地

文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数

推荐文章

热门文章

相关标签