Clustering
聚类前需要进行数据标准化!
我们希望同一簇的样本应该尽可能彼此相似,不同簇的样本尽可能不同。
详细内容见西瓜书p198-p199
将聚类结果与某个“参考模型”进行比较。
直接考察聚类结果而不利用任何参考模型。
例如{飞机,火车,轮船}这样的离散属性,不能直接在属性值上计算距离,一般采用VDM进行距离的计算
mu,a表示在属性u上取值为a的样本数
mu,a,i表示第i个样本簇中在属性u上取值为a的样本数
假设有nc个有序属性,n-nc个无序属性
若不同属性的重要性不同时,可使用加权距离
K-means Clustering:给定一个数据点集合和需要的聚类数目k(用户指定),根据某个距离函数反复地把数据分入k个聚类中。
具体过程配上web数据挖掘P90图4.3
import numpy as np
def loadDataSet(filename):
dataMat = []
f = open(filename)
for line in f.readlines():
curLine = line.strip().split()
fltLine = list(map(float, curLine)) # 将所有元素都映射成float()
dataMat.append(fltLine)
return dataMat
def distEclud(vecA, vecB):
return np.sqrt(np.sum(np.power(vecA-vecB, 2)))
# 构建一个包含k个随机质心的集合
def randCent(dataSet, k):
n = np.shape(dataSet)[1]
centroids = np.mat(np.zeros((k, n)))
for j in range(n):
minJ = np.min(dataSet[:, j])
rangeJ = float(np.max(dataSet[:, j]) - minJ)
centroids[:, j] = minJ + rangeJ * np.random.rand(k, 1)
return centroids
"""
创建k个点作为起始质心(随机选择)
当任意一个点的簇分配结果发生改变时
对数据集中的每个数据点
对每个质心
计算质心与数据点的距离
将数据点分配到距离其最近的簇
对每一个簇,计算簇中所有点的均值并将均值作为质心
"""
def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent):
m = np.shape(dataSet)[0] # 有几个样本
clusterAssment = np.mat(np.zeros((m, 2))) # 簇分配及结果矩阵 列1:簇索引值 列2:存储误差
centroids = createCent(dataSet, k)
clusterChanged = True # 循环条件
while clusterChanged:
clusterChanged = False
for i in range(m): # 对每个样本点
minDist = np.inf # 设为无穷大
minIndex = -1
for j in range(k): # 对于每个质心
distance = distMeas(centroids[j, :], dataSet[i, :]) # 计算当前点与质心的距离
if distance < minDist: # 若当前距离小于之前的最小距离
minIndex = j # 更新簇索引
minDist = distance # 更新最小距离
if clusterAssment[i, 0] != minIndex: # 若当前样本点簇索引改变
clusterChanged = True # 则需要进行下一轮循环
clusterAssment[i, 0] = minIndex # 更新数据
clusterAssment[i, 1] = minDist**2 # 计算SSE误差平方和
for cent in range(k): # 对每一个簇,更新质心
ptsInClust = dataSet[np.nonzero(clusterAssment[:, 0].A == cent)[0]] # 获取在这一簇中的所有样本点
centroids[cent, :] = np.mean(ptsInClust, axis=0) # 列的均值,沿着行
return centroids, clusterAssment
if __name__ == '__main__':
dataMat = np.mat(loadDataSet('testSet.txt'))
myCentroids, clustAssing = kMeans(dataMat, 4)
print(myCentroids, clustAssing)
一种改进算法二分K-均值算法略
import matplotlib.pyplot as plt
from sklearn.datasets._samples_generator import make_blobs
X, y_true = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=0)
# 生成测试集
plt.scatter(X[:, 0], X[:, 1], s=50)
plt.show()
# ---------------------KMeans--------------------
from sklearn.cluster import KMeans
m_kmeans = KMeans(n_clusters=4)
m_kmeans.fit(X)
y_pred = m_kmeans.predict(X)
# ---------------------KMeans--------------------
from sklearn import metrics
def draw(m_kmeans,X,y_pred,n_clusters):
centers = m_kmeans.cluster_centers_
print(centers)
plt.scatter(X[:, 0], X[:, 1], c=y_pred, s=50, cmap='viridis')
# 中心点(质心)用红色标出
plt.scatter(centers[:, 0], centers[:, 1], c='red', s=200, alpha=0.5)
print("Calinski-Harabasz score:%lf" % metrics.calinski_harabasz_score(X, y_pred))
plt.title("K-Means (clusters = %d)" % n_clusters, fontsize=20)
plt.show()
draw(m_kmeans,X,y_pred,4) # 画出聚类结果
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')
n_clusters
: 聚类个数max_iter
: 最大迭代数n_init
: 用不同的质心初始化值运行算法的次数init
: 初始化质心的方法precompute_distances
:预计算距离tol
:关于收敛的参数algorithm
:“auto”, “full” or “elkan” ,”full”就是我们传统的K-Means算法,“elkan”elkan K-Means算法。默认的”auto”则会根据数据值是否是稀疏的,来决定如何选择”full”和“elkan”,稠密的选 “elkan”,否则就是”full”cluster_centers_
:质心坐标labels_
: 每个点的分类列表[0,1,0,1,2,3]inertia_
:每个点到其簇的质心的距离之和简洁、效率高,容易理解也容易实现。
从树状图的最底层开始,每一次通过合并最相似(距离最近)的聚类来形成上一层中的聚类。整个过程当全部数据点都合并到一个聚类(根节点聚类)中时停止。
从一个包含全部数据点的聚类(根)开始。然后把根节点聚类分裂成一些子聚类。每个子聚类再递归地继续往下分裂直到每个聚类中只包含一个数据点。
能够使用任何形式的距离或相似度函数,层次结构更能提供一些细节
时空复杂度高,对异常值十分敏感