聚类算法

聚类算法

 

聚类和分类有什么区别?

分类数据样本是带有标签的,是知道它是哪一个类别的,是有监督的。

但聚类没有标签,是无监督的。

寻找优质用户

在银行客户的数据集之中寻找20%的优质客户,将他们归为一个类别。

社区发现

将联系比较多的几个人聚成一个类别,就可以认为这几个人是一个社群。说明这几个人关系会比较好一点。

异常点监控

将银行后台数据归类为两个类别,比如正常一个类别,不正常一个类别。大多数情况下,数据都会归为正常类别的那一个类,但是党羽带异常点的时候,就会归为另一个类别,所以这个点可能是信用卡诈骗或者是黑客攻击。

K-MEANS

选取两个点作为聚类的中心点(随机)

计算个个点之间的距离。G0代表类别规划,在一个类中,为0表示不是这个类,为1表示是这个类。

将第二类的所有x,y求平均值,找中心点。

中心带确定之后再次计算距离,重新聚类,如此迭代,直到聚类不再发生变化,迭代停止。

类别迭代过程图:相同类别之间数据特征相隔比较近,不同的相隔较远。

 


python实现k-means算法实战

import numpy as np
import matplotlib.pyplot as plt

data = np.genfromtxt("kmeans.txt",delimiter=" ")
plt.scatter(data[:,0],data[:,1])
# plt.show()
# print(data.shape)#(80,2)

#计算距离
def euclDistance(vector1,vector2):
        return np.sqrt(sum((vector2-vector1)**2))

#初始化质心
def initCentroids(data,k):
        numSamples,dim = data.shape
        #k个质心,列数和样本列数相同
        centroids = np.zeros((k,dim))
        #随机选出k个质点
        for i in range(k):
                index = int(np.random.uniform(0,numSamples))#uniform浮点数
                #作为初始化质心
                centroids[i,:] = data[index,:]
        return centroids

#传入数据集和k的值
def kmeans(data,k) :
        #计算样本个数,0代表行,1代表列
        numSamples = data.shape[0]
        #样本的属性,第一列保存该样本的属于哪个簇,第二列保存该样本与它所属样本的误差值。
        clusterData = np.array(np.zeros((numSamples,2)))#把它初始化为0
        #决定质心是否要改变的变量
        clusterChanged = True

        #初始化质心
        centroids = initCentroids(data,k)

        while clusterChanged:
                clusterChanged = False
                #循环每一个样本
                for i in range(numSamples):
                        #最小距离
                        minDist = 100000.0
                        #定义样本所属簇,默认为0
                        minIndex = 0
                        #循环计算每一个质心与该样本的距离
                        for j in range(k):
                                distance = euclDistance(centroids[j,:],data[i,:])
                                #如果计算距离小于最小距离,则更新最小距离
                                if distance < minDist :
                                        minDist = distance
                                        #更新最小距离
                                        clusterData[i,1] = minDist
                                        #更新样本所属的簇
                                        minIndex = j
                        #如果样本所属的簇发生了变化
                        if clusterData[i,0] != minIndex:
                                #质心要重新计算
                                clusterChanged = True
                                #更新样本所属簇
                                clusterData[i,0] = minIndex
                        #更新质心
                for j in range(k):
                         #获取第j个簇所有样本所在的索引
                         #nonzero输出矩阵中不为0的数的坐标,分两行,一行保存所有行坐标,一行保存所有列坐标,
                          cluster_index = np.nonzero(clusterData[:,0] == j)
                          #第j个簇所有的样本点
                          pointsInCluster = data[cluster_index]
                          #计算质心
                          #mean求取平均值
                          # axis 不设置值,对 m*n 个数求均值,返回一个实数
                          # axis = 0:压缩行,对各列求均值,返回 1* n 矩阵
                          # axis =1 :压缩列,对各行求均值,返回 m *1 矩阵
                          centroids[j,:] = np.mean(pointsInCluster,axis=0)
                          # showCluster(data,k,centroids,cluster_index)
        return centroids,clusterData
