大数据分析——外国人群薪资收入数据分析与挖掘
一、 选题背景
人群收入是大众关心的非常重要的经济生活话题,然而人群收入受很多方面的因素影响,有年龄因素、工作性质因素、国家来源因素以及每周工作时长因素等等。根据统计和经济学知识,这些因素确实是跟收入有一定关系的,所以我们这里涉及的预测自变量有15个相关的指标,当然为了保护人群的隐私数据,很大部分数据值都存在脱敏处理,但这并不代表我们不能运用这些信息,重新运用这些信息是需要相应的转换和数据分析的。本文就是基于机器学习技术来预测和分析我们所需要的人群收入内在价值信息,通过内在信息做到对人群信息的掌握,从而统筹好社会发展。
二、 大数据分析设计方案
1.本数据集的数据内容
本数据集是一份外国人群数的相关收入信息数据,含有15个字段,数据共计30000多条。
数据特征分析
字段:解释
Age: 年龄
Work Class: 工作类型
Final Weight: 体重
Education : 教育程度
Education Number: 教育年限
Marital Status: 婚姻状态
Occupation: 职业
Relationship:社会关系
Race: 种族
Sex: 性别
Capital Gain: 资本收益
Capital Loss: 资本损失
Hours per Week: 周工时
Country: 国家
Income: 收入
2.数据分析的课程设计方案概述
(1) 先对数据进行预处理和清洗
(2) 利用数据建模与挖掘进行数据分析
(3) 数据的特征工程与可视化
三、数据分析步骤
1.数据源
数据集来源于国外Kaggle数据集网站进行采集。源数据集网址
https://www.kaggle.com/datasets/jack20216915/population-income?select=income.xlsx
导入包和数据集
1 import matplotlib.pyplot as plt 2 import seaborn as sns 3 import pandas as pd 4 import numpy as np 5 import time 6 import warnings 7 warnings.filterwarnings('ignore') 8 start_time = time.time() 9 plt.rcParams['font.sans-serif']=['SimHei']##中文乱码问题! 10 plt.rcParams['axes.unicode_minus']=False#横坐标负号显示问题! 11 path = 'income.xlsx' 12 data = pd.read_excel(path ) 13 colstr = ['workclass','education','marital-status','occupation','relationship','race','sex', 14 'native-country','income'] 15 data
2数据清洗
数据清洗是建模非常重要的组成部分,能对后续建模起到事半功倍的效果。在工程实践中,我们得到的数据会存在有缺失值、重复值等,在使用之前需要进行数据清洗。
(1)删除无效id列
1 data.drop('id',axis=1,inplace=True) 2 data.head()
(2)稀疏值处理
明显地发现,“资本收益”序列数数存在明显的稀疏情况(0的个数占比92%),“资本损失”也是(0的个数占比95%),稀疏数据的大量存在一方面导致运算复杂,另一方面会对模型造成过拟合现象,去除这两列数据。最终处理结果如下:
1 del data['capital-gain'] 2 del data['capital-loss'] 3 data
(3)数据类型转换,删除缺失值
先对数据的缺失值进行删除(缺失值不是很多),由于本身数据很多字段对应的值为字符串数据,但是字符串数据是不能参与运算的,可是我们还非常想充分利用此数据集,所以将字符串数据改写为类别数值数据。
1 def transform_type(data,col):##转换数据类型 2 3 print('original:',data.shape) 4 data = data.dropna() 5 print('now:',data.shape) 6 7 for i in col: 8 datatemp = data[i] 9 msg = set(datatemp) 10 for j,k in zip(msg,[l for l in range(1,len(msg) + 1)]): 11 data[i][data[i]==j] = k 12 return data 13 res = transform_type(data,colstr) 14 15 res.index = [i for i in range(res.shape[0])] 16 index_ls = res.index 17 print(res)
(4)异常值处理
采用多项式拟合+统计方法来处理,但不处理类别数据,只对连续型数据(排除“年龄”和“教育年限”,这两列数据非常常规不做处理)做处理。
1 def substitute_outliner(data,original_ls,yl,tit,mul1,mul2,num_ls): 2 print('\033[1;34m{0:*^80}\033[1;0m'.format('特征数据“%s”异常值处理'%yl)) 3 copydata = original_ls.copy() 4 for i in data[5]:##获取异常值位置 5 del original_ls[i]##按照位置删除最最保险 6 upvalue = data[2][i] 7 downvalue = data[3][i] 8 originalvalue = copydata[i] 9 if originalvalue <= downvalue: 10 changevaluetemp = downvalue * 0.5 + upvalue * 0.25 11 if changevaluetemp >= upvalue: 12 changevalue = upvalue 13 else: 14 changevalue = max(changevaluetemp,downvalue)##最小不低于downvalue,防止upvalue过小 15 original_ls.insert(i,round(changevalue,1)) 16 print('\033[1;31m异常数据编号为(原始值%s):%s,替换的修正值为:%s,downvalue:%s\033[0m' % (originalvalue, num_ls[i], round(changevalue,2),round(downvalue,2))) 17 if originalvalue >= upvalue: 18 changevaluetemp = upvalue * 0.5 + downvalue * 0.25 19 if changevaluetemp <= downvalue: 20 changevalue = downvalue 21 else: 22 changevalue = min(changevaluetemp,upvalue)##最大不超过upvalue,防止downvalue过大 23 original_ls.insert(i,round(changevalue,1)) 24 print('\033[1;31m异常数据编号为(原始值%s):%s,替换的修正值为:%s,upvalue:%s\033[0m'%(originalvalue,num_ls[i],round(changevalue,2),round(upvalue,2))) 25 26 plt.figure(figsize=(15, 8)) 27 plt.plot(list(copydata), 'y', label='原始数值') 28 plt.plot(data[1], 'r', label='拟合曲线') 29 plt.plot(data[2], 'purple', label='拟合上限(%ssigm)曲线'%mul1) 30 plt.plot(data[3], 'b', label='拟合下限(%ssigm)曲线'%mul2) 31 plt.plot(original_ls, 'g', label='处理完后的数据') 32 plt.legend(fontsize=15) 33 plt.tick_params(labelsize=15) 34 plt.xlabel('编号',fontsize=18) 35 plt.ylabel(yl,fontsize=18) 36 plt.title(tit,fontsize=20) 37 plt.show() 38 return original_ls 39 40 def check_outlier(value,mul1,mul2,yl): 41 42 print('\033[1;34m{0:*^80}\033[1;0m'.format('特征数据“%s”预处理'%yl)) 43 x = [j for j in range(len(value))] 44 coeffs = np.polyfit(x, value, 10) ##专门求多项式估计参数的函数,根据实际数据波动取相应的阶数 45 p = np.poly1d(coeffs) # 一元估计参数 46 sigm = p(x).std() 47 sigm_up = p(x) + mul1 * sigm 48 sigm_down = p(x) - mul2 * sigm 49 outliner = value[(value < sigm_down) | (value > sigm_up)]#条件筛选 50 print('\033[1;31m原数据长度:%s,异常数据:%s\033[0m'%(len(value),len(outliner))) 51 print(outliner) 52 return list(outliner),p(x),sigm_up,sigm_down,x,list(outliner.index) 53 54 col = list(res) 55 remove_ls = colstr + ['age','education-num'] 56 57 for i in remove_ls: 58 col.remove(i)##类别数据不作处理 59 for i in col:##性别和编号不做计算 60 mul1 = 500 61 mul2 = 500##由于数据很大是人为的,这里mul1和mul2参数慎改 62 res1 = check_outlier(res[i],mul1,mul2,i) 63 res2 = substitute_outliner(res1,list(res[i]),i,'“%s”数据预处理图'%i,mul1,mul2,index_ls) 64 res[i] = res2##数据替换 65 66 del res['capital-gain'] 67 del res['capital-loss'] 68 del res['education'] 69 # res.to_excel(path + '处理好的数据.xlsx')
3大数据分析过程及采用的算法
我们主要是利用逻辑回归做预测,因为这种模型在处理二分类上有很好的效果,泛化能力强,过拟合概率低。我们开始先对数据集进行训练集:测试集=7:3的比例的随机选取,然后确定好模型的随机种子、其它相关参数等,多次调整取最优,最终给出评价指标来综合评价预测模型的效果。
评价指标我们主要给出六种,一是模型的准确率指标,二是混淆矩阵可视化图,三是ROC修正后的评价指标,四是召回率,五是精准率,六是F1值。
但是为了最终客观评价模型的性能,一次随机实验是不够的,我们将多次实验,取各个指标的平均结果,最为最后的评价指标。
(1) 逻辑回归模型原理
实现代码
1 from sklearn.metrics import roc_curve, auc,confusion_matrix,f1_score, precision_score, recall_score 2 from sklearn.linear_model import LogisticRegression as LR 3 from sklearn.model_selection import train_test_split 4 import matplotlib.pyplot as plt 5 import pandas as pd 6 import numpy as np 7 8 import warnings 9 warnings.filterwarnings('ignore') 10 11 12 plt.rcParams['font.sans-serif']=['SimHei']##中文乱码问题! 13 plt.rcParams['axes.unicode_minus']=False#横坐标负号显示问题! 14 15 16 data = pd.read_excel('处理好的数据.xlsx',index_col=0) 17 print(data) 18 19 20 # del data['fnlwgt']##去除“体重”变量 21 data.iloc[:,1:data.shape[1]-1] = (data.iloc[:,1:data.shape[1]-1] - data.iloc[:,1:data.shape[1]-1].min()) \ 22 / (data.iloc[:,1:data.shape[1]-1].max() - data.iloc[:,1:data.shape[1]-1].min()) 23 X = np.array(data.iloc[:,1:data.shape[1]-1])##自变量的读取 24 25 Y = np.array(data.iloc[:,data.shape[1]-1])##因变量的读取 26 dis_name = [1,2] 27 rd = 211 28 29 30 ##绘制roc图 31 def make_figure_auc_roc(true_label,score,class_): 32 plt.figure(figsize=(15, 8)) 33 34 fpr, tpr, thresholds = roc_curve(true_label,score,pos_label=class_,drop_intermediate=False) 35 ###返回的是一系列thresholds阈值 36 roc_auc = auc(fpr, tpr) 37 roc_result = pd.DataFrame({'fpr' : fpr,'tpr' : tpr, 'tf' : tpr - (1-fpr),'thresholds' : thresholds}) 38 # roc_result.iloc[(roc_result.tf-0).abs().argsort()[:1]] 39 optimal_idx = np.argmax(tpr - fpr) 40 optimal_threshold = thresholds[optimal_idx] 41 y = tpr[optimal_idx] 42 x = fpr[optimal_idx] 43 plt.figure(figsize=(8,5)) 44 plt.plot(fpr, tpr, color='navy',label='AUC=%.3f' % roc_auc) 45 plt.plot([-0.005, 1.005], [-0.005, 1.005], color='orange',linestyle='--') 46 plt.xlabel('1-特异度',fontsize=10) 47 plt.ylabel('敏感度',fontsize=10) 48 plt.scatter(x, y, c='red',s=15) 49 plt.tick_params(labelsize=12,rotation=10) 50 plt.title('ROC曲线',fontsize=12) 51 plt.legend(loc='best',fontsize=18) 52 plt.text(x+0.05,y-0.05,s='('+str(round(1-x, 3))+', '+str(round(y, 3))+')',fontsize=15) 53 plt.show() 54 return roc_auc 55 56 def cm_plot(yp, y):##混淆矩阵 57 plt.figure(figsize=(15, 8)) 58 cm = confusion_matrix(yp, y) # 混淆矩阵 59 plt.matshow(cm, cmap=plt.cm.Greens) # 画混淆矩阵图,配色风格使用cm.Greens,更多风格请参考官网。 60 plt.colorbar() # 颜色标签 61 62 for x in range(len(cm)): # 数据标签 63 for y in range(len(cm)): 64 plt.annotate(cm[x, y], xy=(x, y), horizontalalignment='center', verticalalignment='center') 65 plt.ylabel('真实标签',fontsize=10) # 坐标轴标签 66 plt.xlabel('预测标签',fontsize=10) # 坐标轴标签 67 plt.title('预测混淆矩阵图', fontsize=12) 68 plt.show() 69 70 ##自定义准确率计算 71 def show_result(dis_name, pre_ls, real_ls,rd):##准确率 72 73 ls_r = [] 74 ls_c = [] 75 for d in dis_name: 76 res_ls = [] 77 for i, j in zip(pre_ls, list(real_ls)): 78 if i == j == d: 79 res_ls.append('正确') 80 81 ls_r.append(len(res_ls) / list(real_ls).count(d)) 82 ls_c.append((len(res_ls),list(real_ls).count(d))) 83 84 print('\033[1;32m随机种子是%s时,%s(%s/%s)准确率:%.3f%%\033[0m' % (rd,d, len(res_ls), list(real_ls).count(d), len(res_ls) / list(real_ls).count(d) * 100)) 85 86 res_ls = [] 87 for i, j in zip(pre_ls, list(real_ls)): 88 if i == j: 89 res_ls.append('正确') 90 else: 91 res_ls.append('错误') 92 93 print('\033[1;31m随机种子是%s时,总预测(%s/%s)准确率:%.3f%%\033[0m' % (rd,res_ls.count('正确'), len(res_ls), res_ls.count('正确') / len(res_ls) * 100)) 94 df = pd.DataFrame([list(real_ls), pre_ls, res_ls], index=['真实', '预测', '预测结果']).T 95 allcorretrate = res_ls.count('正确') / len(res_ls) * 100 96 return df,allcorretrate 97 98 99 ##建立LR模型 100 def model(x,y,rd=rd): 101 102 xtrain, xtest, ytrain, ytest = train_test_split(x, y, test_size=0.3, random_state=rd) 103 lr = LR(solver='liblinear') # 建立逻辑回归模型 104 lr.fit(xtrain, ytrain) # 用特征数据来训练模型 105 pre_lr = lr.predict(xtest) 106 pro_lr = lr.predict_proba(xtest) 107 108 return pre_lr,ytest,pro_lr,lr.classes_[0] 109 110 print('\033[1;38m{0:*^80}\033[0m'.format('一次实验随机种子为%s的准确率汇总'%rd)) 111 112 res = model(X,Y) 113 make_figure_auc_roc(res[1], res[2][:, 0], res[3]) 114 cm_plot(res[0],res[1]) 115 show_result(dis_name,res[0],res[1],rd) 116 117 f1 = round(f1_score(res[1], res[0], average='macro'),3)##F计算 118 p = round(precision_score(res[1], res[0], average='macro'),3)##精准率计算 119 r = round(recall_score(res[1], res[0], average='macro'),3)##召回率计算 120 print(f1,p,r) 121 122 123 ##循环调用LR模型并可视化结果 124 125 def makefigure(rdls,x,y,func,dn): 126 127 plt.figure(figsize=(15, 8)) 128 print('\033[1;38m{0:*^80}\033[0m'.format('多次实验的准确率汇总')) 129 lsr = [] 130 f1_ls = [] 131 p_ls = [] 132 r_ls = [] 133 rou_ls = [] 134 for k in rdls: 135 R = func(x,y,k)##循环调用模型 136 rr = show_result(dn, R[0], R[1],k) 137 f1 = f1_score(R[1], R[0], average='macro') 138 p = precision_score(R[1], R[0], average='macro') 139 r = recall_score(R[1], R[0], average='macro') 140 roc = make_figure_auc_roc(R[1], R[2][:, 0], R[3]) 141 f1_ls.append(f1) 142 p_ls.append(p) 143 r_ls.append(r) 144 lsr.append(rr[1]) 145 rou_ls.append(roc) 146 plt.figure(figsize=(15, 8)) 147 print('\033[1;38m平均准确率:%.3f%%\033[0m'%(pd.Series(lsr).mean())) 148 print('\033[1;38m平均f1值:%.3f\033[0m' % (pd.Series(f1_ls).mean())) 149 print('\033[1;38m平均召回率值:%.3f\033[0m' % (pd.Series(p_ls).mean())) 150 print('\033[1;38m平均精准率值:%.3f\033[0m' % (pd.Series(r_ls).mean())) 151 print('\033[1;38m平均ROC值:%.3f\033[0m' % (pd.Series(rou_ls).mean())) 152 plt.plot(lsr,label='决策树多次计算结果',marker='*') 153 plt.legend(loc='best',fontsize=15) 154 plt.tick_params(labelsize=15) 155 plt.xticks([j for j in range(len(rdls))],[str(j) for j in rdls]) 156 plt.xlabel('随机种子数(%s次计算)'%len(rdls),fontsize=18) 157 plt.ylabel('准确率(%)',fontsize=18) 158 plt.show() 159 160 rand_ls = np.random.randint(0,1000,20) 161 makefigure(rand_ls,X,Y,model,dis_name)###调用函数
一次随机建模结果
由ROC图我们发现,模型的敏感性和特异性还是蛮均衡的,整体来看,模型性能总体还是良好的。
多次平均建模结果
以上就是模型的综合性能,从平均f1值和ROC值发现,我们的模型鲁棒性和准确性还是蛮优良的,有一定的泛化能力,这得力于开始的数据清洗阶段处理的科学有效
4.数据可视化
(1)数据的特征工程与可视化
特征工程是机器学习,甚至是深度学习中最为重要的一部分特征工程主要是对特征进行筛选,构造与降维等等,可以选择主要特征和构造新的特征,从而增加模型泛化能力。
可视化更是让我们清楚了解数据组成部分,为深度分析做准备。
(2) 计算体重、教育年限、工作时长的相关特征值
1 data = pd.read_excel('处理好的数据.xlsx',index_col=0) 2 3 newdf1 = data[['fnlwgt','education-num','hours-per-week']].dropna() 4 print(newdf1.describe()) 5 print(newdf1.corr())
以上就是相关数据的描述性统计特征值,由此我们发现,这些数据的分布范围和数量级都是不同的,尤其体重的数量级是非常大的,所以在后面的建模中,我们要主要有些变量的取值不同带来的负面效果。
(3)计算体重、教育年限、工作时长它们之间的皮尔森相关性
为了减少共线性变量带来的运算资源的浪费,接下来,通过变量之间的相关性分析来筛选变量,根据相关系数理论,当两变量之间的相关系数绝对值大于0.8时,可以认为两变量相关性非常强烈,取之一即可,具体见下表展示:
1 sns.heatmap(newdf1.corr(),square = True, vmax=0.8) 2 plt.show()
由于上述三种数据本身就是连续型数值数据,所以我们选择这些数据做特征分析和相关性分析,由上述相关系数值的计算,发现这三则的两两之间,并没有什么太大关系,甚至还有点负相关关系。
(4)变量分布的可视化
绘制概率密度图
1 ##循环绘制概率密度图 2 for i in ['fnlwgt','education-num','hours-per-week']: 3 plt.figure(figsize=(15, 8)) 4 lstemp = data[i] 5 sns.distplot(lstemp, rug=False, hist=True, bins=15) 6 plt.tick_params(labelsize=18) 7 plt.ylabel('概率密度', fontsize=18) 8 plt.xlabel(i, fontsize=18) 9 plt.title('%s的概率密度分布图'%i,fontsize=20) 10 plt.show() 11 plt.show()
以上3幅图就是这三个变量对应的概率密度分布图,我们发现,这些变量的分布并不是很标准的正态分布,但也都有非常突出的区间段数据,尤其是教育年限达到13年左右,也是个人数非常集中的区间段落。每周工作时长集中在40小时左右,看来非常符合8小时工作日的平常制度。
(5)人种分布饼图
1 # 生成数据 2 datat = pd.read_excel(path + 'income.xlsx',index_col=0) 3 datat = list(datat['race']) 4 set_ls = set(datat) 5 count_ls = [] 6 for i in set_ls: 7 count_ls.append(round(datat.count(i) / len(datat),2)) 8 labels = list(set_ls) 9 share = count_ls 10 11 # 设置分裂属性 12 explode = [0 for i in range(len(set_ls))] 13 14 # 分裂饼图 15 plt.figure(figsize=(15, 8)) 16 plt.pie(share, explode = explode, 17 labels = labels, autopct = '%3.1f%%', 18 startangle = 180, shadow = True,) 19 plt.tick_params(labelsize=20) 20 # 标题 21 plt.title('人种分布扇形图',fontsize=20) 22 plt.show()
由上图的扇形图发现,此数据集的人种分布很明显是白人和黑人组成,占了95%以上,这是比较符合美国国情的。
(6)性别与教育年限关联图
1 def makefigure(xname,yname): 2 3 plt.figure(figsize=(15, 8)) 4 sns.countplot(x=xname,hue=yname, data=data) 5 plt.legend(fontsize=18) 6 plt.ylabel(yname,fontsize=18) 7 plt.xlabel(xname,fontsize=18) 8 plt.title('%s与%s关联的柱状图'%(xname,yname),fontsize=20) 9 plt.xticks((0,1),('male','female')) 10 plt.tick_params(labelsize=15) 11 plt.show() 12 13 makefigure('sex','education-num') 14 makefigure('sex','income')
由上述分布柱状图我们发现男性和女性的教育年限基本都分布在9-13年这区域,这点是相同的,但不同的是男性的教育年限在第9年的人数比例是非常大的,比女性要大很多。
(7)性别与收入关联图
我发现在大于50K的人数分布比例上,男性是明显大于女性的(女性比值大约是8.1,男性大约是2.3),这侧面说明高收入人群还是男性居多,男性更多是创造社会财富,女性也许更多的是照顾家庭。
5.完整代码附上
1 from sklearn.metrics import roc_curve, auc,confusion_matrix,f1_score, precision_score, recall_score 2 from sklearn.linear_model import LogisticRegression as LR 3 from sklearn.model_selection import train_test_split 4 import matplotlib.pyplot as plt 5 import pandas as pd 6 import numpy as np 7 import warnings 8 import seaborn as sns 9 import time 10 11 warnings.filterwarnings('ignore') 12 13 start_time = time.time() 14 plt.rcParams['font.sans-serif']=['SimHei']##中文乱码问题! 15 plt.rcParams['axes.unicode_minus']=False#横坐标负号显示问题! 16 17 18 data = pd.read_excel('income.xlsx',index_col=0) 19 # print(data) 20 21 colstr = ['workclass','education','marital-status','occupation','relationship','race','sex', 22 'native-country','income'] 23 24 def transform_type(data,col):##转换数据类型 25 26 print('original:',data.shape) 27 data = data.dropna() 28 print('now:',data.shape) 29 30 for i in col: 31 datatemp = data[i] 32 msg = set(datatemp) 33 for j,k in zip(msg,[l for l in range(1,len(msg) + 1)]): 34 data[i][data[i]==j] = k 35 return data 36 res = transform_type(data,colstr) 37 38 res.index = [i for i in range(res.shape[0])] 39 index_ls = res.index 40 print(res) 41 42 43 def substitute_outliner(data,original_ls,yl,tit,mul1,mul2,num_ls): 44 45 print('\033[1;34m{0:*^80}\033[1;0m'.format('特征数据“%s”异常值处理'%yl)) 46 copydata = original_ls.copy() 47 for i in data[5]:##获取异常值位置 48 del original_ls[i]##按照位置删除最最保险 49 upvalue = data[2][i] 50 downvalue = data[3][i] 51 originalvalue = copydata[i] 52 if originalvalue <= downvalue: 53 changevaluetemp = downvalue * 0.5 + upvalue * 0.25 54 if changevaluetemp >= upvalue: 55 changevalue = upvalue 56 else: 57 changevalue = max(changevaluetemp,downvalue)##最小不低于downvalue,防止upvalue过小 58 original_ls.insert(i,round(changevalue,1)) 59 print('\033[1;31m异常数据编号为(原始值%s):%s,替换的修正值为:%s,downvalue:%s\033[0m' % (originalvalue, num_ls[i], round(changevalue,2),round(downvalue,2))) 60 if originalvalue >= upvalue: 61 changevaluetemp = upvalue * 0.5 + downvalue * 0.25 62 if changevaluetemp <= downvalue: 63 changevalue = downvalue 64 else: 65 changevalue = min(changevaluetemp,upvalue)##最大不超过upvalue,防止downvalue过大 66 original_ls.insert(i,round(changevalue,1)) 67 print('\033[1;31m异常数据编号为(原始值%s):%s,替换的修正值为:%s,upvalue:%s\033[0m'%(originalvalue,num_ls[i],round(changevalue,2),round(upvalue,2))) 68 69 plt.figure(figsize=(15, 8)) 70 plt.plot(list(copydata), 'y', label='原始数值') 71 plt.plot(data[1], 'r', label='拟合曲线') 72 plt.plot(data[2], 'purple', label='拟合上限(%ssigm)曲线'%mul1) 73 plt.plot(data[3], 'b', label='拟合下限(%ssigm)曲线'%mul2) 74 plt.plot(original_ls, 'g', label='处理完后的数据') 75 plt.legend(fontsize=15) 76 plt.tick_params(labelsize=15) 77 plt.xlabel('编号',fontsize=18) 78 plt.ylabel(yl,fontsize=18) 79 plt.title(tit,fontsize=20) 80 plt.show() 81 return original_ls 82 83 def check_outlier(value,mul1,mul2,yl): 84 85 print('\033[1;34m{0:*^80}\033[1;0m'.format('特征数据“%s”预处理'%yl)) 86 x = [j for j in range(len(value))] 87 coeffs = np.polyfit(x, value, 10) ##专门求多项式估计参数的函数,根据实际数据波动取相应的阶数 88 p = np.poly1d(coeffs) # 一元估计参数 89 sigm = p(x).std() 90 sigm_up = p(x) + mul1 * sigm 91 sigm_down = p(x) - mul2 * sigm 92 outliner = value[(value < sigm_down) | (value > sigm_up)]#条件筛选 93 print('\033[1;31m原数据长度:%s,异常数据:%s\033[0m'%(len(value),len(outliner))) 94 print(outliner) 95 return list(outliner),p(x),sigm_up,sigm_down,x,list(outliner.index) 96 97 col = list(res) 98 remove_ls = colstr + ['age','education-num'] 99 100 for i in remove_ls: 101 col.remove(i)##类别数据不作处理 102 for i in col:##性别和编号不做计算 103 mul1 = 500 104 mul2 = 500##由于数据很大是人为的,这里mul1和mul2参数慎改 105 res1 = check_outlier(res[i],mul1,mul2,i) 106 res2 = substitute_outliner(res1,list(res[i]),i,'“%s”数据预处理图'%i,mul1,mul2,index_ls) 107 res[i] = res2##数据替换 108 109 del res['capital-gain'] 110 del res['capital-loss'] 111 del res['education'] 112 res.to_excel('处理好的数据.xlsx') 113 114 115 data = pd.read_excel('处理好的数据.xlsx',index_col=0) 116 117 newdf1 = data[['fnlwgt','education-num','hours-per-week']].dropna() 118 print(newdf1.describe()) 119 print(newdf1.corr()) 120 121 sns.heatmap(newdf1.corr(),square = True, vmax=0.8) 122 plt.show() 123 124 ##循环绘制概率密度图 125 for i in ['fnlwgt','education-num','hours-per-week']: 126 plt.figure(figsize=(15, 8)) 127 lstemp = data[i] 128 sns.distplot(lstemp, rug=False, hist=True, bins=15) 129 plt.tick_params(labelsize=18) 130 plt.ylabel('概率密度', fontsize=18) 131 plt.xlabel(i, fontsize=18) 132 plt.title('%s的概率密度分布图'%i,fontsize=20) 133 plt.show() 134 plt.show() 135 136 # 生成数据 137 datat = pd.read_excel(path + 'income.xlsx',index_col=0) 138 datat = list(datat['race']) 139 set_ls = set(datat) 140 count_ls = [] 141 for i in set_ls: 142 count_ls.append(round(datat.count(i) / len(datat),2)) 143 labels = list(set_ls) 144 share = count_ls 145 146 # 设置分裂属性 147 explode = [0 for i in range(len(set_ls))] 148 149 # 分裂饼图 150 plt.figure(figsize=(15, 8)) 151 plt.pie(share, explode = explode, 152 labels = labels, autopct = '%3.1f%%', 153 startangle = 180, shadow = True,) 154 plt.tick_params(labelsize=20) 155 # 标题 156 plt.title('人种分布扇形图',fontsize=20) 157 plt.show() 158 159 def makefigure(xname,yname): 160 161 plt.figure(figsize=(15, 8)) 162 sns.countplot(x=xname,hue=yname, data=data) 163 plt.legend(fontsize=18) 164 plt.ylabel(yname,fontsize=18) 165 plt.xlabel(xname,fontsize=18) 166 plt.title('%s与%s关联的柱状图'%(xname,yname),fontsize=20) 167 plt.xticks((0,1),('male','female')) 168 plt.tick_params(labelsize=15) 169 plt.show() 170 171 makefigure('sex','education-num') 172 makefigure('sex','income') 173 174 data = pd.read_excel('处理好的数据.xlsx',index_col=0) 175 print(data) 176 177 178 # del data['fnlwgt']##去除“体重”变量 179 data.iloc[:,1:data.shape[1]-1] = (data.iloc[:,1:data.shape[1]-1] - data.iloc[:,1:data.shape[1]-1].min()) \ 180 / (data.iloc[:,1:data.shape[1]-1].max() - data.iloc[:,1:data.shape[1]-1].min()) 181 X = np.array(data.iloc[:,1:data.shape[1]-1])##自变量的读取 182 183 Y = np.array(data.iloc[:,data.shape[1]-1])##因变量的读取 184 dis_name = [1,2] 185 rd = 211 186 187 188 ##绘制roc图 189 def make_figure_auc_roc(true_label,score,class_): 190 plt.figure(figsize=(15, 8)) 191 192 fpr, tpr, thresholds = roc_curve(true_label,score,pos_label=class_,drop_intermediate=False) 193 ###返回的是一系列thresholds阈值 194 roc_auc = auc(fpr, tpr) 195 roc_result = pd.DataFrame({'fpr' : fpr,'tpr' : tpr, 'tf' : tpr - (1-fpr),'thresholds' : thresholds}) 196 # roc_result.iloc[(roc_result.tf-0).abs().argsort()[:1]] 197 optimal_idx = np.argmax(tpr - fpr) 198 optimal_threshold = thresholds[optimal_idx] 199 y = tpr[optimal_idx] 200 x = fpr[optimal_idx] 201 plt.figure(figsize=(8,5)) 202 plt.plot(fpr, tpr, color='navy',label='AUC=%.3f' % roc_auc) 203 plt.plot([-0.005, 1.005], [-0.005, 1.005], color='orange',linestyle='--') 204 plt.xlabel('1-特异度',fontsize=10) 205 plt.ylabel('敏感度',fontsize=10) 206 plt.scatter(x, y, c='red',s=15) 207 plt.tick_params(labelsize=12,rotation=10) 208 plt.title('ROC曲线',fontsize=12) 209 plt.legend(loc='best',fontsize=18) 210 plt.text(x+0.05,y-0.05,s='('+str(round(1-x, 3))+', '+str(round(y, 3))+')',fontsize=15) 211 plt.show() 212 return roc_auc 213 214 def cm_plot(yp, y):##混淆矩阵 215 plt.figure(figsize=(15, 8)) 216 cm = confusion_matrix(yp, y) # 混淆矩阵 217 plt.matshow(cm, cmap=plt.cm.Greens) # 画混淆矩阵图,配色风格使用cm.Greens,更多风格请参考官网。 218 plt.colorbar() # 颜色标签 219 220 for x in range(len(cm)): # 数据标签 221 for y in range(len(cm)): 222 plt.annotate(cm[x, y], xy=(x, y), horizontalalignment='center', verticalalignment='center') 223 plt.ylabel('真实标签',fontsize=10) # 坐标轴标签 224 plt.xlabel('预测标签',fontsize=10) # 坐标轴标签 225 plt.title('预测混淆矩阵图', fontsize=12) 226 plt.show() 227 228 ##自定义准确率计算 229 def show_result(dis_name, pre_ls, real_ls,rd):##准确率 230 231 ls_r = [] 232 ls_c = [] 233 for d in dis_name: 234 res_ls = [] 235 for i, j in zip(pre_ls, list(real_ls)): 236 if i == j == d: 237 res_ls.append('正确') 238 239 ls_r.append(len(res_ls) / list(real_ls).count(d)) 240 ls_c.append((len(res_ls),list(real_ls).count(d))) 241 242 print('\033[1;32m随机种子是%s时,%s(%s/%s)准确率:%.3f%%\033[0m' % (rd,d, len(res_ls), list(real_ls).count(d), len(res_ls) / list(real_ls).count(d) * 100)) 243 244 res_ls = [] 245 for i, j in zip(pre_ls, list(real_ls)): 246 if i == j: 247 res_ls.append('正确') 248 else: 249 res_ls.append('错误') 250 251 print('\033[1;31m随机种子是%s时,总预测(%s/%s)准确率:%.3f%%\033[0m' % (rd,res_ls.count('正确'), len(res_ls), res_ls.count('正确') / len(res_ls) * 100)) 252 df = pd.DataFrame([list(real_ls), pre_ls, res_ls], index=['真实', '预测', '预测结果']).T 253 allcorretrate = res_ls.count('正确') / len(res_ls) * 100 254 return df,allcorretrate 255 256 257 ##建立LR模型 258 def model(x,y,rd=rd): 259 260 xtrain, xtest, ytrain, ytest = train_test_split(x, y, test_size=0.3, random_state=rd) 261 lr = LR(solver='liblinear') # 建立逻辑回归模型 262 lr.fit(xtrain, ytrain) # 用特征数据来训练模型 263 pre_lr = lr.predict(xtest) 264 pro_lr = lr.predict_proba(xtest) 265 266 return pre_lr,ytest,pro_lr,lr.classes_[0] 267 268 print('\033[1;38m{0:*^80}\033[0m'.format('一次实验随机种子为%s的准确率汇总'%rd)) 269 270 res = model(X,Y) 271 make_figure_auc_roc(res[1], res[2][:, 0], res[3]) 272 cm_plot(res[0],res[1]) 273 show_result(dis_name,res[0],res[1],rd) 274 275 f1 = round(f1_score(res[1], res[0], average='macro'),3)##F计算 276 p = round(precision_score(res[1], res[0], average='macro'),3)##精准率计算 277 r = round(recall_score(res[1], res[0], average='macro'),3)##召回率计算 278 print(f1,p,r) 279 280 281 ##循环调用LR模型并可视化结果 282 283 def makefigure(rdls,x,y,func,dn): 284 285 plt.figure(figsize=(15, 8)) 286 print('\033[1;38m{0:*^80}\033[0m'.format('多次实验的准确率汇总')) 287 lsr = [] 288 f1_ls = [] 289 p_ls = [] 290 r_ls = [] 291 rou_ls = [] 292 for k in rdls: 293 R = func(x,y,k)##循环调用模型 294 rr = show_result(dn, R[0], R[1],k) 295 f1 = f1_score(R[1], R[0], average='macro') 296 p = precision_score(R[1], R[0], average='macro') 297 r = recall_score(R[1], R[0], average='macro') 298 roc = make_figure_auc_roc(R[1], R[2][:, 0], R[3]) 299 f1_ls.append(f1) 300 p_ls.append(p) 301 r_ls.append(r) 302 lsr.append(rr[1]) 303 rou_ls.append(roc) 304 plt.figure(figsize=(15, 8)) 305 print('\033[1;38m平均准确率:%.3f%%\033[0m'%(pd.Series(lsr).mean())) 306 print('\033[1;38m平均f1值:%.3f\033[0m' % (pd.Series(f1_ls).mean())) 307 print('\033[1;38m平均召回率值:%.3f\033[0m' % (pd.Series(p_ls).mean())) 308 print('\033[1;38m平均精准率值:%.3f\033[0m' % (pd.Series(r_ls).mean())) 309 print('\033[1;38m平均ROC值:%.3f\033[0m' % (pd.Series(rou_ls).mean())) 310 plt.plot(lsr,label='决策树多次计算结果',marker='*') 311 plt.legend(loc='best',fontsize=15) 312 plt.tick_params(labelsize=15) 313 plt.xticks([j for j in range(len(rdls))],[str(j) for j in rdls]) 314 plt.xlabel('随机种子数(%s次计算)'%len(rdls),fontsize=18) 315 plt.ylabel('准确率(%)',fontsize=18) 316 plt.show() 317 318 rand_ls = np.random.randint(0,1000,20) 319 makefigure(rand_ls,X,Y,model,dis_name)###调用函数
四、总结
主要先对数据预处理清洗,然后进行一些可视化分析,再然后我们对逻辑回归模型底层逻辑进行了一些回顾,并选择此机器学习模型,实际建模时,我们设置好模型参数,对数据进行建模和分析,最终我们给出模型的综合评价指标,做到客观科学的评价模型。
通过一系列方法运用,我们客观且科学地建立了基于人群特征数据的人群收入分类器,而且准确率还不错,这很有效地帮助我们解决在实际人群不知道是高收入还是低收入的情况下,通过模型来给出判别结果,在可视化分析阶段,我们也总结了很多人群内在信息的相关特点。
但是方法是多样的,我们可以建立深度学习模型如LSTM、CNN或者其他机器学习如支持向量机模型SVM、随机森林RF模型等等,我们同时可以对特征进行相关建模,比如更高级的特征筛选或者特征降维,这都是需要努力的方向!
标签:数据分析,plt,##,res,挖掘,ls,薪资,033,data From: https://www.cnblogs.com/msadew/p/16997312.html