CategoryResourceRepost/极客时间专栏/数据分析实战45讲/第二模块:数据分析算法篇/26丨K-Means(上):如何给20支亚洲球队做聚类?.md
louzefeng d3828a7aee mod
2024-07-11 05:50:32 +00:00

199 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<audio id="audio" title="26丨K-Means如何给20支亚洲球队做聚类" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/bc/86/bc32d39df47bfa5cc044cd9c2a778886.mp3"></audio>
今天我来带你进行K-Means的学习。K-Means是一种非监督学习解决的是聚类问题。K代表的是K类Means代表的是中心你可以理解这个算法的本质是确定K类的中心点当你找到了这些中心点也就完成了聚类。
那么请你和我思考以下三个问题:
<li>
如何确定K类的中心点
</li>
<li>
如何将其他点划分到K类中
</li>
<li>
如何区分K-Means与KNN
</li>
如果理解了上面这3个问题那么对K-Means的原理掌握得也就差不多了。
先请你和我思考一个场景假设我有20支亚洲足球队想要将它们按照成绩划分成3个等级可以怎样划分
## K-Means的工作原理
对亚洲足球队的水平,你可能也有自己的判断。比如一流的亚洲球队有谁?你可能会说伊朗或韩国。二流的亚洲球队呢?你可能说是中国。三流的亚洲球队呢?你可能会说越南。
其实这些都是靠我们的经验来划分的,那么伊朗、中国、越南可以说是三个等级的典型代表,也就是我们每个类的中心点。
所以回过头来如何确定K类的中心点一开始我们是可以随机指派的当你确认了中心点后就可以按照距离将其他足球队划分到不同的类别中。
这也就是K-Means的中心思想就是这么简单直接。你可能会问如果一开始选择一流球队是中国二流球队是伊朗三流球队是韩国中心点选择错了怎么办其实不用担心K-Means有自我纠正机制在不断的迭代过程中会纠正中心点。中心点在整个迭代过程中并不是唯一的只是你需要一个初始值一般算法会随机设置初始的中心点。
好了那我来把K-Means的工作原理给你总结下
<li>
选取K个点作为初始的类中心点这些点一般都是从数据集中随机抽取的
</li>
<li>
将每个点分配到最近的类中心点这样就形成了K个类然后重新计算每个类的中心点
</li>
<li>
重复第二步,直到类不发生变化,或者你也可以设置最大迭代次数,这样即使类中心点发生变化,但是只要达到最大迭代次数就会结束。
</li>
## 如何给亚洲球队做聚类
对于机器来说需要数据才能判断类中心点所以我整理了2015-2019年亚洲球队的排名如下表所示。
我来说明一下数据概况。
其中2019年国际足联的世界排名2015年亚洲杯排名均为实际排名。2018年世界杯中很多球队没有进入到决赛圈所以只有进入到决赛圈的球队才有实际的排名。如果是亚洲区预选赛12强的球队排名会设置为40。如果没有进入亚洲区预选赛12强球队排名会设置为50。
<img src="https://static001.geekbang.org/resource/image/d8/4a/d8ac2a98aa728d64f919bac088ed574a.png" alt=""><br>
针对上面的排名,我们首先需要做的是数据规范化。你可以把这些值划分到[0,1]或者按照均值为0方差为1的正态分布进行规范化。具体数据规范化的步骤可以看下13篇也就是[数据变换](https://time.geekbang.org/column/article/77059)那一篇。
我先把数值都规范化到[0,1]的空间中,得到了以下的数值表:
<img src="https://static001.geekbang.org/resource/image/a7/17/a722eeab035fb13751a6dc5c0530ed17.png" alt=""><br>
如果我们随机选取中国、日本、韩国为三个类的中心点,我们就需要看下这些球队到中心点的距离。
距离有多种计算的方式有关距离的计算我在KNN算法中也讲到过
<li>
欧氏距离
</li>
<li>
曼哈顿距离
</li>
<li>
切比雪夫距离
</li>
<li>
余弦距离
</li>
欧氏距离是最常用的距离计算方式这里我选择欧氏距离作为距离的标准计算每个队伍分别到中国、日本、韩国的距离然后根据距离远近来划分。我们看到大部分的队会和中国队聚类到一起。这里我整理了距离的计算过程比如中国和中国的欧氏距离为0中国和日本的欧式距离为0.732003。如果按照中国、日本、韩国为3个分类的中心点欧氏距离的计算结果如下表所示
<img src="https://static001.geekbang.org/resource/image/b6/e9/b603ccdb93420c8455aea7278efaece9.png" alt=""><br>
然后我们再重新计算这三个类的中心点,如何计算呢?最简单的方式就是取平均值,然后根据新的中心点按照距离远近重新分配球队的分类,再根据球队的分类更新中心点的位置。计算过程这里不展开,最后一直迭代(重复上述的计算过程:计算中心点和划分分类)到分类不再发生变化,可以得到以下的分类结果:
<img src="https://static001.geekbang.org/resource/image/12/98/12c6039884ee99742fbbebf198425998.png" alt=""><br>
所以我们能看出来第一梯队有日本、韩国、伊朗、沙特、澳洲;第二梯队有中国、伊拉克、阿联酋、乌兹别克斯坦;第三梯队有卡塔尔、泰国、越南、阿曼、巴林、朝鲜、印尼、叙利亚、约旦、科威特和巴勒斯坦。
## 如何使用sklearn中的K-Means算法
sklearn是Python的机器学习工具库如果从功能上来划分sklearn可以实现分类、聚类、回归、降维、模型选择和预处理等功能。这里我们使用的是sklearn的聚类函数库因此需要引用工具包具体代码如下
```
from sklearn.cluster import KMeans
```
当然K-Means只是sklearn.cluster中的一个聚类库实际上包括K-Means在内sklearn.cluster一共提供了9种聚类方法比如Mean-shiftDBSCANSpectral clustering谱聚类等。这些聚类方法的原理和K-Means不同这里不做介绍。
我们看下K-Means如何创建
```
KMeans(n_clusters=8, init='k-means++', n_init=10, max_iter=300, tol=0.0001, precompute_distances='auto', verbose=0, random_state=None, copy_x=True, n_jobs=1, algorithm='auto')
```
我们能看到在K-Means类创建的过程中有一些主要的参数
<li>
**n_clusters**: 即K值一般需要多试一些K值来保证更好的聚类效果。你可以随机设置一些K值然后选择聚类效果最好的作为最终的K值
</li>
<li>
**max_iter** 最大迭代次数,如果聚类很难收敛的话,设置最大迭代次数可以让我们及时得到反馈结果,否则程序运行时间会非常长;
</li>
<li>
**n_init**初始化中心点的运算次数默认是10。程序是否能快速收敛和中心点的选择关系非常大所以在中心点选择上多花一些时间来争取整体时间上的快速收敛还是非常值得的。由于每一次中心点都是随机生成的这样得到的结果就有好有坏非常不确定所以要运行n_init次, 取其中最好的作为初始的中心点。如果K值比较大的时候你可以适当增大n_init这个值
</li>
<li>
**init** 即初始值选择的方式默认是采用优化过的k-means++方式你也可以自己指定中心点或者采用random完全随机的方式。自己设置中心点一般是对于个性化的数据进行设置很少采用。random的方式则是完全随机的方式一般推荐采用优化过的k-means++方式;
</li>
<li>
**algorithm**k-means的实现算法有“auto” “full”“elkan”三种。一般来说建议直接用默认的"auto"。简单说下这三个取值的区别,如果你选择"full"采用的是传统的K-Means算法“auto”会根据数据的特点自动选择是选择“full”还是“elkan”。我们一般选择默认的取值即“auto” 。
</li>
在创建好K-Means类之后就可以使用它的方法最常用的是fit和predict这个两个函数。你可以单独使用fit函数和predict函数也可以合并使用fit_predict函数。其中fit(data)可以对data数据进行k-Means聚类。 predict(data)可以针对data中的每个样本计算最近的类。
现在我们要完整地跑一遍20支亚洲球队的聚类问题。我把数据上传到了[GitHub](https://github.com/cystanford/kmeans)上,你可以自行下载。
```
# coding: utf-8
from sklearn.cluster import KMeans
from sklearn import preprocessing
import pandas as pd
import numpy as np
# 输入数据
data = pd.read_csv('data.csv', encoding='gbk')
train_x = data[[&quot;2019年国际排名&quot;,&quot;2018世界杯&quot;,&quot;2015亚洲杯&quot;]]
df = pd.DataFrame(train_x)
kmeans = KMeans(n_clusters=3)
# 规范化到[0,1]空间
min_max_scaler=preprocessing.MinMaxScaler()
train_x=min_max_scaler.fit_transform(train_x)
# kmeans算法
kmeans.fit(train_x)
predict_y = kmeans.predict(train_x)
# 合并聚类结果,插入到原数据中
result = pd.concat((data,pd.DataFrame(predict_y)),axis=1)
result.rename({0:u'聚类'},axis=1,inplace=True)
print(result)
```
运行结果:
```
国家 2019年国际排名 2018世界杯 2015亚洲杯 聚类
0 中国 73 40 7 2
1 日本 60 15 5 0
2 韩国 61 19 2 0
3 伊朗 34 18 6 0
4 沙特 67 26 10 0
5 伊拉克 91 40 4 2
6 卡塔尔 101 40 13 1
7 阿联酋 81 40 6 2
8 乌兹别克斯坦 88 40 8 2
9 泰国 122 40 17 1
10 越南 102 50 17 1
11 阿曼 87 50 12 1
12 巴林 116 50 11 1
13 朝鲜 110 50 14 1
14 印尼 164 50 17 1
15 澳洲 40 30 1 0
16 叙利亚 76 40 17 1
17 约旦 118 50 9 1
18 科威特 160 50 15 1
19 巴勒斯坦 96 50 16 1
```
## 总结
今天我给你讲了K-Means算法原理我们再来看下开篇我给你提的三个问题。
如何确定K类的中心点其中包括了初始的设置以及中间迭代过程中中心点的计算。在初始设置中会进行n_init次的选择然后选择初始中心点效果最好的为初始值。在每次分类更新后你都需要重新确认每一类的中心点一般采用均值的方式进行确认。
如何将其他点划分到K类中这里实际上是关于距离的定义我们知道距离有多种定义的方式在K-Means和KNN中我们都可以采用欧氏距离、曼哈顿距离、切比雪夫距离、余弦距离等。对于点的划分就看它离哪个类的中心点的距离最近就属于哪一类。
如何区分K-Means和KNN这两种算法呢刚学过K-Means和KNN算法的同学应该能知道两者的区别但往往过了一段时间就容易混淆。所以我们可以从三个维度来区分K-Means和KNN这两个算法
<li>
首先这两个算法解决数据挖掘的两类问题。K-Means是聚类算法KNN是分类算法。
</li>
<li>
这两个算法分别是两种不同的学习方式。K-Means是非监督学习也就是不需要事先给出分类标签而KNN是有监督学习需要我们给出训练数据的分类标识。
</li>
<li>
最后K值的含义不同。K-Means中的K值代表K类。KNN中的K值代表K个最接近的邻居。
</li>
<img src="https://static001.geekbang.org/resource/image/eb/c5/eb60546c6a3d9bc6a1538049c26723c5.png" alt=""><br>
那么学完了今天的内容后你能说一下K-Means的算法原理吗如果我们把上面的20支亚洲球队用K-Means划分成5类在规范化数据的时候采用标准化的方式即均值为0方差为1该如何编写程序呢运行的结果又是如何
欢迎你在评论区与我分享你的答案,也欢迎点击“请朋友读”,把这篇文章分享给你的朋友或者同事。