#显示结果
def showCluster(data,k,centroids,clusterData):
        numSamples,dim = data.shape
        if dim != 2:
                print("dimension of your data is not 2!")
                return 1
        # 用不同的颜色来表示各个类别
        mark = ['or', 'ob', 'og', 'ok', '^r', '+r', 'sr', 'dr', '<r', 'pr']
        if k > len(mark) :
                print("Your k is too large!")
                return 1
        #画样本点
        for i in range(numSamples):
                markIndex = int(clusterData[i,0])
                plt.plot(data[i,0],data[i,1],mark[markIndex])
         # 用不同的颜色来表示各个类别
        mark = ['*r', '*b', '*g', '*k', '^b', '+b', 'sb', 'db', '<b', 'pb']
        #画质心点
        for i in range(k) :
                plt.plot(centroids[i,0],centroids[i,1],mark[i],markersize = 20)
        plt.show()
#设置k值
k = 4
#centroids 簇的中心点
#cluster Data样本属性,第一列保存该样本属哪个簇,第二列保存该样本跟他所属簇的误差
centroids,clusterData = kmeans(data,k)
if np.isnan(centroids).any():#只要里面存在任何的空值,那么就为true
        print('Error')
else:
        print('cluster complete!')
        #显示结果
showCluster(data,k,centroids,clusterData)
print(centroids)

画出簇的作用域:

#做预测
x_test = [0,1]
np.tile(x_test,(k,1))#行复制k次,列复制1次

#误差
np.tile(x_test,(k,1))-centroids

#误差平方
(np.tile(x_test,(k,1))-centroids)**2

#误差平方和
((np.tile(x_test,(k,1))-centroids)**2).sum(axis=1)
#最小值所在索引号
np.argmin(((np.tile(x_test,(k,1))-centroids)**2).sum(axis=1))

def predict(datas):
        return np.array([np.argmin(((np.tile(data,(k,1))-centroids)**2).sum(axis=1)) for data in datas])

#获取数据值所在范围
x_min,x_max = data[:,0].min() - 1,data[:,0].max() + 1
y_min,y_max = data[:,1].min() - 1,data[:,1].max() + 1

#生成网格矩阵
xx,yy = np.meshgrid(np.arange(x_min,x_max,0.02),
                    np.arange(y_min,y_max,0.02))
z = predict(np.c_[xx.ravel(),yy.ravel()])
#扁平化,得到一个一个的点
#ravel和flatten类似,多维数据转一维,flatten不会改变原始数据,而ravel会
z = z.reshape(xx.shape)
#等高线图
#在这里,只有两个高度,0和1
cs = plt.contourf(xx,yy,z)

showCluster(data,k,centroids,clusterData)


 

 


sklearn-K-Means算法:

from sklearn.cluster import KMeans
import numpy as np
import matplotlib.pyplot as plt

#载入数据
data = np.genfromtxt('kmeans.txt',delimiter=" ")
k = 4

model = KMeans(n_clusters=k)
model.fit(data)

#分类中心点坐标
centers  = model.cluster_centers_
print(centers)

#预测结果
result = model.predict(data)
print(result)
print(model.labels_)

mark = ['or','ob','og','oy']
for i,d in enumerate(data):
        plt.plot(d[0],d[1],mark[result[i]])

mark = ['*r','*b','*g','*y']
for i,center in enumerate(centers):
        plt.plot(center[0],center[1],mark[i],markersize=20)

plt.show()

 


 

 


Sklearn-mini-Batch-K-Means

KMeans和Mini的结果对比:

数据量非常大的时候可以使用Mini,一般情况下直接使用K-Means就好。


 


K-Means存在的四个问题

算法分析1:

算法分析2:

算法分析3:

算法分析4:

数据比较大时,收敛会比较慢。


解决K-Means的算法分析1的问题:

算法优化1:两条竖线时取模的意思,内部可以为两个向量。

