机器学习 (十二)让你轻松理解K-means 聚类算法

前言

       你还记得菜市场卖菜的吗?书店卖书的或者是平时去超市买东西时的物品,它们是不是都根据相似性摆放在一起了呢,饮料、啤酒、零食分布在各自区域,像这样各级事物的相似特点或特性组织在一起的方法,在机器学习里面即成为聚类,感觉是不是很简单呢,我们先以一个实例聚类来观察一下,有一个直观的感觉。

实战-NBA球员分析

       下面我们先来看一下数据,如下图所示
《机器学习 (十二)让你轻松理解K-means 聚类算法》
player :姓名
pos :表示球员打球的位置,后卫、防守等
pts :球员总共得分
g:是打球的场次
ast :助攻数量
tov :助攻失误数量

       为了方便显示数据,我们暂且只使用这几列数据,其它数据也是可以使用的,维数太多了不方便展示,这里我们通过每位球员的平均得分和平均助攻数来作为特征衡量一个人进行聚类,意思是根据这个指标将人员进行自动分类,好比平时我们考试得分,班主任总是根据每个人的考试得分将本来就没几个人的班分为上等生、中等生、下等生,现在发现老师这么分等级是带有很大偏见的,毕竟社会考量一个人不仅仅是根据分数,而是一个人的总和能力。
平均得分(ppg) = 总得分(pts) / 打球场次(g)
平均助攻 = 总助攻(ast) / 助攻失误数量 (tov)

       以下为手动实现聚类分析的代码,实现起来还是比较简单的,第一步是随机初始化n个质心,然后不断计算每个样本点到质心的距离,不断更新质心位置,如此循环往复,直到质心不再变化为止,即达到了我们的分类效果。

# 控球控制筛选 后卫人员
point_guards = nba[nba['pos']=='PG']
# 每场球赛得分
point_guards['ppg'] = point_guards['pts'] / point_guards['g']
# 平均助攻数量
point_guards = point_guards[point_guards['tov'] != 0 ]
point_guards['atr'] = point_guards['ast'] / point_guards['tov']
散点图展示如下:
plt.scatter(point_guards['ppg'],point_guards['atr'],c='g')
plt.title('Point Guards')
plt.xlabel('Points per Game',fontsize=15)
plt.ylabel('Radio',fontsize=15)
plt.show()

打球平均得分与助攻平均数散点图如下:

《机器学习 (十二)让你轻松理解K-means 聚类算法》

# 随机初始化5个质心
num_clusters = 5
random_initial_points = np.random.choice(point_guards.index,size=num_clusters)
centroids = point_guards.loc[random_initial_points]
print centroids
# 红色显示质心
plt.scatter(point_guards['ppg'],point_guards['atr'],c='y')
plt.scatter(centroids['ppg'],centroids['atr'],c='red')
plt.title('Centroids')
plt.xlabel('Points per Game',fontsize=15)
plt.ylabel('Radio',fontsize=15)
plt.show()

红色点位随机质心,如下图:
《机器学习 (十二)让你轻松理解K-means 聚类算法》

# 计算两点之间的欧式距离
def calcuate_distance(centroid,player_values):
    root_distance = 0

    for x in range(0,len(centroid)):
        difference = centroid[x] - player_values[x]
        squared_difference = difference**2
        root_distance+= squared_difference

    euclid_distance = math.sqrt(root_distance)
    return euclid_distance
# 循环更新每点到质心的距离,选取最近的质心
def assigin_to_cluster(row):
    lowest_distance = -1
    closest_cluster = -1

    for cluster_id,centroid in centroids_dict.items():
        df_row = [row['ppg'],row['atr']]
        euclidean_distance = calcuate_distance(centroid,df_row)

        if (lowest_distance == -1):
            lowest_distance=euclidean_distance
            closest_cluster=cluster_id
            print closest_cluster
        elif (euclidean_distance < lowest_distance):
            lowest_distance = euclidean_distance
            closet_cluster = cluster_id

    return closest_cluster

point_guards['cluster'] = point_guards.apply(lambda row : assigin_to_cluster(row),axis=1)

# 显示聚类后的数据点
def visualize_clusters(df,num_clusters):
    colors = ['b','g','r','c','m','y']

    print num_clusters
    for n in range(num_clusters):
        clustered_df = df[df['cluster'] == n]
        print colors[n-1]
        plt.scatter(clustered_df['ppg'],clustered_df['atr'],c=colors[n-1])
        plt.xlabel('Points per Game',fontsize=15)
        plt.ylabel('Assist tur ratio',fontsize=15)
    plt.show()

visualize_clusters(point_guards,5)

聚类效果如下图所示:
《机器学习 (十二)让你轻松理解K-means 聚类算法》

       上面是手动生成聚类算法的代码,其实很多库已经帮我们写好了,如很流行的sklearn 、tensorflow ,在性能和稳定性上都比我们自己写的好,没必要自己造轮子,sklearn代码如下:

# 引入sklearn框架
from sklearn.cluster import KMeans
# 初始化kmeans模型
kmeans = KMeans(n_clusters=num_clusters)
# 输入数据训练 
kmeans.fit(point_guards[['ppg','atr']])
# 更新数据的簇标签
point_guards['cluster']=kmeans.labels_
# 展示数据
visualize_clusters(point_guards,num_clusters)

       是不是觉的使用框架简单了好多,框架使得我们的工作重心从写繁琐的算法代码转移到了模型调参、数据特征分析上面,可以让我们事半功倍,一马平川,但这也并不是不用去关心算法内部实现以及原理,知道了算法原理有助于我们更好的理解模型参数,我们才知道如何去调节参数,两者相辅相成,缺一不可。

优缺点

数据需要标准化处理,否则各维度计算的欧式距离可能差异比较大
因为质心随机生成,生成结果不稳定,多次运行结果可能不一样
维数过多后欧式距离可能不准,需要衡量距离算法
易于理解,和knn类似都是思路简单,容上上手,运行速度快

优化问题

k值如何选择?

k值是我们设计者自己设定的值,依赖于设计者的经验水平,不同的人经验不同给出来的值可能也不一样,那么主观随意性就比较大,如果是研究可以,但是在工程上这种主观是不好的,效率不高,还是那句话我们不能重复造轮子,最好站在巨人肩膀上,登高而呼。

  • 数据的先验知识 也即人的主观性
  • 基于变化的算法:即定义一个函数,随着K的改变,认为在正确的K时会产生极值
  • 基于层次聚类:即基于合并或分裂的思想,在一定情况下停止从而获得K
  • 基于一致性矩阵的算法:即认为在正确的K时,不同次聚类的结果会更加相似,以此确定K

距离计算方法?

每种距离的计算方式都有自己的限制,再具体使用中需要结合样本的特点和场景不同合理选择描述样本之间相似性的算法,在这里我们说一下常见的几种算法。
《机器学习 (十二)让你轻松理解K-means 聚类算法》

  • 欧氏距离
    上面公式是一个通用公式,当p=2时即欧式距离,欧氏距离是我们最常用的距离计算方式,也成为几何距离,表示两个点的距离差平方和,简单直观

  • 曼哈顿距离
    当p=1时表示这个距离,计算的是两个点之间的实地走的距离,欧式距离时两点之间的空间直线距离,不考虑其它影响

  • 切比雪夫距离
    当p趋于无穷大时,公式如下:
    《机器学习 (十二)让你轻松理解K-means 聚类算法》

  • 向量內积
    向量的內积在很多场合都在使用,向量內积是在向量空间里面,公式如下:
    《机器学习 (十二)让你轻松理解K-means 聚类算法》
    內积的结果是一个标量,大小没有限制,上下没有界限因此不好表示两个向量的相关性,于是有人提出来使用余弦来表示相似性,它有大小限制容易表示相似性。
    《机器学习 (十二)让你轻松理解K-means 聚类算法》

其它典型场景

  • 基于用户位置信息的商业选址
    意思是对用户的住址等位置聚类,通过聚类结果来选择商铺位置,比如你打算开一个饭店当然是开在人多的地方最好了,最好距离每一个客户位置都近,这样来的人也就多啦
  • 图像分割
    这一应用在进行分析图片时非常重要,解析图片内容,自动驾驶里面让计算机读懂图片是很重要的,影响着汽车判断
  • 保险投保者分组
  • 新闻分类
    如今日头条自动分类
  • 国家电网用户画像
    有助于挖掘有价值的客户信息,为营销、推广打下基础

思考题

1.为什么要有向量内积?向量內积的意义?
2.方差-聚类关系?

总结

       用一句话总结一件事才说名懂了,大道至简是自然规律,用一句话来描述聚类即 选定一个对象相似规则,不断更新质心,直至稳定。

题外思考

什么限制了我们的创造性?
       你是否思考过是什么限制了我们人的创造性呢?本科、研究生、还有博士水平可以说逐渐增高,对知识的理解和运用能力也是处于高层次阶段,拥有了大量专业水平可还是没有创造力,究其原因再加上思考,发现创造性是和知识量的积累没有必然联系,但大量的知识积累是创造的基础。
       对世界的认知限制了我们的创造性,如果大家不相信,请思考一个问题,π(pai) 是什么?
       当你接收身边任何事物时,别人告诉你了或你从书本上面得来的,都欣然接收了,但是没有思考其根源,具有推本溯源的意识,当你背诵乘法口诀、加法口诀时是否有疑问?1+1 为什么等于2? 1 又是什么,如果这个问题你想不清楚,那么如何创造出来更多的数字,要知道人类社会1出现在现代文明当中也就几百年 几代人而已,所谓科学家即推本溯源 追求真理的人,所谓真理即他创造出来被人们所接受的、对社会有意义东西。

参考资料:
1.https://zhuanlan.zhihu.com/p/27518705
2.https://zhuanlan.zhihu.com/p/30221347
3.https://zhuanlan.zhihu.com/p/34330242
4.https://zhuanlan.zhihu.com/p/20432322
5.https://blog.csdn.net/jbfsdzpp/article/details/48497347
6.http://www.cnblogs.com/daniel-D/p/3244718.html
7.https://zhuanlan.zhihu.com/p/24546995
8.https://zhuanlan.zhihu.com/p/20912337
9.https://blog.csdn.net/liulingyuan6/article/details/53637812

    原文作者:聚类算法
    原文地址: https://blog.csdn.net/jiaolong724/article/details/80144000
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