聚类 (二)

聚类实例

数据集

  在文章前半部分我用到的数据集为西瓜集4.0。(周志华老师西瓜书上的数据)
  

/

  具体数值可以复制以下数据并保存到.csv文件中。

number,density,sugercontent
1,0.697,0.460
2,0.774,0.376
3, 0.634,0.264
4,0.608,0.318
5,0.556,0.215
6,0.403,0.237
7,0.481,0.149
7,0.666,0.091
8,0.437,0.211
9,0.666,0.091
10,0.243,0.267
11,0.245,0.057
12,0.343,0.099
13,0.639,0.161
14,0.657,0.198
15,0.360,0.370
16,0.593,0.042
17,0.719,0.103
18,0.359,0.188
19,0.339,0.241
20,0.282,0.257
21,0.748,0.232
22,0.714,0.346
23,0.483,0.312
24,0.478,0.437
25,0.525,0.369
26,0.751,0.489
27,0.532,0.472
28,0.473,0.376
29,0.725,0.445
30,0.446,0.459

K-means

  给出测试代码,由于K-means在 sklearn s k l e a r n 包 中自带,所以就简单的调用了包中的函数,给出代码如下:

import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
import pandas as pd

data = pd.read_csv('./watermelon.csv')
value = data.values

estimator = KMeans(n_clusters = 5, max_iter = 200)
res = estimator.fit_predict(value[:, 1:3])

for i in range(30):
    if res[i] == 0:
        plt.scatter(value[i][1], value[i][2], color = 'red')
    if res[i] == 1:
        plt.scatter(value[i][1], value[i][2], color = 'green')
    if res[i] == 2:
        plt.scatter(value[i][1], value[i][2], color = 'blue')
    if res[i] == 3:
        plt.scatter(value[i][1], value[i][2], color = 'black')
    if res[i] == 4:
        plt.scatter(value[i][1], value[i][2], color = 'yellow')

plt.show()

  首先导入matplotlib.pyplotsklearn.clusterpandas三个包,分别用作画图、使用K-means接口、读取和规范化数据。
  首先我们调用pandas中的read_csv方法读取.csv数据,当然如果watermelon.csv不在当前目录下就会报错,也可以使用绝对路径。   data = pd.read_csv('./watermelon.csv')
  然后用value保存data中的纯数据,因为在data中第一行会有属性名称。
  value = data.values
  可以分别输出data和value来看看里面的内容以加深理解。
  然后调用sklearn.cluster中的KMeans方法,返回的是一个预测器。这里设置了聚类所得簇为5簇,最高迭代200次。
  estimator = KMeans(n_clusters = 5, max_iter = 200)
  预测出分类结果,参数是分类的依据,在这里就是value的第[1, 3)列,即密度、含糖率。
  res = estimator.fit_predict(value[:, 1:3])
  此时可以输出res查看得到的是什么。
  结果为:

[4 4 1 1 1 0 0 0 2 0 0 0 2 1 3 2 2 0 0 0 1 4 3 3 3 4 3 3 4 3]

  这个30个元素的数组表示了30个西瓜被分配到的簇编号。
  为了形象地看出结果,我用matplotlib作出了结果图,代码如下:

for i in range(30):
    if res[i] == 0:
        plt.scatter(value[i][1], value[i][2], color = 'red')
    if res[i] == 1:
        plt.scatter(value[i][1], value[i][2], color = 'green')
    if res[i] == 2:
        plt.scatter(value[i][1], value[i][2], color = 'blue')
    if res[i] == 3:
        plt.scatter(value[i][1], value[i][2], color = 'black')
    if res[i] == 4:
        plt.scatter(value[i][1], value[i][2], color = 'yellow')

  对于不同类簇的点,在二维(密度、含糖率)图中分别用不同颜色的点标出,最终调用plt.show()作出图像,结果如下:
  

/

  可以发现,聚类结果还是比较乐观的。

学习向量量化(LVQ)

  由于sklearn中不包含这个方法,所以只能手写代码来实现。鉴于本人的代码水平有限,很多地方写完之后发现没有必要,过于冗杂了,然后又懒得改,直接贴代码了。
  代码如下:

import numpy as np
import matplotlib.pyplot as plt
import math
import random
import pandas as pd

def init():
    vec.append(data[5 - 1][1: 3])
    vec.append(data[12 - 1][1: 3])
    vec.append(data[18 - 1][1: 3])
    vec.append(data[23 - 1][1: 3])
    vec.append(data[29 - 1][1: 3])

