问题:
数据集:
链接:https://pan.baidu.com/s/1TUOLr8jFbT38p_iUh1iBsQ
提取码:1234
银行营销数据集
这些数据与葡萄牙银行机构的直接营销活动有关。这些直接营销活动是以电话为基础的。通常来说,银行机构的客服人员至少需要联系一次客户来得知客户是否将认购银行的产品(定期存款)。因此,与该数据集对应的任务是分类任务,而分类目标是预测客户是(yes)否(no)认购定期存款(变量y)。
数据集包含四个csv文件:
1) bank-additional-full.csv: 包含所有的样例(41188个)和所有的特征输入(20个),根据时间排序(从2008年5月到2010年9月);
2) bank-additional.csv: 从1)中随机选出10%的样例(4119个);
3) bank-full.csv: 包含所有的样例(41188个)和17个特征输入,根据时间排序。(该数据集是更老的版本,特征输入较少);
4) bank.csv: 从3)中随机选出10%的样例(4119个)。
数据集的输入变量是20个特征量,分为数值变量(numeric)和分类(categorical)变量,
输出变量为y,即客户是否已经认购定期存款(binary: "yes", "no")
策略:使用四个模型先粗测当前预测准确度,对其中准确度较高的进一步调优
算法简单介绍:
1.KNN算法
通过以某个数据为中心:
分析离其最近的K个邻居的类别;
获得该数据可能的类别
如果取K=1
待分类样本的类别就是最近邻居的类
2.SVM算法
SVM(Support Vector Machine)中文名为支持向量机,是常见的一种判别方法。在机器学习领域,是一个有监督的学习模型,通常用来进行模式识别、分类以及回归分析。
二维上,就是找一分割线W•X+b =0把两类分开,区分两个类别并且能使间隔(margin)最大
3.AdaBoost算法
该算法其实是一个简单的弱分类算法提升过程,这个过程通过不断的训练,可以提高对数据的分类能力。1. 先通过对N个训练样本的学习得到第一个弱分类器;
2. 将分错的样本和其他的新数据一起构成一个新的N个的训练样本,通过对这个样本的学习得到第二个弱分类器 ;
3. 将1和2都分错了的样本加上其他的新样本构成另一个新的N个的训练样本,通过对这个样本的学习得到第三个弱分类器;
4. 最后,将各个训练得到的弱分类器组合成强分类器。误差率低的弱分类器在最终分类器中占的比例较大,反之较小。
4.随机森林算法
随机森林顾名思义,是用随机的方式建立一个森林,森林里面有很多的决策树组成,随机森林的每一棵决策树之间是没有关联的。在得到森林之后,当有一个新的输入样本进入的时候,就让森林中的每一棵决策树分别进行一下判断,看看这个样本应该属于哪一类(对于分类算法),然后看看哪一类被选择最多,就预测这个样本为那一类。
完整代码见最后:
#训练集和测试集的导入
trainfile = pd.read_csv(r'.\bank-additional-full.csv', sep=';')
testfile = pd.read_csv(r'.\bank-additional.csv', sep=';')
1.判断有无显示的缺失值(为空值的部分)
2.判断有无隐含缺失值(分析发现存在很多unknown项)
3.统计每个特征值unknown项数
4.处理:对unknown项少的使用众数替换和行删除判断可行性(前后对比准确率)
对unknown项比较多的(unknown行数超过总体数据集的30%时)使用删除列处理
#判断数据是否读入完整
print(data.shape)
#判断是否存在缺失数据(空值):
data.info()
for col in trainfile.columns:
if type(trainfile[col][0]) is str:
print('unknown value count in'+col+':'+
str(trainfile[trainfile[col]=='unknown']['y'].count())
)
#删除unknown大于30%的列
for col in csvfile.columns:
if type(csvfile[col][0]) is str:
num=csvfile[csvfile[col]=='unknown'][col].count()
if num/len(csvfile)>0.3:
csvfile.drop(col,axis=1,inplace=True)
删除前的4个算法准确率:
删除后的4个算法准确率:
(决策树应该改为随机森林)
下面验证对该数据集缺失数据替换或者删除的可行性探究:
#替换为该列众数
for col in csvfile.columns:
if type(csvfile[col][0]) is str:
if 'unknown' in csvfile[col].tolist():
col_mode=csvfile[col].mode()[0]
csvfile[col].replace('unkonwn',col_mode,inplace=True)
# 删除含有'unknown'的行
for index, row in csvfile.iterrows():
if ('unknown' in row.values):
csvfile.drop([index], inplace=True)
删除前:
删除后:
这里我们采取的最高准确性比较所以选择的删除行
**
**
1. 分析特征:
通过分析个特征的数据选取其中差异化较大的特征作为最后我们用于模型训练的特征使用
部分情况如下:
比如这里的contact分布情况就相差很大所以我们这里就要选择其作为之后模型训练的一个特征值使用
比如这里的day_of_week其对结果数据的差异化就不明显所以不需要选择其作为最后模型训练的特征值
其他属性字段可以做类似的的图形,但是最快的还是属于使用热力图提取相关特征:
使用热力图显示各特征之间的相关性(如果时间不够,最快的方法就是使用热力图快速找到相关性较大的属性,将其作为特征)
2. 特征工程:
1.对以上选择的特征值进行数值化编码(方便处理数据)
2.离散化处理,处理数据中的极大极小值
3.对选取特征标准化或者归一化处理(作用:使得数据具有同等重要的作用,特别是在按距离分类的算法如K近邻算法d=sqrt((a-b)^2…)如果不做归一化或者标准化处理,如果此时a值较大,b值较小则最后可能对结果有同等重要性的数据只有一个被用上了,因为在距离函数中a大则其对结果数据起主导作用,b对结果的影响非常的小,甚至可以忽略。这种情况下,分类的特征就变少了,使得预测结果不准确。(我们要的应该是对于那些对结果数据差异化明显的数据尽可能的加入,这样的预测准确率才高)
4.样本均衡
关于特征工程:https://www.likecs.com/show-203284838.html
具体过程如下:
1.二分变量数值化:
csvfile.replace(['yes', 'no'], [1, 0], True) # 替换yes,no为1,0;
csvfile['nr.employed'].replace([5191.0, 5228.1], [0, 1], True) # 替换nr.employed列元素为0,1;
2.将其它分类变量(包括有序和无序)数值化
educationlist = ["illiterate", "basic.4y", "basic.6y", "basic.9y", "high.school", "professional.course",
"university.degree"]
educationvalue = [i for i in range(0, len(educationlist))]
joblist = ["admin.", "blue-collar", "entrepreneur", "housemaid", "management", "retired", "self-employed",
"services", "student", "technician", "unemployed"]
jobvalue = [i for i in range(0, len(joblist))]
maritallist = ["divorced", "married", "single"]
maritalvalue = [i for i in range(0, len(maritallist))]
contactlist = ["cellular", "telephone"]
contactvalue = [0, 1]
monthlist = ['month_apr', 'month_aug', 'month_dec', 'month_jul', 'month_jun', 'month_mar', 'month_may', 'month_nov',
'month_oct', 'month_sep']
monthvalue = [i for i in range(0, len(monthlist))]
day_of_weeklist = ['day_of_week_fri', 'day_of_week_mon', 'day_of_week_thu', 'day_of_week_tue', 'day_of_week_wed']
day_of_weekvalue = [i for i in range(0, len(day_of_weeklist))]
csvfile['day_of_week'].replace(day_of_weeklist, day_of_weekvalue, True)
csvfile['month'].replace(monthlist, monthvalue, True)
csvfile['contact'].replace(contactlist, contactvalue, True)
csvfile['job'].replace(joblist, jobvalue, True)
csvfile['marital'].replace(maritallist, maritalvalue, True)
csvfile['education'].replace(educationlist, educationvalue, True)
3.数据离散化:
把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。
通俗的说,离散化是在不改变数据相对大小的条件下,对数据进行相应的缩小。
#分箱离散化
csvfile['age']=pd.qcut(csvfile['age'],10)
csvfile['age']=pd.factorize(csvfile['age'])[0]
csvfile['duration']=pd.qcut(csvfile['duration'],10)
csvfile['duration']=pd.factorize(csvfile['duration'])[0]
csvfile['campaign']=pd.qcut(csvfile['campaign'],5,duplicates='drop')
csvfile['campaign']=pd.factorize(csvfile['campaign'])[0]
csvfile['pdays'] = pd.qcut(csvfile['pdays'], 10, duplicates='drop')
csvfile['pdays'] = pd.factorize(csvfile['pdays'])[0]
4.数据标准化:
标准化数据通过减去均值然后除以方差(或标准差),这种数据标准化方法经过处理后数据符合标准正态分布,即均值为0,标准差为1,转化函数为:x =(x - 均值)/方差
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
train_x = ss.fit_transform(train_x)#对数据先进行拟合处理,然后再将其进行标准化
test_x = ss.transform(test_x)
综上结果可知:在默认值参数下KNN算法是最优的,正确率是最高的。
max=0
max_index=1
for i in range(2,30,1):
# print(i)
knn = KNeighborsClassifier(p=1,n_neighbors=i)#选择的曼哈顿距离
knn.fit(train_x, train_y)
predict_y = knn.predict(test_x)
KNN2=accuracy_score(test_y, predict_y)
if KNN2>max:
max=KNN2
max_index=i
print("KNN准确率:", accuracy_score(test_y, predict_y))
print("最优k值为:")
print(max_index)
print("最优准确率:")
print(max)
距离参数通过手动调整发现曼哈顿距离最好,对于K值的选择我们使用for循环进行的查找(本来想使用二分,但是考虑到其不是顺序的所以就直接使用的线性查找)
另外其实这里取K=1时是最大的准确率在98%,但这其实是因为:
K值较小就意味着整体模型变得复杂,容易发生过拟合
K值较大就意味着整体模型变得简单,容易发生欠拟合
最终结果:(k从2开始)
最后我们取的K值为3
优点:
1、通过多种分类模型对比,使我们对题目了解跟全面,结构更清晰,准确度更高
2、精度高、对异常值不敏感、无数据输入假定。
缺点:
1、对部分属性进行了直接删除,忽略了数据相关性对结果的影响;
2、对部分非有序变量采用直接转变为数字的做法,使变量值之间的权重不相同;
展望:
1、更细致的特征选择,如派生属性;
2、采用更好的方法解决数据不平衡问题,如:代价敏感学习方法;
3、更细致的调参;
4、长视其他分类模型,如:神经网络等
5、因为前面是选择的当前最优算法,所以可能存在其他三个算法调优之后其准确度更高的情况。之后可以继续尝试其他算法调参后的准确度
完整代码:
(已修改,可以直接使用)
import pandas as pd
#训练集和测试集的导入
trainfile = pd.read_csv(r'.\bank-additional\bank-additional-full.csv', sep=';')
testfile = pd.read_csv(r'.\bank-additional\bank-additional.csv', sep=';')
# 数据预处理
def Pretreatment(csvfile):
# 删除'poutcome'列-nonexistent占比超过80%
csvfile.drop(['poutcome'], axis=1, inplace=True)
# 删除unknown大于30%的列
for col in csvfile.columns:
if (type(csvfile[col][0])) is str:#只有str类型才有‘unknown’项
num = csvfile[csvfile[col] == 'unknown'][col].count()
if (num / len(csvfile) > 0.3):
csvfile.drop(col, axis=1, inplace=True)
# 删除含有'unknown'的行
for index, row in csvfile.iterrows():
if ('unknown' in row.values):
csvfile.drop([index], inplace=True)
# 替换unknown为每列的众数
# for col in csvfile.columns.tolist():
# if (type(csvfile[col][0])) is str:
# if ('unknown' in csvfile[col].tolist()):
# col_mode = csvfile[col].mode()[0]
# csvfile[col].replace('unknown', col_mode, inplace=True)
# 分类变量数值化
csvfile.replace(['yes', 'no'], [1, 0], True) # 替换yes,no为1,0;
csvfile['nr.employed'].replace([5191.0, 5228.1], [0, 1], True) # 替换nr.employed列元素为0,1;
educationlist = ["illiterate", "basic.4y", "basic.6y", "basic.9y", "high.school", "professional.course",
"university.degree"]
educationvalue = [i for i in range(0, len(educationlist))]
joblist = ["admin.", "blue-collar", "entrepreneur", "housemaid", "management", "retired", "self-employed",
"services", "student", "technician", "unemployed"]
jobvalue = [i for i in range(0, len(joblist))]
maritallist = ["divorced", "married", "single"]
maritalvalue = [i for i in range(0, len(maritallist))]
contactlist = ["cellular", "telephone"]
contactvalue = [0, 1]
monthlist = ['month_apr', 'month_aug', 'month_dec', 'month_jul', 'month_jun', 'month_mar', 'month_may', 'month_nov',
'month_oct', 'month_sep']
monthvalue = [i for i in range(0, len(monthlist))]
day_of_weeklist = ['day_of_week_fri', 'day_of_week_mon', 'day_of_week_thu', 'day_of_week_tue', 'day_of_week_wed']
day_of_weekvalue = [i for i in range(0, len(day_of_weeklist))]
csvfile['day_of_week'].replace(day_of_weeklist, day_of_weekvalue, True)
csvfile['month'].replace(monthlist, monthvalue, True)
csvfile['contact'].replace(contactlist, contactvalue, True)
csvfile['job'].replace(joblist, jobvalue, True)
csvfile['marital'].replace(maritallist, maritalvalue, True)
csvfile['education'].replace(educationlist, educationvalue, True)
# # 离散化处理数据
# csvfile['age']=pd.qcut(csvfile['age'],10)
# csvfile['age']=pd.factorize(csvfile['age'])[0]
# csvfile['duration']=pd.qcut(csvfile['duration'],10)
# csvfile['duration']=pd.factorize(csvfile['duration'])[0]
# csvfile['campaign']=pd.qcut(csvfile['campaign'],5,duplicates='drop')
# csvfile['campaign']=pd.factorize(csvfile['campaign'])[0]
# csvfile['pdays'] = pd.qcut(csvfile['pdays'], 10, duplicates='drop')
# csvfile['pdays'] = pd.factorize(csvfile['pdays'])[0]
return csvfile
data = Pretreatment(trainfile)
data_test = Pretreatment(testfile)
#特征对结果影响分析
import matplotlib.pyplot as plt
import seaborn as sns
#这部分不需要,可以直接使用相关性矩阵进行相关性分析
'''plt.rcParams['font.sans-serif'] = 'SimHei'
plt.figure(figsize=(20, 8), dpi=256)
sns.countplot(x='age', data=data)
plt.title("各年龄段的人数")
plt.savefig('./1.png')
plt.figure(figsize=(18, 16), dpi=512)
plt.subplot(221)
sns.countplot(x='contact', data=data)
plt.title("contact分布情况")
plt.subplot(222)
sns.countplot(x='day_of_week', data=data)
plt.title("day_of_week分布情况")
plt.subplot(224)
sns.countplot(x='education', data=data)
plt.xticks(rotation=70)
plt.title("education分布情况")
plt.savefig('./2.png')
plt.figure(figsize=(18, 16), dpi=512)
plt.subplot(221)
sns.countplot(x='housing', data=data)
plt.title("housing分布情况")
plt.subplot(222)
sns.countplot(x='job', data=data)
plt.xticks(rotation=70)
plt.title("job分布情况")
plt.subplot(223)
sns.countplot(x='loan', data=data)
plt.title("loan分布情况")
plt.subplot(224)
sns.countplot(x='marital', data=data)
plt.xticks(rotation=70)
plt.title("marital分布情况")
plt.savefig('./3.png')
plt.figure(figsize=(18, 8), dpi=512)
plt.subplot(221)
sns.countplot(x='month', data=data)
plt.xticks(rotation=30)'''
#相关性矩阵,用于选择与结果属性y相关性强的属性作为特征
plt.rcParams['font.sans-serif'] = 'SimHei'
plt.figure(figsize=(10, 8), dpi=256)
plt.rcParams['axes.unicode_minus'] = False
sns.heatmap(data.corr(), annot=True)#使用热力图表示相关性矩阵
plt.title("各特征的相关性")
plt.savefig('./5.png')
plt.show()#图像显示
#特征选择
features = ['age','job', 'marital', 'education', 'housing', 'contact', 'duration',
'campaign', 'pdays', 'previous', 'emp.var.rate', 'cons.price.idx', 'cons.conf.idx', 'euribor3m', 'nr.employed']
from sklearn.preprocessing import LabelEncoder
le_x = LabelEncoder()
for feature in features:
data[feature] = le_x.fit_transform(data[feature])#对分类数据进行编码
data_test[feature] = le_x.fit_transform(data_test[feature])
col = features
import numpy as np
#得到训练集和测试集
train_x=np.array(data[col])
train_y=data['y']
test_x=np.array(data_test[col])
test_y=data_test['y']
# 数据规范化到正态分布的数据
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
train_x = ss.fit_transform(train_x)#对数据先进行拟合处理,然后再将其进行标准化
test_x = ss.transform(test_x)
#引入AdaBoost算法
from sklearn.ensemble import AdaBoostClassifier
from sklearn.metrics import accuracy_score
ada = AdaBoostClassifier()
ada.fit(train_x, train_y)
predict_y = ada.predict(test_x)
print("Adaoost准确率:", accuracy_score(test_y, predict_y))
#引入支持向量机算法
from sklearn.svm import SVC
svc = SVC()
svc.fit(train_x, train_y)
predict_y = svc.predict(test_x)
print("svm准确率:", accuracy_score(test_y, predict_y))
# ans.append(accuracy_score(test_y, predict_y))
#引入Knn算法
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
knn = KNeighborsClassifier()
knn.fit(train_x, train_y)
predict_y = knn.predict(test_x)
print("KNN准确率:", accuracy_score(test_y, predict_y))
#引入随机森林算法
from sklearn.tree import DecisionTreeClassifier
dtc = DecisionTreeClassifier()
dtc.fit(train_x, train_y)
predict_y = dtc.predict(test_x)
print("随机森林准确率:", accuracy_score(test_y, predict_y))
print("由此得KNN算法为当前4个算法的最优算法,所以我们对KNN算法进行进一步的调参,过程如下:")
max=0
max_index=1
for i in range(2,30,1):
# print(i)
knn = KNeighborsClassifier(p=1,n_neighbors=i)#选择的曼哈顿距离
knn.fit(train_x, train_y)
predict_y = knn.predict(test_x)
KNN2=accuracy_score(test_y, predict_y)
if KNN2>max:
max=KNN2
max_index=i
print("KNN准确率:", accuracy_score(test_y, predict_y))
print("最优k值为:")
print(max_index)
print("最优准确率:")
print(max)
疯狂之处在于这个只用了两天来做 (ó﹏ò。)