本篇探讨文本型数据如何进行K-means聚类。

我们分为以下几个步骤来进行:

1、输入各文档数据

2、切词

3、整合文档

4、计算tf-idf权重矩阵

5、取K值,进行K-means聚类

6、判断聚类效果

首先,我们一起来看看dog&cat爱情故事的聚类情况是怎样!以下是文档的数据:

第一份txt : i love dog.

第二份txt: i love cat.

第三份txt: dog.

第四份txt: cat love dog?


这4份文档,简单的四句话,如果分为2类,是1&2、3&4,还是1&3、2&4,又或是其他情况呢?不妨自己先凭直觉将他们分类,再来看看用K-means聚类法后的得出的结果是否和你的猜测一样。 


我们将步骤2(切词)和步骤3(整合文档)合一起,得到:




接下来,计算tf-idf权重矩阵


↑↑↑以上是原始求tf-idf的公式


为了承接我下个问题,先将第一个文档的「dog」改成「you」,即




按照原始公式,有

you -tf =1/3 

you -idf = log(4/2)=0.301    

tf*idf=0.333*0.301=0.1


那么问题来了,将「you」改为「dog」,那「dog 」呢?  经计算出来是0?这时候有人提出了:我用Python软件计算出来的幷不是0啊!为什么会这样?


首先按照原始公式计算出来是0,也是说得过去的,4个文档,有3个文档都说到了dog,放大来说,1000个文档,就有999个文档都说到了dog,那么再来找特征词dog也就没有了意义了不是?但为什么有人就说用软件算出来的dog在第一份文档的tf-idf权值不是0呢?


这就得引入Python里面scikit-learn工具调用的TfidfTransformer()函数了,我们先来打个预防针——这里用到的公式和原始的公式是不一样的。


scikit-learn 中实现的tf为词频,df为文档频率,idf和tf-idf分别是



在scikit-learn中使用的tf-idf公式为:



一般在计算tf-idf之前都会对原始词频进行归一化处理,TfidfTransformer就直接对tf-idf做了归一化,scikit-learn中的 TfidfTransformer使用了L2归一化



好了,那么可以来计算dog 的tf-idf

在第一份档中dog的tf为1,df为3,idftf-idf分别是




同样可计算出love的tf-idf为1.097,进行归一化处理



来看看用Python做出来的结果是什么:



这就对应上了是不是?不过,别高兴太早,接下来该怎么进行聚类


可以联想到上周我们对brother例子的聚类。Brother例子是二维的,而我们这次是三维的,但思维是一样的喔!


计算过程可看:依旧取 K = 2



如此,a1和a3为一类;a2和a4为一类。(是否和你一开始猜测的结果相符,可否接受?)


这时又有个疑问:我想知道这4份文档分成2类合适吗?是最优的吗?如果不是最优的,那K = ?才是最优的呢?


这里引入SK指标。SK指标是用来判断聚类效果。




其中Ci表示第i类数据对象的集合。Ci是簇Ci的质心,K表示该数据集可以划分为K个簇的集合,dist是欧几里德空间里2个空间对象之间的欧式距离。


误差平方和SSE值越小,说明数据点越接近于它们的质心,簇类效果也就越好。



通过计算SK的大小,来反推出最佳簇类个数的选取,SK越小,说明聚类效果越好,幷且对应的K值即为最佳的簇类个数。


像刚才dog&cat爱情故事例子,考虑K=2和K=3即可。



当K=2时,SSK=0.447,SK=0.893;同样,当K=3时,SSK=0.154,SK=0.462。所以分三类,1文档一类,2和4文档为一类,3为一类效果最佳


下面来看看用Python程序运行出来的结果:

首先用jiaba库以及导入自定义词典进行分词幷输出语料库



引入sklearn 模块调用的TfidfTransformerCountVectorizer函数来计算TFIDF矩阵幷进行K-means聚类;



当K=2时,有:



误差平方和SSK=0.447,其SK=0.893;


当K=3时,有:



误差平方和SSK=0.154,其SK=0.462;所以相比K=2,1文档一类,2和4文档为一类,3为一类效果最佳


总结:每一种算法都有其优缺点,我们使用时更多考虑其是否合适。K-means聚类法的优点相信很多人都深有体会——原理简单,实现容易;而它最大缺点是K 值的选定非常难估计,虽然我们知道用SK指标可以判断K 取何值时最优,但当数据量大的时候,这种迭代的消耗几乎成指数倍增加。

如需下载本文的例子的Python代码,请关注“博易数据”(微信号:boyidata)公众号并发送“py K-means2”获取