内容
1.客户对于银行而言是重要的资产,对银行的收益以及市场占有率起着决定性作用。但是银行每年都要面对严重的客户流失问题,相较留住一个客户,获取一个新客户所需的成本往往是其数倍。因此分析出一个客户是否可能是潜在的易流失客户对于银行而言具有极大价值。通过研究客户的历史行为来捕捉流失客户的特点,分析客户流失原因,从而可以在客户真正流失之前做出相应的营销干预,对客户进行挽留。请根据国外某银行的匿名化数据,进行客户流失分析,具体的训练集和测试数据集请见Bank-Train.csv和Bank-Test.csv。
1)数据集中有一些非数值类型的特征,例如地理位置Geography(France,Spain,Germany)、性别Gender(female,male),这些非数值特征可能在分类中产生比较大的作用,请将这两个特征数值化。
2)对于信用分数CreditScore属性,有25%的数据小于584,50%的数据小于652,75%的数据小于718,请将信用分数小于584的数据划分为第一档,信用分数为584 ~652的数据划分为第二档,信用分数为584~718的数据划分为第三档,信用分数大于718的数据则划分为第四档,实现数据的离散化。
3)将经过前面两步处理后的训练数据集进行学习,编程实现一种分类模型(如:线性回归模型,KNN,朴素贝叶斯等),对测试数据集做出预测,计算其预测精度及召回率。特别提醒,模型不能调用SKLearn库等现有的方法来实现,需要自己编程实现。
4)以图形的方式分别给出训练集和测试集对应的混淆矩阵;注意,如果采用KNN算法实现,则只需要给出测试集的混淆矩阵。
5)将预测精度通过柱状图表示出来,其中横轴为模型名称,纵轴为其对应的预测精度。
数据集属性说明:
RowNumber:行号 ×
CustomerID:用户编号 ×
Surname:用户姓名 ×
CreditScore:信用分数
Geography:用户所在国家/地区
Gender:用户性别
Age:年龄
Tenure:当了本银行多少年用户
Balance:存贷款情况
NumOfProducts:使用产品数量
HasCrCard:是否有本行信用卡
IsActiveMember:是否活跃用户
EstimatedSalary:估计收入
Exited:是否已流失,标签数据;0表示未流失,1表示已流失
格式类似如下:
Bank_Train.csv:测试集。10000行。
Test_Train.csv:验证集。1000行。
代码
使用KNN实现。
#!/usr/bin/env python
# encoding: utf-8
import numpy as np
import matplotlib.pyplot as plt
import pandas
# 第一、二题:通过lambda表达式将Geography,性别Gender特征数值化;
# 同时进行数据的离散化
def file2matrix(filepath):
df = pandas.read_csv(filepath, delimiter=',')
def Geography_numerical(Geography):
if Geography in ['France']:
return 2
elif Geography in ['Spain']:
return 1
else:
return 0
df['Geography'] = df['Geography'].apply(lambda x: Geography_numerical(x))
def Gender_numerical(Gender):
if Gender in ['female']:
return 1
else:
return 0
df['Gender'] = df['Gender'].apply(lambda x: Gender_numerical(x))
def CreditScore_numerical(CreditScore):
if CreditScore < 584:
return 0
elif CreditScore >= 584 & CreditScore < 652:
return 1
elif CreditScore >= 652 & CreditScore < 718:
return 3
else:
return 4
df['CreditScore'] = df['CreditScore'].apply(lambda x: CreditScore_numerical(x))
df.drop(['Surname'], axis=1, inplace=True)
df.drop(['RowNumber'], axis=1, inplace=True)
df.drop(['CustomerId'], axis=1, inplace=True)
# print(df)
# print(df.iloc[:,0:-1])
# print(np.array(df.iloc[:, 0:-1]))
# print(np.array(df.iloc[:, -1]))
m = df.shape[0]
returnMat = np.array(df.iloc[:, 0:-1])
classlabelVector = np.array(df.iloc[:, -1]).reshape(m,1)
print(classlabelVector)
return returnMat, classlabelVector
# 第三题:利用KNN算法将其分类
def classify(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0] #shape(m, n)m列n个特征
inxSize = inX.shape[0]
diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
sqDiffMat = diffMat ** 2
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances ** 0.5 #欧式距离
sortedDistIndicies = distances.argsort() #排序并返回index
classCount = {}
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]][0]
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1 #default 0
sortedClassCount = sorted(classCount.items(), key=lambda d:d[1], reverse=True)
return sortedClassCount[0][0]
# 数据归一化
def autoNorm(dataSet):
minVal = dataSet.min(0)
maxVal = dataSet.max(0)
ranges = maxVal - minVal
normDataSet = np.zeros(dataSet.shape)
m, n = dataSet.shape # 行, 特征
normDataSet = dataSet - minVal
normDataSet = normDataSet / ranges
return normDataSet, ranges, minVal
#对验证集测试集的划分主要在这里
def train_and_test():
TrainDataMat, trainLabels = file2matrix('Bank-Train.csv')
TestDataMat, testLabels = file2matrix('Bank-Test.csv')
m, n = TestDataMat.shape
result = []
accuCount = 0 # 错误分类数
recallNum = 0
for i in range(m):
classifierResult = classify(TestDataMat[i, :], TrainDataMat, trainLabels, 3)
result.append(classifierResult)
if classifierResult == testLabels[i]:
accuCount += 1
if testLabels[i] == 1 :
recallNum += 1;
print("the total error rate is: %f" % (accuCount / float(m)))
print("the total recall rate is: %f" % (recallNum / accuCount))
# 第四题:混淆矩阵的给出
result = np.array(result)
result = result.reshape(-1)
count = 0
count_r = 0
count_e = 0
count_fp = 0
count_tn = 0
# print(result)
# print(result.shape)
for i in range(0, result.size):
if testLabels[i] == 1:
if testLabels[i] == result[i]:
count_r = count_r + 1
if testLabels[i] == 0:
if testLabels[i] == result[i]:
count_tn = count_tn + 1
if testLabels[i] != result[i]:
count = count + 1
if (result[i] == 0):
count_e = count_e + 1
if (result[i] == 1):
count_fp = count_fp + 1
print("\n\n matrix is:")
print("TP:", count_r, "FN:", count_e)
print("FP:", count_fp, "TN:", count_tn)
matrix = [[count_r, count_e], [count_fp, count_tn]]
plt.matshow(matrix, cmap=plt.cm.Reds)
plt.colorbar()
for i in range(len(matrix)):
for j in range(len(matrix)):
plt.annotate(matrix[i][j], xy=(i, j), horizontalalignment='center', verticalalignment='center')
plt.ylabel('True label')
plt.xlabel('Predicted label')
plt.show()
# 第五题:预测精度的柱状图(只有KNN)
plt.bar("KNN", accuCount / float(m))
plt.show()
if __name__ == '__main__':
train_and_test()