import numpy as np
import matplotlib.pyplot as plt

data = np.genfromtxt("kmeans.txt",delimiter=" ")
plt.scatter(data[:,0],data[:,1])
# plt.show()
# print(data.shape)#(80,2)

#计算距离
def euclDistance(vector1,vector2):
        return np.sqrt(sum((vector2-vector1)**2))

#初始化质心
def initCentroids(data,k):
        numSamples,dim = data.shape
        #k个质心,列数和样本列数相同
        centroids = np.zeros((k,dim))
        #随机选出k个质点
        for i in range(k):
                index = int(np.random.uniform(0,numSamples))#uniform浮点数
                #作为初始化质心
                centroids[i,:] = data[index,:]
        return centroids

#传入数据集和k的值
def kmeans(data,k) :
        #计算样本个数,0代表行,1代表列
        numSamples = data.shape[0]
        #样本的属性,第一列保存该样本的属于哪个簇,第二列保存该样本与它所属样本的误差值。
        clusterData = np.array(np.zeros((numSamples,2)))#把它初始化为0
        #决定质心是否要改变的变量
        clusterChanged = True

        #初始化质心
        centroids = initCentroids(data,k)

        while clusterChanged:
                clusterChanged = False
                #循环每一个样本
                for i in range(numSamples):
                        #最小距离
                        minDist = 100000.0
                        #定义样本所属簇,默认为0
                        minIndex = 0
                        #循环计算每一个质心与该样本的距离
                        for j in range(k):
                                distance = euclDistance(centroids[j,:],data[i,:])
                                #如果计算距离小于最小距离,则更新最小距离
                                if distance < minDist :
                                        minDist = distance
                                        #更新最小距离
                                        clusterData[i,1] = minDist
                                        #更新样本所属的簇
                                        minIndex = j
                        #如果样本所属的簇发生了变化
                        if clusterData[i,0] != minIndex:
                                #质心要重新计算
                                clusterChanged = True
                                #更新样本所属簇
                                clusterData[i,0] = minIndex
                        #更新质心
                for j in range(k):
                         #获取第j个簇所有样本所在的索引
                         #nonzero输出矩阵中不为0的数的坐标,分两行,一行保存所有行坐标,一行保存所有列坐标,
                          cluster_index = np.nonzero(clusterData[:,0] == j)
                          #第j个簇所有的样本点
                          pointsInCluster = data[cluster_index]
                          #计算质心
                          #mean求取平均值
                          # axis 不设置值,对 m*n 个数求均值,返回一个实数
                          # axis = 0:压缩行,对各列求均值,返回 1* n 矩阵
                          # axis =1 :压缩列,对各行求均值,返回 m *1 矩阵
                          centroids[j,:] = np.mean(pointsInCluster,axis=0)
                          # showCluster(data,k,centroids,cluster_index)
        return centroids,clusterData
#显示结果
def showCluster(data,k,centroids,clusterData):
        numSamples,dim = data.shape
        if dim != 2:
                print("dimension of your data is not 2!")
                return 1
        # 用不同的颜色来表示各个类别
        mark = ['or', 'ob', 'og', 'ok', '^r', '+r', 'sr', 'dr', '<r', 'pr']
        if k > len(mark) :
                print("Your k is too large!")
                return 1
        #画样本点
        for i in range(numSamples):
                markIndex = int(clusterData[i,0])
                plt.plot(data[i,0],data[i,1],mark[markIndex])
         # 用不同的颜色来表示各个类别
        mark = ['*r', '*b', '*g', '*k', '^b', '+b', 'sb', 'db', '<b', 'pb']
        #画质心点
        for i in range(k) :
                plt.plot(centroids[i,0],centroids[i,1],mark[i],markersize = 20)
        plt.show()
#设置k值
k = 4
min_loss = 10000
min_loss_centroids = np.array([])
min_loss_clusterData = np.array([])

