机器学习简易入门(三) - 聚类
摘要:本文简单叙述了如何用聚类来通过投票记录分析美国参议员的实际政治倾向
声明:(本文的内容非原创,但经过本人翻译和总结而来,转载请注明出处)
本文内容来源:https://www.dataquest.io/mission/60/clustering-basics
在前面的两篇文章中使用的线性回归和分类都属于有监督的机器学习(根据已有的数据训练模型,然后预测未知的数据),而无监督的学习则不是尝试预测任何东西,而是寻找数据中的特征,在无监督学习中,有一个重要的方法称为聚类。聚类算法是把具有相同特征的数据聚集在一组。
原始数据展现
在美国的参议院要通过一项法律时,需要由参议员来投票,而这些议员主要来自于两个政党,共和党(Democrats)和民主党(Republicans),现在使用的数据就是这些议员的投票记录,每一行代表了一个议员的情况(party – 所属政党,D代表共和党,R代表民主党,I代表无党派, 第三列之后都代表了某一个法案的投票情况,1代表赞成,0代表反对,0.5代表弃权)
import pandas votes = pandas.read_csv('114_congress.csv')
统计一下每个政党的人数
print(votes["party"].value_counts())
聚类算法
计算距离
为了把具有相同特征的议员聚集在一组,就需要衡量两个议员的特征究竟有多么的接近,在这里使用的是欧几里德距离计算公式
譬如取前两个议员的记录来进行计算,这是他们的投票结果:
计算结果:d = 1.73
在python中计算欧几里德距离,可以通过scikit-learn库的euclidean_distances()方法,现在仍然计算前两个议员的距离
from sklearn.metrics.pairwise import euclidean_distances print(euclidean_distances(votes.iloc[0,3:], votes.iloc[1,3:])) # 因为前三列不是数字类型,所以要排除前三列的数据
聚类
接下来会使用k-means聚类算法来根据欧几里德距离来将数据进行分组聚集,每一组都会有一个中心点,然后计算每个议员到这个中心点的距离,再将该议员分配到距离最小的那个中心点所属的组中。下面使用scikit-learn库来训练一个k-means模型(因为主要有两个政党,所以分为两组即可)
import pandas as pd from sklearn.cluster import KMeans # n_clusters参数指定分组数量,random_state = 1用来重现同样的结果 kmeans_model = KMeans(n_clusters=2, random_state=1) # 通过fit_transform()方法来训练模型 senator_distances = kmeans_model.fit_transform(votes.iloc[:, 3:])
生成的是一个ndarray,每一行代表了一个议员,第一列代表了该议员与第一组中心点的距离,第二列代表了该议员与第二组中心点的距离
统计
经过上面的计算,现在要统计在每一组中究竟分布着多少个来自于不同政党的议员(类似于透视图),使用Pandas中的crosstab()方法可以进行统计,该方法需要两个向量或者Series作为参数来进行统计
labels = kmeans_model.labels_ print(pd.crosstab(labels, votes["party"]))
上面语句中的labels变量的结果如下:(在ndarray中的每个元素代表了一个议员所属的组编号,其编号取其距离最小的那组)
上面的结果显示,第一组包含了41个民主党议员和两个无党派议员,第二组包含了3个民主党议员和54个共和党议员,看起来有3个民主党议员的政治倾向更偏于共和党,而这三位仁兄就是
democratic_outliers = votes[(labels == 1) & (votes["party"] == "D")]
数据可视化
在上面的计算中,已经把每位议员到两个组的举例计算出来了,现在将这两个距离数据分别作为x和y坐标,然后做一个散点图,并且根据它们的组编号进行不同着色
plt.scatter(x=senator_distances[:,0], y=senator_distances[:,1], c=labels)
plt.show()
寻找激进分子
可以根据上面计算的每个议员与组的距离来判断一个议员是否属于激进分子,最激进的议员就是那些远离一个组中心点最远的数据点,而处于两个中心点的数据点则表明这是比较温和的议员。要衡量这个激进程度,可以通过对两个距离计算结果进行指数运算来放大差异性。例如对于某个激进议员extremist = [3.4, .24]和温和议员moderate = [2.6, 2],如果只是简单相加其结果,就会得到3.4 + .24 = 3.64, 和2.6 + 2 = 4.6,看起来他们之间的差距并不大。然而,将它们分别进行立方运算再相加3.4 ** 3 + .24 ** 3 = 39.3, 和2.6 ** 3 + 2 ** 3 = 25.5,就能体现他们之间的差异性了
extremism = (senator_distances ** 3).sum(axis=1) votes["extremism"] = extremism votes.sort("extremism", inplace=True, ascending=False) # 根据激进性进行降序排序
总结
聚类是一个用来寻找数据特征的强有力的方法,在使用有监督的机器学习方法并没有取得进展时,可以尝试使用无监督的学习方法,通常来说,在使用有监督学习方法之前先使用无监督学习方法是一个不错的开始。