用Scipy实现K-means聚类算法
这是我之前写过的一篇文章,使用k-均值聚类算法给明星的身材分分类,由于技艺不精,写 得着实不好。今天在stackoverflow上发现,原来 scipy有聚类的相关包,还挺方便的。不 过,貌似网上似乎都没有它的使用介绍。我忙了一下午,终于搞好了,我的数据如下:
名字 | 身高 | 体重 | 胸围 | 腰围 | 臀围 |
---|---|---|---|---|---|
金巧巧 | 164 | 112.5 | 34.0 | 25.0 | 34.0 |
杨幂 | 168 | 99.0 | 32.0 | 24.0 | 32.0 |
钟丽缇 | 168 | 108.0 | 36.0 | 24.0 | 35.0 |
朱茵 | 160 | 95.0 | 33.0 | 22.0 | 33.0 |
赵薇 | 166 | 105.0 | 33.0 | 23.0 | 33.0 |
李珊珊 | 175 | 115.0 | 36.0 | 24.0 | 36.0 |
佘诗曼 | 164 | 96.0 | 33.0 | 22.0 | 34.0 |
郭羡妮 | 166 | 103.0 | 33.0 | 23.0 | 34.0 |
郑秀文 | 165 | 100.0 | 31.0 | 22.0 | 32.0 |
林嘉欣 | 163 | 108.0 | 33.0 | 24.0 | 34.0 |
韩君婷 | 168 | 108.0 | 34.0 | 24.0 | 35.0 |
安雅 | 163 | 104.0 | 34.5 | 24.0 | 35.0 |
林志玲 | 174 | 117.0 | 34.0 | 24.0 | 36.0 |
萧蔷 | 170 | 108.0 | 34.0 | 23.0 | 35.0 |
林嘉绮 | 180 | 126.0 | 34.0 | 25.0 | 35.0 |
姚乐怡 | 163 | 101.0 | 34.0 | 24.0 | 34.0 |
关之琳 | 170 | 117.0 | 35.0 | 24.0 | 35.0 |
巩俐 | 168 | 126.0 | 38.0 | 30.0 | 36.0 |
彭丹 | 169 | 125.0 | 36.0 | 24.0 | 36.0 |
张柏芝 | 165 | 101.0 | 33.0 | 25.0 | 34.0 |
章子怡 | 164 | 108.0 | 32.0 | 24.0 | 34.0 |
何洁 | 157 | 104.0 | 32.0 | 20.0 | 45.0 |
蔡依林 | 158 | 92.0 | 32.0 | 24.0 | 32.0 |
阿娇 | 160 | 101.0 | 32.0 | 24.0 | 33.0 |
阿Sa | 165 | 100.0 | 32.0 | 23.0 | 33.5 |
高圆圆 | 167 | 108.0 | 33.0 | 24.0 | 34.0 |
奥黛丽赫本 | 170 | 103.5 | 32.0 | 20.0 | 35.0 |
温碧霞 | 164 | 106.0 | 33.0 | 23.0 | 33.0 |
安吉利娜-朱丽 | 173 | 130.0 | 36.0 | 27.0 | 36.0 |
巩新亮 | 168 | 101.0 | 34.0 | 22.0 | 33.0 |
舒淇 | 168 | 115.0 | 34.0 | 24.0 | 35.0 |
范冰冰 | 168 | 112.0 | 33.0 | 22.0 | 32.0 |
阿朵 | 166 | 115.0 | 38.0 | 30.0 | 38.0 |
白歆惠 | 175 | 112.0 | 33.0 | 23.0 | 35.0 |
韩艺瑟 | 166 | 101.0 | 33.0 | 24.0 | 33.0 |
幸田来未 | 156 | 92.0 | 33.0 | 22.0 | 33.0 |
饭岛爱 | 161 | 100.0 | 33.5 | 22.0 | 33.5 |
苍井空 | 155 | 101.0 | 35.0 | 22.4 | 32.7 |
衫本彩 | 168 | 124.0 | 33.9 | 22.6 | 33.6 |
宋慧乔 | 161 | 101.0 | 33.0 | 24.0 | 32.0 |
李慧珍 | 160 | 92.0 | 33.0 | 24.0 | 32.0 |
陈怡蓉 | 160 | 101.0 | 32.0 | 25.0 | 34.0 |
张梓林 | 182 | 128.0 | 34.7 | 25.0 | 34.8 |
斯嘉丽·约翰逊 | 160 | 108.0 | 35.5 | 24.6 | 35.5 |
霍莉·威洛比 | 170 | 123.8 | 29.3 | 23.4 | 30.1 |
碧昂斯 | 170 | 126.0 | 35.2 | 23.8 | 34.4 |
蕾哈娜 | 173 | 108.0 | 30.0 | 24.0 | 32.0 |
玛丽莲 | 166 | 120.4 | 35.0 | 22.0 | 35.0 |
黛塔·范·提思 | 168 | 107.0 | 34.0 | 22.0 | 34.0 |
凯蒂·派瑞 | 173 | 130.0 | 34.0 | 27.0 | 33.0 |
碧姬·芭铎 | 170 | 128.0 | 35.0 | 23.0 | 35.0 |
金·卡戴珊 | 175 | 128.0 | 35.5 | 25.0 | 36.0 |
拉拉·斯通 | 173 | 112.5 | 34.0 | 24.0 | 35.0 |
洪欣 | 167 | 124.0 | 33.0 | 25.0 | 35.0 |
王祖贤 | 172 | 128.0 | 33.0 | 25.0 | 33.0 |
林心如 | 167 | 103.5 | 33.0 | 22.0 | 34.0 |
孟广美 | 178 | 129.0 | 34.0 | 26.0 | 36.0 |
应采儿 | 175 | 112.5 | 33.0 | 24.5 | 34.0 |
张韶涵 | 158 | 90.0 | 32.0 | 23.5 | 32.0 |
徐若瑄 | 161 | 114.0 | 33.0 | 25.0 | 33.0 |
桂纶镁 | 164 | 103.5 | 32.0 | 23.0 | 34.5 |
陈乔恩 | 165 | 90.0 | 33.0 | 22.0 | 33.3 |
杨丞琳 | 161 | 99.0 | 32.0 | 23.0 | 33.0 |
廖碧儿 | 171 | 117.0 | 35.0 | 24.0 | 34.0 |
李玟 | 162 | 105.0 | 35.0 | 22.5 | 35.0 |
Maggie | 170 | 106.0 | 34.0 | 24.0 | 34.0 |
张曼玉 | 168 | 115.0 | 32.4 | 23.0 | 34.0 |
上述数据用csv格式存储,代码如下:
import pandas as pd from scipy.cluster.vq import vq, kmeans, whiten,kmeans2 data = pd.read_csv('/home/rickey/文档/学习/数据挖掘与数据仓库/数据挖掘作业/三围数据',sep='t',index_col=0) matData = data.as_matrix() whitened = whiten(matData) center = kmeans(whitened,12)[0] result = vq(whitened,center)[0] dicResult = {} resultList = result.tolist() i = 0 for i in range(len(resultList)): #print i if dicResult.has_key(resultList[i]): dicResult[result[i]].append(i) else: dicResult[result[i]] = [i] for i in dicResult: for j in dicResult[i]: print data.index[j], print 'nnn'
现在的代码量相对于之前的,真的是少了很多很多呀。下面我介绍一下一些主要函数的说明: 我这里使用了scipy,pandas两个包,readcsv读取csv文件的效果我觉得比numpy和scipy都 要好。data里面包含了人 名,列名,所以用matData获取纯数据部分。whiten函数比较坑爹, 它的文档的例子是错误的,我是看了它的源代码才知道什么意思的,实际上,它是 先算出 matData各列的标准差,形成一个新的数组,比如上面的数据有四列,该新的数组就有四个 元素,每个元素分别是对应列的标准差。然后,用 matData处于该标准差数据,就得出了 whitened这个结果了。center获得的是聚类中心所形成的数组。,这里,可以用kmeans,也 可以用kmeans2。他们两个的区别我还没有去细致区分。kmeans返回的结果是一个有两个元 素的元组,第一个元素是聚类中心数组,第二个元素是单个数字,我不太明白它的意思。 result则是聚类的结果。这里,vq需要两个参数,分别是whitened,center,通过vq,可以 获取每个人所属的类,返回的也是如kmeans一样的元组结果,第一个元素如下:
array([ 6, 11, 7, 3, 11, 7, 3, 11, 11, 6, 7, 8, 7, 7, 10, 6, 7, 0, 2, 6, 6, 1, 5, 5, 11, 6, 11, 11, 10, 11, 7, 11, 0, 7, 6, 5, 3, 9, 2, 5, 5, 6, 10, 8, 4, 2, 4, 2, 11, 10, 2, 10, 7, 2, 2, 11, 10, 7, 5, 6, 11, 3, 5, 7, 8, 7, 11])
这个数组的意思是说,第一个人属于聚类中心6,第二个人属于聚类中心11。后面的那些代码, 主要是用来输出人名的,与聚类算法已经无关了,获得的结果会变,貌似即使是同样的k值, 结果还是会有点不一样的,k值也比较难以确定,我分的是12个,结果如下:
巩俐 阿朵
何洁
彭丹 衫本彩 碧昂斯 玛丽莲 碧姬·芭铎 洪欣 王祖贤
朱茵 佘诗曼 饭岛爱 陈乔恩
霍莉·威洛比 蕾哈娜
蔡依林 阿娇 幸田来未 宋慧乔 李慧珍 张韶涵 杨丞琳
金巧巧 林嘉欣 姚乐怡 张柏芝 章子怡 高圆圆 韩艺瑟 陈怡蓉 徐若瑄
钟丽缇 李珊珊 韩君婷 林志玲 萧蔷 关之琳 舒淇 白歆惠 拉拉·斯通 应采儿 廖碧儿 Maggie
安雅 斯嘉丽·约翰逊 李玟
苍井空
林嘉绮 安吉利娜-朱丽 张梓林 凯蒂·派瑞 金·卡戴珊 孟广美
杨幂 赵薇 郭羡妮 郑秀文 阿Sa 奥黛丽赫本 温碧霞 巩新亮 范冰冰 黛塔·范·提思 林心如 桂纶镁 张曼玉
总体来讲,感觉不然我之前的那个算法分得准确。