for i in range(50):
        #centroids为簇的中心点
        #clusterData为样本的属性,第一列保存样本属于哪个簇,第二列保存该样本与它所属簇的距离误差
        centroids,clusterData = kmeans(data,k)
        loss = sum(clusterData[:,1])/data.shape[0]
        if loss<min_loss:
                min_loss = loss
                min_loss_centroids = centroids
                min_loss_clusterData = clusterData
print('cluster complete')
showCluster(data,k,min_loss_centroids,min_loss_clusterData)

运行时可能会出现这种情况,就是我们之前讲过的两个质心在变换过程中重合了,所以在最后四个结果中,会有空值,所以会出现警告。但它选取的时最小代价的那一个,所以不会影响最后结果。

解决K-Means的算法分析2的问题:

算法优化:

肘部法则:

当出现第二种情况,他的代价函数没有很明显的肘部,那么就要根据业务需求或自己的经验来进行判断了。

画肘部法则代价函数曲线:

list_loss = []
for k in range(2,10):
        min_loss = 10000
        min_loss_centroids = np.array([])
        min_loss_clusterData = np.array([])
        for i in range(50):
                #centroids为簇的中心点
                #clusterData为样本的属性,第一列保存样本属于哪个簇,第二列保存该样本与它所属簇的距离误差
                centroids,clusterData = kmeans(data,k)
                loss = sum(clusterData[:,1])/data.shape[0]
                if loss<min_loss:
                        min_loss = loss
                        min_loss_centroids = centroids
                        min_loss_clusterData = clusterData
        list_loss.append(min_loss)
# print('cluster complete')
# showCluster(data,k,min_loss_centroids,min_loss_clusterData)

plt.plot(range(2,10),list_loss)
plt.xlabel('k')
plt.ylabel('loss')
plt.show()


 

 


可视化K-Means

https://www.naftaliharris.com/blog/visualizing-k-means-clustering/

可视化聚类网站网址。


DBSCAN算法

基于密度的聚类算法。

DBSCAN的可视化:

epsilon是聚类领域的半径。实心的圈表示样本对象是核心对象,因为圈内对象个数大于minpoints。

可能会产生孤立地点。因为它大于设置领域的半径,导致不属于任何一个类别。

可以通过设置epsilon,minpoints的值来进行降噪。

实战DBSCAN

要注意调节半径和minpoints的值。

from sklearn.cluster import DBSCAN
import numpy as np
import matplotlib.pyplot as plt

data = np.genfromtxt('kmeans.txt',delimiter=" ")

model = DBSCAN(eps=1.5,min_samples=4)
model.fit(data)

result = model.fit_predict(data)

mark = ['or','ob','og','oy','ok','om']
for i,d in enumerate(data):
        plt.plot(d[0],d[1],mark[result[i]])

plt.show()

可以认为粉红色是噪音值。


import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
x1, y1 = datasets.make_circles(n_samples=2000, factor=0.5, noise=0.05)
x2, y2 = datasets.make_blobs(n_samples=1000, centers=[[1.2,1.2]], cluster_std=[[.1]])#数据标准差为0.1

x = np.concatenate((x1, x2))
plt.scatter(x[:, 0], x[:, 1], marker='o')
plt.show()

from sklearn.cluster import KMeans
y_pred = KMeans(n_clusters=3).fit_predict(x)
plt.scatter(x[:, 0], x[:, 1], c=y_pred)#颜色就用解惑来表示
plt.show()

from sklearn.cluster import DBSCAN
y_pred = DBSCAN().fit_predict(x)#如果不传参,会是一个默认参数eps=0.5,min_point = 5
plt.scatter(x[:, 0], x[:, 1], c=y_pred)
plt.show()

y_pred = DBSCAN(eps = 0.2).fit_predict(x)
plt.scatter(x[:, 0], x[:, 1], c=y_pred)
plt.show()

y_pred = DBSCAN(eps = 0.2, min_samples=50).fit_predict(x)
plt.scatter(x[:, 0], x[:, 1], c=y_pred)
plt.show()

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值