聚类算法
KMeans介绍
概念
1、无监督性问题
分类:有监督
聚类:无监督,能用分类,不用聚类
2、
分为多少簇,超参数K
质心:向量各维取平均即可
工作流程:
1、根据k值随意选取k个点作为初始的质心
2、进行分类
3、将已完成分类的点取平均数,作为质心
再次分类,求质心
初始点选择非常重要
查看过程:
1、数据
x,y = make_blobs(n_samples=2000,centers=blob_centers,
cluster_std = blob_std,random_state=7)
2、训练
kmeans_iter1 = KMeans(n_clusters = 5,init = 'random',
n_init = 1,max_iter=1,random_state=1)
kmeans_iter2 = KMeans(n_clusters = 5,init = 'random',
n_init = 1,max_iter=2,random_state=1)
kmeans_iter3 = KMeans(n_clusters = 5,init = 'random',
n_init = 1,max_iter=3,random_state=1)
#init:10默认,inherited(找最好的一次输出),k坐标初始随机位置
#max_iteration:最大迭代次数
kmeans_iter1.fit(x)
kmeans_iter2.fit(x)
kmeans_iter3.fit(x)
3、画图
def plot_data(x,y=None):#绘制无监督的图
plt.plot(x[:,0],x[:,1],'k.')#绘制数据点
# 绘制中心点
def plot_centroids(centroids,weights=None,circle_color='w',
cross_color='r'):
plt.scatter(centroids[:, 0], centroids[:, 1],
marker='^', s=30, linewidths=8,
color=circle_color, zorder=10, alpha=0.9)
#绘制决策边界
def plot_decision_boundaries(kmeans,x,resolution=1000,
show_centroids=True,
show_xlabels=True,show_ylabels=True):
mins=x.min(axis=0)-0.1#x(2000,2)
maxs=x.max(axis=0)+0.1#0:列,1:行;
xx,yy=np.meshgrid(np.linspace(mins[0],maxs[0],resolution),
np.linspace(mins[1],maxs[1],resolution))
z=kmeans.predict(np.c_[xx.ravel(),yy.ravel()]).reshape(xx.shape)
#等高线加颜色
plt.contour(z,extent=(mins[0],maxs[0],mins[1],maxs[1]),
linewidths=1,color='b')
#等高线
plt.contourf(z, extent=(mins[0], maxs[0], mins[1], maxs[1]),
cmap="Pastel2")
plot_data(x)
if show_centroids:
plot_centroids(kmeans.cluster_centers_)
if show_xlabels:
plt.xlabel("$x_1$", fontsize=14)
else:
plt.tick_params(labelbottom='off')
if show_ylabels:
plt.ylabel("$x_2$", fontsize=14, rotation=0)
else:
plt.tick_params(labelleft='off')
plt.figure(figsize=(12,8))
plt.subplot(321)
plot_data(x)
plot_centroids(kmeans_iter1.cluster_centers_,
circle_color='w')
plt.title('Update cluster_centers')
plt.subplot(322)
plot_decision_boundaries(kmeans_iter1, x,show_xlabels=False,
show_ylabels=False)
plt.title('Label')
plt.subplot(323)
plot_decision_boundaries(kmeans_iter1, x,show_xlabels=False,
show_ylabels=False)
plot_centroids(kmeans_iter2.cluster_centers_,)
plt.subplot(324)
plot_decision_boundaries(kmeans_iter2, x,show_xlabels=False,
show_ylabels=False)
plt.subplot(325)
plot_decision_boundaries(kmeans_iter2, x,show_xlabels=False,
show_ylabels=False)
plot_centroids(kmeans_iter3.cluster_centers_,)
plt.subplot(326)
plot_decision_boundaries(kmeans_iter3, x,
show_xlabels=False, show_ylabels=False)
plt.show()
评价标准
1、inertia:
每个样本与其质心的最短距离的平方的总和
sum(每个样本与其质心的距离(样本到各个质心的最小值)**2)
?找找那个k值inertia最小
kmeans_per_k=[KMeans(n_clusters=k).fit(x) for k in range(1,10)]
inertial=[model.inertia_ for model in kmeans_per_k]
plt.figure(figsize=(8,4))
plt.plot(range(1,10),inertial,'bo-')
plt.axis([1,8.5,0,1500])
plt.show()
2、轮廓系数:
?对比那个k轮廓系数最小
from sklearn.metrics import silhouette_score
silhouette_score(x,kmeans.labels_)
silhouette_scores =[silhouette_score(x,model.labels_) for model in kmeans_per_k[1:]]
# Note that Silhouette Coefficient is only defined
# if number of labels is 2 <= n_labels <= n_samples - 1.
plt.figure(figsize=(8,4))
plt.plot(range(2,10),silhouette_scores,'bo-')
plt.show()
kmeans初始点选择对比
1、数据
x1, y1 = make_blobs(n_samples=1000, centers=((4, -4), (0, 0)),
random_state=42)
x1 = x1.dot(np.array([[0.374, 0.95], [0.732, 0.598]]))
x2, y2 = make_blobs(n_samples=250, centers=1, random_state=42)
x2 = x2 + [6, -8]
x = np.r_[x1, x2]
y = np.r_[y1, y2]
2、训练
kmeans_good = KMeans(n_clusters=3,init=np.array([[-1.5,2.5],[0.5,0],[4,0]]),n_init=1,random_state=42)
#
# init,k值的初始地址,可以指定
kmeans_bad = KMeans(n_clusters=3,random_state=42)
kmeans_good.fit(x)
kmeans_bad.fit(x)
3、画图:
plt.figure(figsize = (10,4))
plt.subplot(121)
plot_decision_boundaries(kmeans_good,x)
plt.title('Good - inertia = {}'.format(kmeans_good.inertia_))
plt.subplot(122)
plot_decision_boundaries(kmeans_bad,x)
plt.title('Bad - inertia = {}'.format(kmeans_bad.inertia_))
优劣势:
优:
简单,高效,时候常规数据集
缺:
k值难确定
复杂度与样本呈线性关系
很难发现任意形状的簇
DBSCAN算法
Density-Based Spatial Clustering of Applications with Noise
主要区别:不需要设置k值,当某个点的密度达到算法设定的阈值则将其设为核心点,需要两个参数,在r领域(半径为r)内点的数量不少于minPts
概念
1、直接密度可达:
若p在q的r领域内,则p,q称为直接密度可达
2、密度可达:
若有一个点序列q0,q1,,qk,对任意qi-qj-1是直接密度可达,则成q0-qk是密度可达
3、密度相连:
若q对p,r都是密度可达的,那么p-r是密度项链
4、边界点:
属于某一个类的非核心点,不能发展下线
5、噪声点:
不属于任何一个类簇的点,从任何一个核心点出发都是密度不可达的
6、过程
假代码:
D:数据集
r:半径大小
MinPts:密度阙值
标记所有对象为unvisited;
do
随机选择一个unvisited对象p
标记p为visited
if p的r领域内至少有MinPts个对象
创建一个新簇C,并将p添加到C中;
令N为p的r领域中对象的集合
for N中的对象p
if p是unvisited
标记p为visited
if p的r领域内至少有MinPts个对象
把这些对象添加到N
if p不是任何簇的成员
把p田间到C中
end for
输出C
else
标记p为噪声点
until 没有标为unvisite的对象
优劣势
优点:
1、不需要指定簇的个数
2、可以发现任意形状的簇
3、擅长找到离群点
4、一共需要两个参数
缺点
高维度较难
参数难以选择
sklearn效率较慢
代码实现:
对比查看r不同所产生的效果:
1、数据导入:
from sklearn.datasets import make_moons
x, y = make_moons(n_samples=1000, noise=0.05, random_state=42)
2、训练数据:
from sklearn.cluster import DBSCAN
dbscan = DBSCAN(eps = 0.05,min_samples=5)
#r=eps,min_samples=
dbscan.fit(x)
dbscan2 = DBSCAN(eps = 0.2,min_samples=5)
dbscan2.fit(x)
参数说明:
print(np.unique(dbscan.labels_))#7簇,-1为离群点
可以查看分为多少类,相当于k值
3、画图展示:
def plot_dbscan(dbscan, X, size, show_xlabels=True, show_ylabels=True):
core_mask = np.zeros_like(dbscan.labels_, dtype=bool)
core_mask[dbscan.core_sample_indices_] = True
anomalies_mask = dbscan.labels_ == -1#噪声点
non_core_mask = ~(core_mask | anomalies_mask)
cores = dbscan.components_#含义(1000,2)
anomalies = X[anomalies_mask]
non_cores = X[non_core_mask]
plt.scatter(cores[:, 0], cores[:, 1],
c=dbscan.labels_[core_mask],
marker='o', s=size, cmap="Paired")
plt.scatter(cores[:, 0], cores[:, 1],
marker='*', s=20, c=dbscan.labels_[core_mask])
plt.scatter(anomalies[:, 0], anomalies[:, 1],
c="r", marker="x", s=100)
plt.scatter(non_cores[:, 0], non_cores[:, 1],
c=dbscan.labels_[non_core_mask], marker=".")
if show_xlabels:
plt.xlabel("$x_1$", fontsize=14)
else:
plt.tick_params(labelbottom='off')
if show_ylabels:
plt.ylabel("$x_2$", fontsize=14, rotation=0)
else:
plt.tick_params(labelleft='off')
plt.title("eps={:.2f}, min_samples={}".format(dbscan.eps, dbscan.min_samples), fontsize=14)
plt.figure(figsize=(9, 3.2))
plt.subplot(121)
plot_dbscan(dbscan, x, size=100)
plt.subplot(122)
plot_dbscan(dbscan2, x, size=600, show_ylabels=False)
plt.show()
分割颜色练习
1、图片作为数据:
from matplotlib.image import imread
image = imread('ladybug.png')
x = image.reshape(-1,3)#将长宽化成一维
2、训练模型
kmeans = KMeans(n_clusters = 8,random_state=42).fit(x)
3、用中心点进行聚类
segmented_img = kmeans.cluster_centers_[kmeans.labels_].reshape(533, 800, 3)
#kmeans.labels_预测的分类结果
#kmeans.cluster_centers_中心点的坐标表示
4、进行颜色分类
segmented_imgs=[]
n_colors=(10,8,6,4,2)
for n_cluster in n_colors:
kmeans=KMeans(n_clusters=n_cluster,random_state=42).fit(x)#实例化
print(np.unique(kmeans.labels_))
segmented_img = kmeans.cluster_centers_[kmeans.labels_]
segmented_imgs.append(segmented_img.reshape(image.shape))
5、展示:
plt.figure(figsize=(10,5))
plt.subplot(231)
plt.imshow(image)
plt.title('Original image')
for idx,n_clusters in enumerate(n_colors):
plt.subplot(232+idx)
plt.imshow(segmented_imgs[idx])
plt.title('{}colors'.format(n_clusters))
半监督学习
部分有标签,部分无标签,所以称为半监督学习
# 1、导入数据,划分数据集
from sklearn.datasets import load_digits
x_digits,y_digits = load_digits(return_X_y = True)
from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test = train_test_split(x_digits,y_digits,random_state=42)
1、监督学习
直接使用有标签的进行逻辑回归学习
from sklearn.linear_model import LogisticRegression
n_labeled = 50
log_reg = LogisticRegression(random_state=42)#逻辑回归
log_reg.fit(x_train[:n_labeled], y_train[:n_labeled])
log_reg.score(x_test, y_test)
0.8266666666666667
2、对质心进行人工监督学习
1、选取质心点
1、聚类
k = 50
kmeans = KMeans(n_clusters=k, random_state=42)
x_digits_dist = kmeans.fit_transform(x_train)
2、选取最小的点,距中心分类最小的就是质心点
representative_digits_idx = np.argmin(x_digits_dist,axis=0)#
x_representative_digits = x_train[representative_digits_idx]
3、显示:
plt.figure(figsize=(8, 2))
for index, x_representative_digit in enumerate(x_representative_digits):
plt.subplot(k // 10, 10, index + 1)
plt.imshow(x_representative_digit.reshape(8, 8),
cmap="binary", interpolation="bilinear")
plt.axis('off')
plt.show()
4、看图,人工写出结果,进行监督学习
y_representative_digits = np.array([
4, 8, 0, 6, 8, 3, 7, 7, 9, 2,
5, 5, 8, 5, 2, 1, 2, 9, 6, 1,
1, 6, 9, 0, 8, 3, 0, 7, 4, 1,
6, 5, 2, 4, 1, 8, 6, 3, 9, 2,
4, 2, 9, 4, 7, 6, 2, 3, 1, 1])
log_reg = LogisticRegression(random_state=42)
log_reg.fit(x_representative_digits, y_representative_digits)
log_reg.score(x_test, y_test)
0.92