聚类
分类 vs. 聚类
class cluster
有监督 无监督
样本相似性:欧氏距离
欧几里得
《几何原理》
不同维度的距离求解:
P(x1) - Q(x2): |x1-x2| = sqrt((x1-x2)2)
P(x1,y1) - Q(x2,y2): sqrt((x1-x2)2+(y1-y2)2)
P(x1,y1,z1) - Q(x2,y2,z2):sqrt((x1-x2)2+ (y1-y2)2+(z1-z2)2)
用两个样本对应特征值之差的平方和之平方根,即欧氏距离,来表示这两个样本的相似性。
K均值算法
聚类中心:任意一个聚类成员与该聚类中心的距离一定小于该成员与其他聚类中心的距离。
几何中心:聚类中所有成员对应特征值的算数平均数表示的虚拟样本-抽象性。
理想聚类:聚类中心与几何中心重合。
在总样本空间中,随机选择K个样本作为初始聚类中心,计算所有样本距离每个聚类中心的欧氏距离,离哪个中心斤就隶属于该中心所表示的类别,这样就完成了一次聚类划分,针对所得到的每个聚类,计算其样本集的几何中心,如果几何中心与计算中心不重合,以几何中心作为新的聚类中心重新计算每个样本与其划分所依据的聚类中心重合或足够接近为止。
问题:
- 聚类数K需要事先知道。
通过性能指标优选最好的K - 初始聚类中心的选择可能会影响最终的聚类划分结果。
以最大间距原则选择初始的聚类中心
示例:
import numpy as np
import sklearn.cluster as sc
import matplotlib.pyplot as mp
x = []
with open(r'C:\Users\Cs\Desktop\机器学习\ML\data\multiple3.txt', 'r') as f:
for line in f.readlines():
data = [float(substr) for substr
in line.split(',')]
x.append(data)
x = np.array(x)
# K均值聚类器,n_clusters聚类数(核心数)
model = sc.KMeans(n_clusters=4)
model.fit(x)
centers = model.cluster_centers_
l, r, h = x[:, 0].min() - 1, x[:, 0].max() + 1, 0.005
b, t, v = x[:, 1].min() - 1, x[:, 1].max() + 1, 0.005
grid_x = np.meshgrid(np.arange(l, r, h),
np.arange(b, t, v))
flat_x = np.c_[grid_x[0].ravel(), grid_x[1].ravel()]
flat_y = model.predict(flat_x)
grid_y = flat_y.reshape(grid_x[0].shape)
pred_y = model.predict(x)
mp.figure('K-Means Cluster', facecolor='lightgray')
mp.title('K-Means Cluster', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.pcolormesh(grid_x[0], grid_x[1], grid_y,
cmap='gray')
mp.scatter(x[:, 0], x[:, 1], c=pred_y, cmap='brg',
s=80)
mp.scatter(centers[:, 0], centers[:, 1], marker='+',
c='gold', s=1000, linewidth=1)
mp.show()
图片量化
通过聚类的方法,将图片中的不同颜色(或者灰度的不同亮度)进行聚类,得到单色图。
import numpy as np
import cv2
import sklearn.cluster as sc
import matplotlib.pyplot as mp
image1 = cv2.imread(r'C:\Users\Cs\Desktop\3.jpg', cv2.IMREAD_GRAYSCALE)
model=sc.KMeans(2)
# 转换成一维
model.fit(image1.reshape((-1,1)))
y=model.labels_
print("y:",y)
centers=model.cluster_centers_
print("centers:",centers)
# 通过网筛得到图片矩阵
x=centers[y].reshape(image1.shape)
mp.imshow(x)
mp.show()
均值漂移算法
首先假定样本空间中的每个聚类均服从某种已知的概率分布规则,然后用不同的概率密度函数拟合样本中的统计直方图,不断移动密度函数的中心(均值)的位置,直到获得最佳拟合效果为止。这些概率密度函数的峰值点就是聚类的中心,再根据每个样本距离各个中心的距离,选择最近聚类中心所属的类别作为该样本的类别。
1)聚类数不必事先已知,算法会自动识别出统计直方图的中心数量。
2)聚类中心不依据于最初假定,聚类划分的结果相对稳定。
3)样本空间应该服从某种概率分布规则,否则算法的准确性会大打折扣。
聚类中心:
k均值算法的聚类中心:几何中心----------------\基于中心
均值漂移算法的聚类中心:随机分布中心------/ 的预测
代码:
import numpy as np
import sklearn.cluster as sc
import matplotlib.pyplot as mp
x = []
with open('../../data/multiple3.txt', 'r') as f:
for line in f.readlines():
data = [float(substr) for substr
in line.split(',')]
x.append(data)
x = np.array(x)
# 量化带宽,决定每次调整概率密度函数的步进量
bw = sc.estimate_bandwidth(x, n_samples=len(x),
quantile=0.1)
# 均值漂移聚类器,bin_seeding:如果为真,初始化点不是所有点,可以加快迭代速度,初始化位置更少
model = sc.MeanShift(bandwidth=bw, bin_seeding=True)
model.fit(x)
centers = model.cluster_centers_
...
凝聚层次算法
首先假定每个样本都是一个独立的聚类,如果统计出来的聚类数大于期望的聚类数,则从每个样本出发寻找离自己最近的另一个样本,与之聚集,形成更大的聚类,同时令总聚类数减少,不断重复以上过程,直到统计出来的聚类数达到期望值为止。
1)聚类数k必须事先已知。
借助某些评估指标,优选最好的聚类数。
2)没有聚类中心的概念,因此只能在训练集中划分聚类,但不能对训练集以外的未知样本确定其聚类归属。
3)在确定被凝聚的样本时,除了以距离作为条件以外,还可以根据连续性来确定被聚集的样本。
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import numpy as np
import sklearn.cluster as sc
import matplotlib.pyplot as mp
x = []
with open('../../data/multiple3.txt', 'r') as f:
for line in f.readlines():
data = [float(substr) for substr
in line.split(',')]
x.append(data)
x = np.array(x)
# 凝聚层次聚类器
model = sc.AgglomerativeClustering(n_clusters=4)
pred_y = model.fit_predict(x)
mp.figure('Agglomerative Cluster',
facecolor='lightgray')
mp.title('Agglomerative Cluster', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.scatter(x[:, 0], x[:, 1], c=pred_y, cmap='brg',
s=80)
mp.show()
基于距离的凝聚:块状凝聚
基于线性(连续性)的凝聚:线状凝聚
凝聚层次算法的线性凝聚方式
凝聚成此算法可以线性凝聚和块状凝聚。具体使用如下:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import numpy as np
import sklearn.cluster as sc
import sklearn.neighbors as nb
import matplotlib.pyplot as mp
n_samples = 500
t = 2.5 * np.pi * (1 + 2 * np.random.rand(n_samples, 1))
x = 0.05 * t * np.cos(t)
y = 0.05 * t * np.sin(t)
n = 0.05 * np.random.rand(n_samples, 2)
x = np.hstack((x, y)) + n
# 无连续性的凝聚层次聚类器
model_nonc = sc.AgglomerativeClustering(linkage='average', n_clusters=3)
pred_y_nonc = model_nonc.fit_predict(x)
# 近邻筛选器
conn = nb.kneighbors_graph(x, 10, include_self=False)
# 有连续性的凝聚层次聚类器
model_conn = sc.AgglomerativeClustering(linkage='average', n_clusters=3,
connectivity=conn)
pred_y_conn = model_conn.fit_predict(x)
mp.figure('Nonconnectivity',
facecolor='lightgray')
mp.title('Nonconnectivity', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.axis('equal')
mp.scatter(x[:, 0], x[:, 1], c=pred_y_nonc, cmap='brg', alpha=0.5, s=60)
mp.figure('Connectivity', facecolor='lightgray')
mp.title('Connectivity', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.axis('equal')
mp.scatter(x[:, 0], x[:, 1], c=pred_y_conn, cmap='brg', alpha=0.5, s=60)
mp.show()
轮廓系数
好的聚类:内密外疏,同一个聚类内部的样本要足够密集,不同聚类之间样本要足够疏远。
电视机
皮夹克
电冰箱
羽绒服
好!
A : 电视机,电冰箱
B : 皮夹克,羽绒服
差!
A : 电视机,羽绒服
B : 电冰箱,皮夹克
通过轮廓系数表示聚类内密外输的程度,即聚类的性别。
一个样本的轮廓系数:s=(b-a)/max(a,b)
将整个样本空间中所有样本的轮廓系数取算数平均值,作为聚类划分的性能指标s。
-1 <----- 0 -----> 1
最差 聚类重叠 最好
sm.silhouette_score(输入集, 输出集, sample_size=样本数, metric=距离算法)->平均轮廓系数
距离算法:euclidean,欧几里得距离
输出值通过训练的model.predict(x)得到
import numpy as np
import sklearn.cluster as sc
import sklearn.metrics as sm
import matplotlib.pyplot as mp
x = []
with open(r'C:\Users\Cs\Desktop\机器学习\ML\data\multiple3.txt', 'r') as f:
for line in f.readlines():
data = [float(substr) for substr
in line.split(',')]
x.append(data)
x = np.array(x)
# K均值聚类器
model = sc.KMeans(n_clusters=4)
model.fit(x)
centers = model.cluster_centers_
l, r, h = x[:, 0].min() - 1, x[:, 0].max() + 1, 0.005
b, t, v = x[:, 1].min() - 1, x[:, 1].max() + 1, 0.005
grid_x = np.meshgrid(np.arange(l, r, h),
np.arange(b, t, v))
flat_x = np.c_[grid_x[0].ravel(), grid_x[1].ravel()]
flat_y = model.predict(flat_x)
grid_y = flat_y.reshape(grid_x[0].shape)
pred_y = model.predict(x)
# 打印平均轮廓系数
print(sm.silhouette_score(
x, pred_y, sample_size=len(x),
metric='euclidean'))
mp.figure('K-Means Cluster', facecolor='lightgray')
mp.title('K-Means Cluster', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.pcolormesh(grid_x[0], grid_x[1], grid_y,
cmap='gray')
mp.scatter(x[:, 0], x[:, 1], c=pred_y, cmap='brg',
s=80)
mp.scatter(centers[:, 0], centers[:, 1], marker='+',
c='gold', s=1000, linewidth=1)
mp.show()
DBSCAN(带噪声的基于密度的聚类)算法
DBSCAN(带噪声的基于密度的聚类)算法
核心思想:朋友的朋友也是朋友
从样本空间中任意选择一个样本,以事先给定的半径做圆,凡被该圆圈中的样本都视为与该样本处于相同的聚类,以这些被圈中的样本为圆心继续做圆,重复以上过程,不断扩大被圈中样本的规模,直到再也没有新的样本加入为止,至此即得到一个聚类。于剩余样本中,重复以上过程,直到耗尽样本空间中的所有样本为止。
1)事先给定的半径会影响最后的聚类效果,可以借助轮廓系数选择较优的方案。
2)根据聚类的形成过程,把样本细分为以下三类:
外周样本:被其它样本聚集到某个聚类中,但无法再引入新样本的样本。
孤立样本:聚类中的样本数低于所设定的下限,则不称其为聚类,反之称其为孤立样本。
核心样本:除了外周样本和孤立样本以外的样本。
代码:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import numpy as np
import sklearn.cluster as sc
import sklearn.metrics as sm
import matplotlib.pyplot as mp
x = []
with open(r'C:\Users\Cs\Desktop\机器学习\ML\data\perf.txt', 'r') as f:
for line in f.readlines():
data = [float(substr) for substr
in line.split(',')]
x.append(data)
x = np.array(x)
# epsilons:
epsilons, scores, models = np.linspace(0.3, 1.2, 10), [], []
for epsilon in epsilons:
# DBSCAN聚类器
model = sc.DBSCAN(eps=epsilon, min_samples=5)
model.fit(x)
# 获取当前model的轮廓系数
score = sm.silhouette_score(x, model.labels_, sample_size=len(x), metric='euclidean')
scores.append(score)
models.append(model)
scores = np.array(scores)
best_index = scores.argmax()
# 得到最佳半径系数
best_epsilon = epsilons[best_index]
print(best_epsilon)
# 得到最佳轮廓系数
best_score = scores[best_index]
print(best_score)
# 得到最佳模型
best_model = models[best_index]
# 得到聚类结果,注意fit_predict方法,这里居然没有predict方法
pred_y = best_model.fit_predict(x)
core_mask = np.zeros(len(x), dtype=bool)
# DBSCAN属性:
#core_sample_indices_: array, shape = [n_core_samples]:核心点标签。
# components_: array, shape = [n_core_samples, n_features]:通过培训找到的每个核心样本的副本。
# labels_: array, shape = [n_samples]:将数据集中每个点的标签聚类到fit()中。噪声样本被标记为-1。
#指数核心样本的下标
core_mask[best_model.core_sample_indices_] = True
print("core_sample_indices_:",best_model.core_sample_indices_)
print("coremask:",core_mask)
# 噪声点
offset_mask = best_model.labels_ == -1
#边缘点
periphery_mask = ~(core_mask | offset_mask)
mp.figure('DBSCAN Cluster', facecolor='lightgray')
mp.title('DBSCAN Cluster', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
labels = set(pred_y)
cs = mp.get_cmap('brg', len(labels))(
range(len(labels)))
mp.scatter(x[core_mask][:, 0], x[core_mask][:, 1],
c=cs[pred_y[core_mask]], s=80,
label='Core')
mp.scatter(x[periphery_mask][:, 0], x[periphery_mask][:, 1],
edgecolor=cs[pred_y[periphery_mask]],
facecolor='none', s=80, label='Periphery')
mp.scatter(x[offset_mask][:, 0], x[offset_mask][:, 1],
c=cs[pred_y[offset_mask]], marker='x',
s=80, label='Offset')
mp.legend()
mp.show()
KNN算法
K - 若干个
N - Nearest,最近
N - Neighbors, 邻居
分类
对于一个未知类别的样本,在其周围寻找距离最近的K个已知样本,根据与距离成反比的加权投票,决定未知样本的类别。
代码:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import numpy as np
import sklearn.neighbors as sn
import matplotlib.pyplot as mp
train_x, train_y = [], []
with open(r'C:\Users\Cs\Desktop\机器学习\ML\data\knn.txt', 'r') as f:
for line in f.readlines():
data = [float(substr) for substr
in line.split(',')]
train_x.append(data[:-1])
train_y.append(data[-1])
train_x = np.array(train_x)
train_y = np.array(train_y, dtype=int)
# 创建KNN分类器模型
model = sn.KNeighborsClassifier(
n_neighbors=10, weights='distance')
# 训练KNN分类器模型
model.fit(train_x, train_y)
# 点阵水平边界和步长
l, r, h = train_x[:, 0].min() - 1, train_x[:, 0].max() + 1, 0.005
# 点阵垂直边界和步长
b, t, v = train_x[:, 1].min() - 1, train_x[:, 1].max() + 1, 0.005
# 生成二维点阵
# _ grid_x
# ^ |h| /
# t | * * * *
# | * * * *-- v
# b | * * * *--
# +-------->
# l r
grid_x = np.meshgrid(np.arange(l, r, h), np.arange(b, t, v))
# 将点阵中每个点的水平坐标和垂直坐标作为
# 样本的两个特征合并成一个两列的二维数组
flat_x = np.c_[grid_x[0].ravel(), grid_x[1].ravel()]
# 利用KNN分类器模型预测点阵的类别
flat_y = model.predict(flat_x)
# 将一维形式的类别变成点阵形式的二维数组
grid_y = flat_y.reshape(grid_x[0].shape)
test_x = np.array([
[2.2, 6.2],
[3.6, 1.8],
[4.5, 3.6]])
pred_test_y = model.predict(test_x)
# 返回到邻居点距离和邻居点坐标
nn_distance, nn_indices = model.kneighbors(test_x)
# 绘制训练样本和分类边界
mp.figure('KNN Classification', facecolor='lightgray')
mp.title('KNN Classification', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.pcolormesh(grid_x[0], grid_x[1], grid_y,
cmap='gray')
mp.scatter(train_x[:, 0], train_x[:, 1], c=train_y,
cmap='brg', s=60)
mp.scatter(test_x[:, 0], test_x[:, 1], c=pred_test_y,
cmap='brg', s=60, marker='D')
mp.scatter(train_x[nn_indices[0], 0],
train_x[nn_indices[0], 1], marker='D',
edgecolor='r', facecolor='none', s=180)
mp.scatter(train_x[nn_indices[1], 0],
train_x[nn_indices[1], 1], marker='D',
edgecolor='b', facecolor='none', s=180)
mp.scatter(train_x[nn_indices[2], 0],
train_x[nn_indices[2], 1], marker='D',
edgecolor='g', facecolor='none', s=180)
mp.show()
对于类别比例相差悬殊的样本不适合用KNN法预测分类。
2.回归
对于一个未知输出的样本,在其周围寻找距离最近的K个已知样本,根据与距离成反比的加权平均,决定未知样本的输出。
代码:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import numpy as np
import sklearn.neighbors as sn
import matplotlib.pyplot as mp
train_x = 10 * np.random.rand(100, 1) - 5
train_y = np.sinc(train_x).ravel()
train_y += 0.2 * (0.5 - np.random.rand(
train_y.size))
model = sn.KNeighborsRegressor(
n_neighbors=10, weights='distance')
model.fit(train_x, train_y)
test_x = np.linspace(-5, 5, 10000).reshape(-1, 1)
test_y = np.sinc(test_x).ravel()
pred_test_y = model.predict(test_x)
mp.figure('KNN Regression', facecolor='lightgray')
mp.title('KNN Regression', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.grid(linestyle=':')
mp.scatter(train_x, train_y, c='dodgerblue',
s=60, label='Training')
mp.plot(test_x, test_y, '--', c='limegreen',
linewidth=1, label='Testing')
mp.plot(test_x, pred_test_y, c='orangered',
label='Predicted')
mp.legend()
mp.show()
对于预测输入远远偏离训练集的样本不适合用KNN法回归预测。