天天看点

Kaggle实战——Gender Recognition by Voice声音的性别区分(结构化数据)(一)

Kaggle实战——Gender Recognition by Voice声音的性别区分(结构化数据)(一)

这是以前的一次小组期末作业(

Kaggle实战——Gender Recognition by Voice声音的性别区分(结构化数据)(一)

当然编程部分都是我独立完成),写在这里也当做记录一下,顺便复习一下python和常用的机器学习算法吧。在进行数据分析时候第一件事情就是......数据集的查找........无论对于新手还是老手来说,Kaggle都是一个很好的数据平台,新手直接上手以前的玩具数据,至于老手可以直接对新数据进行比赛.......可以的话还可以混点奖金什么的(虽然哥从没得过奖)。这次的数据属于“玩具数据”级别,识别率能够比较容易达到95%以上(成就感满满的!),对于入门来说,已经完全足够了。理论上只要满足下面的编程所需环境,是可以非常容易进行复现的。

数据集下载地址:https://www.kaggle.com/primaryobjects/voicegender

编程所用的环境:python——3.6.4

Python所需的库以及版本号:Matplotlib——2.1.2,Pandas——0.22.0,Sklearn——0.19.1

这里先介绍点简单的知识:

一般数据处理的流程是:

数据获取——数据探索——数据预处理——建模——验证和测试——模型的改善

值得强调的是,数据预处理是其中最繁琐和苦恼的地方,一来它不像建模那样有挑战性和成就感,二来需要花费极其大量的时间(按照教科书上的所讲是花70%左右,自己经过几次数据处理发现也接近这个水平),但确实数据决定成败的关键所在,稍有不慎就会使得 后面的建模部分大打折扣(例子后面会讲)。因此希望各位入门数据分析的要多加留意和重视。

废话不多,直接开始。

数据获取:

这里的获取非常简单,直接在上文下载即可,当然,实际中往往需要我们进行爬虫,调研获取什么的(这也是最近爬虫招得特别多的原因)。不在本文的考虑范围之内。

数据探索:

简单就是看看数据的变量是什么,有没有缺失值啊,缺失值的情况怎样啊。新手入门往往不管数据的类型那些,直接一股脑地丢进模型里面,但是在实际应用中,特别是在经济学的领域中,变量的解释性往往十分重要,因此,即使是只做分析不涉及具体的业务,请务必养成观看变量类型和含义的习惯。

首先我们得知道他们每个变量所在的位置和含义:

https://www.kaggle.com/primaryobjects/voicegender

这里在下载页面有较为详细的介绍,我们也可以知道,这里总共有21个变量,其中前20个是自变量,最后一个则是因变量。

当然如果感觉英语较为吃力,当时我们小组非常贴心的把它们翻译成了中文,可以看一下:

Kaggle实战——Gender Recognition by Voice声音的性别区分(结构化数据)(一)

由于此blog侧重分析而不是应用,因此其具体意义不再细讲(工科声学大佬会比我这个理科渣渣好n倍),这里只是为了后续说明一点,以上的值在理论中是不会出现数字0的(例如声频不可能为负),而接下来我们进行缺失值的探索要充分用到这一性质,因为对缺失值的标注并没有固定的格式(有也没啥人遵守),有的数据中使用NA作为缺失值(如程序语言中),有的直接为空,有的用用0(无语ing

Kaggle实战——Gender Recognition by Voice声音的性别区分(结构化数据)(一)

)。而在这里给出的数据中,则是以0作为缺失值进行标注的。

因此,在查看缺失值的时候我们可以直接使用EXCEL(COUNTIF)函数进行查看变量缺失值的严重情况。其结果如下:

Kaggle实战——Gender Recognition by Voice声音的性别区分(结构化数据)(一)

数据预处理:

数据预处理(data preprocessing)是指在主要的处理以前对数据进行的一些处理。包括变量变换,离散化,缺失值填补,特征选取,异常值检测等多个方面。是决定后面数据建模至关重要的部分。

数据预处理的重要性 

1)数据预处理可以去掉数据中的噪声 (eg.领导讲话)

2)纠正不正确的属性值(人机输入时错误 )

3)对于不一致的数据进行清理(填写缺失值、光滑噪声数据、识别删除离群点)

4)数据预处理可以提高数据挖掘的效率(压缩数据集不损害数据挖掘结果)

事实上上述处理的选择更多凭借的是行业经验进行选取,例如,用什么来填补缺失值,是否要进行离散化,在不同类型的数据乃至相同类型的数据中都没有一个绝对明确的标准(有的话众多数据分析师可以直接失业,一个程序员编写一堆if-else函数即可搞定)。由于这个属于玩具数据的类型,因此,上述部分只处理必须处理的步骤。在本文中,我们使用python的pandas包对数据进行处理:

import pandas as pd
voice_data=pd.read_csv('voice.csv')
x=voice_data.iloc[:,:-1]
y=voice_data.iloc[:,-1]
           

对于y而言,本身只有male和female两个属性,因此,我们使用一个0-1变量(哑变量)进行替代。在python中,使用sklearn包即可解决,若是属性多于两个,则可以考虑使用one-hot编码:

from sklearn.preprocessing import LabelEncoder
y = LabelEncoder().fit_transform(y)
           

我们首先处理缺失值,由上文中的数据探索中我们可以发现,缺失值的占比很少,总共只有3个变量有缺失值,而总的来说所占比例不高,因此,在这里使用均值进行缺失值的填补:

from sklearn.preprocessing import  Imputer 
imp=Imputer(missing_values=0,strategy='mean',axis=0)  
x=imp.fit_transform(x) 
           

此外,因为数据前半部分全是y=1(male),后半部分y=0(female),同时,也要划分好训练集和测试机。因此要对其进行打乱操作:

from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3)
           

值得注意的是,我们在建模的过程中往往会忽略对数据进行归一化(也可以说是标准化进行处理),而实际中,不进行此处理会使得收敛过程变得非常困难,特别对于神经网络中和SVM中尤为困难。事实上,在此模型中,若不适用归一化其准确率仅有80%,而使用归一化后则能达到95%以上的精度。另外,以为这里的训练集和测试集是我们人为进行划分,所以常常会不经意把整个模型进行归一化,但是,在实际应用中,测试集或者测试样本我们往往是未知的,因此,归一化所要用到的均值和方差仅能使用训练集,或者是已经检验过的测试集+训练集,而不能代入未来因子,在sklearn中,这点可以很容易实现:

from sklearn.preprocessing import StandardScaler
scaler1 = StandardScaler()
scaler1.fit(x_train)
x_train = scaler1.transform(x_train)
x_test = scaler1.transform(x_test)
           

建模:

在数据处理中,新手往往觉得建模过程是最困难的,但实际中,如果仅使用成熟的方法进行建模,这一步往往是最为简单的一步(比起之前预处理的准备步骤不要太过简单)。因为成熟模型往往都具有很强的通用性,网上已经有足够多的大牛把它们写成简单易懂的接口,简单到甚至你可以理论完全不懂都可以进行使用,而最近几年的兴起的深度模型,还有十几年前很火的SVM这些,基本属于黑箱模型类别,即使能解释,也是要解释半天的那种(事实上我就没见过有人会解释神经网络,更别说深度学习了)。因此,真正牛逼的数据分析师,往往是能用超级简单的模型来简述很复杂的问题。

本实验主要运用了六种经典的分类模型对语音性别数据集进行建模,六种算法分类算法分别是 Logistic 分类器、人工神经网络、分类树(Cart 算法)、随机森林、支持向量机(SVM)和 KNN 分类器。接下来我们将逐一说明各个分类模型的具体参数设置。 

Logistic 分类器:

Logistic 回归可以理解为一个 2 层的神经网络,其激活函数为 sigmoid。因此,在建模的过程中,为了保证能够得到收敛,在此将其最大迭代次数设置为10000 。其使用代码为:

from sklearn.linear_model import LogisticRegression 
logistic=LogisticRegression(max_iter=10000) 
logistic.fit(x_train,y_train)
           

神经网络:

神经网络可以看成 Logistics 的升级版本,为了尽量避免出现梯度消失和梯度爆炸的问题,在这里我们使用三层的神经网络即可。输入和输出层的个数由数据输入和输出确定,而隐藏层的结点个数则是一个超参数的选择问题。经过多次试验,我们发现,使用默认的设置,即隐藏层的结点个数为 100 时即可达到很不错的效果。同时,由于神经网络的计算量远高于 Logistics 回归,因而在这里我们设置其最大迭代次数为 Logistics 的 10 倍,即 100000。此外,为了防止过拟合现象的出现,我们使用 L2 正则化(即其默认选择)。

from sklearn.neural_network import MLPClassifier 
nn=MLPClassifier(max_iter=100000) 
nn.fit(x_train,y_train)
           

分类树(Cart 算法):

Cart 算法是决策树中非常常用的算法,其衡量标准是基尼系数。在 sklearn实现中,并 没 有 直 接 使 用 Cart 算 法 的 方 法 。 因 此 , 我 们 使 用sklearn.tree.DecisionTreeClassifier 中将其指标设定成和 Cart 一样即可,经过搜索发现,其默认的配置即跟 Cart 算法相差无几,因此我们将其进行调用。由于在后续的模型评价中发现其过拟合现象并不严重,在此并不进行常用的剪树处理。

from sklearn.tree import DecisionTreeClassifier 
cart=DecisionTreeClassifier() 
cart.fit(x_train,y_train)
           

随机森林:

随机森林为集成学习 bagging 中使用决策树的一种。可以简单理解为使用多棵决策树进行模型提升。在这里,我们选用的决策树类型为 Cart 算法得出的决策树,使用 10 棵决策树进行模型的提升。 

from sklearn.ensemble import RandomForestClassifier 
rf=RandomForestClassifier(n_estimators=10,criterion=”gini”) 
rf.fit(x_train,y_train)
           

SVM:

 SVM 可以理解为将样本映射到高维空间中将其线性可分同时取其分类间隔的分类方法。在实际使用中,其超参数选择就是其松弛变量系数和核函数。在此,我们使用径向基核函数,其松弛变量系数设为 1 即可达到很好的效果。此外,由于需要最后进 ROC-AUC 曲线的筛选,因此在此我们要是其 probability=True 以保证能返回概率。

from sklearn.svm import SVC 
svc=SVC(C=1,kernel=’rbf’, probability=True) 
svc.fit(x_train,y_train) 
           

KNN 算法 :

KNN 是一种机械学习方式。在数据量不大的情况下往往能得到很好的表现。在 KNN 中,对超参数的选择主要是相邻结点决定分类的个数以及距离的计算公式。因为我们的模型实现了标准化,因此,其距离选用常规的欧式距离即可。其个数经过尝试后发现使用其默认的 n_neighbors=5 即可达到非常不错的效果。 

from sklearn.neighbors import KNeighborsClassifier 
knn=KNeighborsClassifier() 
knn.fit(x_train,y_train) 
           

验证和测试:

这里的验证和测试与上面的数据划分息息相关,最常用的方法就是向上文那样划分出训练集和验证集,当然也有另一种分法:训练集:验证集:测试集,而因为在这里我们仅需判断上述建模哪个好,不需要对模型进行一个无偏的估计,因此,不必进行测试集的划分。因为上文已经使用sklearn中把模型fit进去了,此时把他应用在具体的数据集上,值得注意的是,除了验证验证集的数据外,也要同时看看训练集上的数据,已便偏差和方差分析即可:

from sklearn import metrics

y_train_result=cart.predict(x_train)
print('cart train Accuracy Score:')
print(metrics.accuracy_score(y_train_result,y_train))
y_pred=cart.predict(x_test)
print('cart test Accuracy Score:')
print(metrics.accuracy_score(y_test,y_pred))
print('\n')

y_train_result=svc.predict(x_train)
print('svc train Accuracy Score:')
print(metrics.accuracy_score(y_train_result,y_train))
y_pred=svc.predict(x_test)
print('svm test Accuracy Score:')
print(metrics.accuracy_score(y_test,y_pred))
print('\n')

y_train_result=logistic.predict(x_train)
print('logistic train Accuracy Score:')
print(metrics.accuracy_score(y_train_result,y_train))
y_pred=svc.predict(x_test)
print('logistic test Accuracy Score:')
print(metrics.accuracy_score(y_test,y_pred))
print('\n')

y_train_result=knn.predict(x_train)
print('knn train Accuracy Score:')
print(metrics.accuracy_score(y_train_result,y_train))
y_pred=knn.predict(x_test)
print('knn test Accuracy Score:')
print(metrics.accuracy_score(y_test,y_pred))
print('\n')

y_train_result=nn.predict(x_train)
print('nn train Accuracy Score:')
print(metrics.accuracy_score(y_train_result,y_train))
y_pred=nn.predict(x_test)
print('nn test Accuracy Score:')
print(metrics.accuracy_score(y_test,y_pred))
print('\n')

y_train_result=rf.predict(x_train)
print('rf train Accuracy Score:')
print(metrics.accuracy_score(y_train_result,y_train))
y_pred=rf.predict(x_test)
print('rf test Accuracy Score:')
print(metrics.accuracy_score(y_test,y_pred))
           

输出结果如下:

cart train Accuracy Score:
1
cart test Accuracy Score:
0.96424816

svc train Accuracy Score:
0.9864682
svm test Accuracy Score:
0.975814932

logistic train Accuracy Score:
0.974289581
logistic test Accuracy Score:
0.975814932

knn train Accuracy Score:
0.9864682
knn test Accuracy Score:
0.965299685

nn train Accuracy Score:
0.9864682
nn test Accuracy Score:
0.972660358

rf train Accuracy Score:
0.99954894
rf test Accuracy Score:
0.974763407
           

我们可以看到,在训练集和测试集上我们的精度已经轻松的达到了95%以上,由于对cart树并没有采用剪枝的方法,出现了一些过拟合现象,但并不严重,因此无需对其进行后剪枝的方法。当然,对其验证和测试,以及模型的优化并没有结束。有兴趣的童鞋可以继续看:

Kaggle实战——Gender Recognition by Voice声音的性别区分(结构化数据)(二)