def get_distance(a, b):
    return math.sqrt((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2)

n = 0.1
q = 5
arr = []
vec = []
mark = [1, 2, 2, 1, 1]

def LVQ(nums):
    while nums > 0:
        now = random.randint(0, 29)
        dis = []
        for i in range(q):
            dis.append(get_distance(vec[i], data[now][1:3]))
        min = 1000000
        cnt = 0
        for i in range(q):
            if dis[i] < min:
                min = dis[i]
                cnt = i
        if data[now][3] == mark[cnt]:
            vec[cnt] = vec[cnt] + n * (data[now][1:3] - vec[cnt])
        else:
            vec[cnt] = vec[cnt] - n * (data[now][1:3] - vec[cnt])
        nums = nums - 1

def draw():
    for i in range(30):
        min = 100000
        cnt = 0
        for j in range(q):
            dis = get_distance(vec[j], data[i][1:3])
            if dis < min:
                cnt = j
                min = dis
        if cnt == 0:
            plt.scatter(data[i][1], data[i][2], color = 'red')
        elif cnt == 1:
            plt.scatter(data[i][1], data[i][2], color = 'blue')
        elif cnt == 2:
            plt.scatter(data[i][1], data[i][2], color = 'green')
        elif cnt == 3:
            plt.scatter(data[i][1], data[i][2], color = 'black')
        else:
            plt.scatter(data[i][1], data[i][2], color = 'yellow')
    plt.show()


xigua = pd.read_csv('./watermelon.csv')

data = xigua.values

for i in range(30):
    arr.append([])
    for j in range(3):
        if j == 0:
            arr[i].append(int(data[i][j] + 0.01))
        if j == 1 or j == 2:
            arr[i].append(int(data[i][j] * 1000) / 1000.0)
    if i + 1 >= 9 and i + 1 <= 21:
        arr[i].append(2)
    else:
        arr[i].append(1)

data = np.array(arr)

init()
LVQ(400)
draw()

  运行结果如下图:
  

/

  可以发现,LVQ的聚类结果也是比较乐观的。

高斯混合聚类

  高斯混合聚类的过程很繁琐,值得庆幸的是sklearn包中包含调用该方法的函数。具体调用形式和K-means差不多,直接给出代码:

from sklearn.mixture import GaussianMixture
import pandas as pd
import matplotlib.pyplot as plt

data = pd.read_csv('./watermelon.csv')
value = data.values

estimator = GaussianMixture(n_components=5, max_iter=30).fit(value[:, 1:3])
res = estimator.predict(value[:, 1:3])

for i in range(30):
    if res[i] == 0:
        plt.scatter(value[i][1], value[i][2], color = 'red')
    if res[i] == 1:
        plt.scatter(value[i][1], value[i][2], color = 'green')
    if res[i] == 2:
        plt.scatter(value[i][1], value[i][2], color = 'blue')
    if res[i] == 3:
        plt.scatter(value[i][1], value[i][2], color = 'black')
    if res[i] == 4:
        plt.scatter(value[i][1], value[i][2], color = 'yellow')

plt.show()

  该代码和K-means代码几乎一样,所以就不多赘述。
  给出高斯混合聚类的结果图(每次跑起来结果都不一样的):
  

/

  可以发现,高斯混合聚类的聚类结果也是比较乐观的。

密度聚类(DBSCAN)

  密度聚类是比较新的一种聚类方式,最近用的比较广。
  sklearn包中包含DBSCAN,所以可以直接调用DBSCAN的函数,代码如下:

from sklearn.cluster import DBSCAN
import pandas as pd
import matplotlib.pyplot as plt

data = pd.read_csv('./watermelon.csv')
value = data.values

estimator = DBSCAN(eps = 0.11, min_samples = 5)
res = estimator.fit_predict(value[:, 1:3])

print(res)

for i in range(len(res)):
    if res[i] == 0:
        plt.scatter(value[i][1], value[i][2], color = 'red')
    elif res[i] == 1:
        plt.scatter(value[i][1], value[i][2], color = 'green')
    elif res[i] == 2:
        plt.scatter(value[i][1], value[i][2], color = 'blue')
    elif res[i] == 3:
        plt.scatter(value[i][1], value[i][2], color = 'yellow')
    else:
        plt.scatter(value[i][1], value[i][2], color = 'pink')

plt.show()

  运行结果如下:
  

/

  其中,粉色的两个点是噪声,因为它们离别的点太远了,太不合群了,所以就变成噪声了,该图中可以看出,一共聚了四个类。

  由于闲的没事,我又手写代码实现了一遍DBSCAN,代码如下:

from __future__ import print_function
import pandas as pd
import matplotlib.pyplot as plt
import math
import random
import Queue

xigua = pd.read_csv('/Users/apathetically/PycharmProjects/watermelon.csv')

data = xigua.values

num = 30 #the numbers of elements
eps = 0.11
MinPts = 5
k = 0 #the nums of clustering

iscore = []
ans = [0 for i in range(num)]
pts = []

for i in range(num):
    cnt = 0
    for j in range(num):
        if math.sqrt((data[i][1] - data[j][1]) ** 2 + (data[i][2] - data[j][2]) ** 2) <= eps:
            cnt += 1
    if cnt >= MinPts:
        iscore.append(i)
    pts.append(cnt)

unused = [i for i in range(num)]

while len(iscore):
    unusedold = []
    for i in range(len(unused)):
        unusedold.append(unused[i])
    core = random.randint(0, len(iscore) - 1)
    core = iscore[core]
    Q = Queue.Queue()
    Q.put(core)
    unused.remove(core)
    while not Q.empty():
        q = Q.get()
        if pts[q] >= MinPts:
            temp = []
            for i in range(len(unused)):
                if math.sqrt((data[q][1] - data[unused[i]][1]) ** 2 + (data[q][2] - data[unused[i]][2]) ** 2) <= eps:
                    temp.append(unused[i])
            for i in range(len(temp)):
                Q.put(temp[i])
                unused.remove(temp[i])
    k = k + 1

    for i in range(num):
        if i in unusedold and i not in unused:
            ans[i] = k
            if i in iscore:
                iscore.remove(i)

for i in range(num):
    if ans[i] == 1:
        plt.scatter(data[i][1], data[i][2], color = 'red')
    elif ans[i] == 2:
        plt.scatter(data[i][1], data[i][2], color = 'green')
    elif ans[i] == 3:
        plt.scatter(data[i][1], data[i][2], color = 'blue')
    elif ans[i] == 4:
        plt.scatter(data[i][1], data[i][2], color = 'yellow')
    else:
        plt.scatter(data[i][1], data[i][2], color = 'pink')

plt.show()

  最终聚类结果如下:
  

/

  通过对比调用sklearn.cluster中的DBSCAN和手写的DBSCAN结果图,我们可以发现聚类结果近乎一致(颜色什么的其实是一样的),但是有一个点划分的簇不同,可能是sklearn.cluster中内置的DBSCAN方法和西瓜书中描述的方法有所不同。

层次聚类

  书上最后一种介绍道的聚类方式是层次聚类,层次聚类在sklearn中也有内置函数,使用代码如下:

import numpy as np
from sklearn.cluster import AgglomerativeClustering
import pandas as pd
import matplotlib.pyplot as plt

xigua = pd.read_csv('./watermelon.csv')
data = xigua.values

estimator = AgglomerativeClustering(n_clusters=6)
res = estimator.fit_predict(data[:, 1:3])

c = ['red', 'green', 'blue', 'yellow', 'black', 'purple']

for i in range(30):
    if res[i] == 0:
        plt.scatter(data[i][1], data[i][2], c = c[0])
    elif res[i] == 1:
        plt.scatter(data[i][1], data[i][2], c = c[1])
    elif res[i] == 2:
        plt.scatter(data[i][1], data[i][2], c = c[2])
    elif res[i] == 3:
        plt.scatter(data[i][1], data[i][2], c = c[3])
    elif res[i] == 4:
        plt.scatter(data[i][1], data[i][2], c = c[4])
    else:
        plt.scatter(data[i][1], data[i][2], c = c[5])

plt.show()

  该代码和Kmeans、高斯混合聚类以及DBSCAN调用函数接口大同小异。给出结果图:
    

/

  图中一共聚了六个类,聚类效果也比较乐观。

聚类在生活中的运用

  最近在优秀学姐的带领下在实验室做项目,在项目的内容和聚类有关的就是将气象网站搜集到的一系列数据进行PCA降维,然后进行聚类,找出哪些地点的气候较为接近,也就是反应中国气候分布的。
  由于不同聚类方式结果不同,在这个问题中,由于各个数据的距离差的比较多,所以密度聚类的效果不是很好(很难确定eps和Minpts)。而别的几个聚类效果都还行,选择性地放一张高斯混合聚类出来的结果:
  

/

  图是用Basemap画的,感觉效果还是挺不错的,将气候聚了五个类,在途中根据经纬度绘制出来,发现结果十分美妙,地理位置对气候的影响至关重要,可以看内蒙古-新疆的沙漠那块儿气候一致,而稍微南边的青海西藏又是另一种气候,另外东北、东南、南方又是不同的气候。当然每次聚类的结果不一定相同(因为高斯混合聚类本身就不稳定)。
  下面是另一次运行的结果:
  
/

  可以看出,在云南数据的聚类上和第一次运行结果产生了分歧,这也是情有可原的,大体上聚类结果还是差不多的。
  这个结果还是很令人兴奋的,训练集中并不存在任何地理因素,而仅仅是根据气象因素聚类出来的结果在地理分布上又那么有规律。所以说聚类还是很有用处,很有趣的。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值