scikit-learn机器学习七 (K-均值算法,PCA)

无监督学习任务

前面我们讨论的都是监督的学习任务,我们根据测试集的x_train,y_train来训练我们的模型,并最后用最后训练好的模型来预测x_test,最后将结果与y_test进行比较,得出accuracy

无监督的算法在训练时只需要特征矩阵x_train,不需要标签,当然得出的结果,我们也无法跟监督任务一样,通过和y_test的值进行对比来得出模型性能的好坏——我们需要使用其他的指标来衡量

聚类

而这里我们开始讨论无监督学习任务——聚类,聚类被用于在一个非标记数据集中发现类似观测值的群组

聚类常被用来探索数据集,并将其按照一定特征进行分组

K-均值算法

K-均值算法是一个迭代移动聚类中心的过程。它每次迭代更新聚类实例的均值位置,并找到离聚类中心最近的实例重新聚类。

K-均值算法又叫K-means算法,具体的算法的实现步骤如下:

  • 首先人为确定K的值——也就是确定需要分成的簇(cluster)的数目
  • 算法随机抽取K个样本作为最初的质心
  • 通过距离公式,将所有的样本分配到离他们最近的质心,生成K个簇
  • 对于每个簇重新计算它的质心
  • 根据新的质心重新分配样本所属的簇
  • 循环直到前后两次质心不变时迭代停止

k是一个代表聚类数量的超参数,它会自动观测实例分配到不同的聚类中,但是它无法决定最合适的聚类数量(需要人为调试),我们使用一种估计最优聚类数量的方法——肘部最优法

肘部最优法

我们使用不同的K值来绘制出代价函数的值,随着k值得增加,平均偏差会增加,而当它变化下降得最陡时的K值称为肘部。我们一般选取这个k值作为聚类的数量

例子:

import numpy as np
from sklearn.cluster import  KMeans
from scipy.spatial.distance import cdist
import matplotlib.pyplot as plt

c1x = np.random.uniform(1, 2, (1, 10))
c1y = np.random.uniform(1, 2, (1, 10))
c2x = np.random.uniform(3.5, 6, (1, 10))
c2y = np.random.uniform(3.5, 6, (1, 10))
x = np.hstack((c1x, c1y))
y = np.hstack((c2x, c2y))
z = np.vstack((x, y)).T
K = range(1, 10)
md = []
for k in K:
    kmeans = KMeans(n_clusters=k)
    kmeans.fit(z)
    md.append(sum(np.min(cdist(z, kmeans.cluster_centers_, 'euclidean'), axis=1))/z.shape[0])

plt.plot(K, md, 'bx-')
plt.xlabel('k')
plt.ylabel('average dispersion')
plt.title('selcet k with elbow method')
plt.show()

我们使用matplotlib绘制出的图为:

在这里插入图片描述
我们可以看到在K为2时,曲线的下降开始趋于缓慢,所以K为2就是肘部,就是我们要取的值

簇内平方和(inertia)

聚类算法所聚出的簇我们一般认为一个簇中的数据具有相似性,不同的簇的数据不同。所以我们追求簇内差异小,簇间差异大

所以我们用样本点到其所在簇的质心的距离来衡量聚类算法的好坏——簇内平方和(但其实这样会有风险后面再提)

我们先自己创建一个数据集:

from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt

X, y = make_blobs(n_samples=500, n_features=2, centers=4, random_state=1)

fig, ax1 = plt.subplots(1)
ax1.scatter(X[:, 0], X[:, 1], marker='o', s=8)
plt.show()

可视化:
在这里插入图片描述
我们可以朦胧的感知到应该分为2, 3, 4个簇会比较合适,下面我们分别让n_cluster=2, 3, 4然后计算他们的簇内平方和:

from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
# 生成数据集
X, y = make_blobs(n_samples=500, n_features=2, centers=4, random_state=1)

n_clusters = [2, 3, 4]

for i in n_clusters:
    cluster = KMeans(n_clusters=i, random_state=0).fit(X)

    y_pred = cluster.labels_

    centroid = cluster.cluster_centers_
    # 打印每个簇的质心的位置
    print(centroid)

    inertia = cluster.inertia_
    # 打印簇内平方和
    print(inertia)

    color = ["red", "pink", "orange", "gray"]
    fig, ax1 = plt.subplots(1)
    for j in range(i):
    	# 使用不同颜色代表不同簇
        ax1.scatter(X[y_pred == j, 0], X[y_pred == j, 1], marker='o', s=8, c=color[j])
        # 使用X来标记簇质心的位置
        ax1.scatter(centroid[:, 0], centroid[:, 1], marker="x", s=15, c="black")
    plt.show()

可视化:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
输出结果:

[[-7.75782734 -5.03639416] # 返回的矩阵为质心的位置,一个x坐标,一个y坐标
 [-1.54234022  4.43517599]]
3735.405674929567 # 打印的簇内平方和

[[-8.09286791 -3.50997357]
 [-1.54234022  4.43517599]
 [-7.0877462  -8.08923534]]
1903.5342237665059

[[-10.00969056  -3.84944007]
 [ -1.54234022   4.43517599]
 [ -6.08459039  -3.17305983]
 [ -7.09306648  -8.10994454]]
908.3855684760603

我们可以看到K=4时,簇内平方和最小,所以我们可以分为四个簇


评估聚类的方法——轮廓系数

上面我们提到了inertia这个指标,但是这个指标的缺陷也十分明显:

  1. 计算容易受到维度诅咒,不适合用来多次评估模型
  2. 对数据的分布假设有限,在很多特殊的簇分类时效果不佳(如环形,细长条形数据集)

所以我们引入另一个评估的方法——轮廓系数

轮廓系数是对聚类紧密程度和稀疏程度的衡量

当聚类内部很紧密且每个聚类之间的距离很远时,轮廓系数很大;
对于体积很大且相互重叠的聚类,轮廓系数很小

单个样本的轮廓系数计算:
在这里插入图片描述
a : 样本于自身所在簇中其他样本的相似度,等于样本与同一簇其他点的平均距离

b : 样本与其他簇中的样本的相似度,等于样本与另一个最近的簇中所有点的平均距离

变形:

在这里插入图片描述
我们很容易看出轮廓系数的取值在(-1, 1),越接近1表示与簇内样本越相似,与其他簇样本越不相似。为0说明两个样本相似度一样,本来应该是同一簇,越接近-1,则与簇外的样本更相似

我们可以这样编写代码计算轮廓系数:

import numpy as np
from sklearn.cluster import KMeans
from sklearn import metrics # 轮廓系数在这里面
import matplotlib.pyplot as plt

plt.subplot(3, 2, 1)
x1 = np.array([1, 2, 3, 1, 5, 6, 5, 5, 6, 7, 8, 9, 7, 9])
x2 = np.array([1, 3, 2, 2, 8, 6, 7, 6, 7, 1, 2, 1, 1, 3])
z = np.array(list(zip(x1, x2))).reshape(len(x1), 2)

plt.xlim([0, 10])
plt.ylim([0, 10])
plt.title('picture sample')
plt.scatter(x1, x2)
plt.xticks([])   # 这两行用于消除坐标,让图表看起来更简洁
plt.yticks([])
colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k', 'b'] # 设置颜色
markers = ['o', 's', 'D', 'v', '^', 'p', '*', '+'] # 设置图例的形状

tests = [2, 3, 4, 5, 8]
counter = 1
for t in tests:
    counter += 1
    plt.subplot(3, 2, counter)
    kmeans = KMeans(n_clusters=t).fit(z)
    for i, l in enumerate(kmeans.labels_):
        plt.plot(x1[i], x2[i], color=colors[l], marker=markers[l], ls='None')
        plt.xticks([])
        plt.yticks([])
    plt.xlim([0, 10])
    plt.ylim([0, 10])
    plt.title('K=%s, %0.3f' % (t, metrics.silhouette_score(z, kmeans.labels_, metric='euclidean')))

plt.show()

绘制的图形:

在这里插入图片描述
我们分别将K设置为2, 3, 4, 5, 8 然后通过轮廓系数来比较其分类的好坏,明显我们可以得出,当K=3时,轮廓系数最大,从绘制的图形我们也可以得知,三个聚类是最合适的

降维-PCA

我们知道当数据涉及到高维度时,维度诅咒就会对我们问题的解决产生巨大影响

当数据集维度数量增加,一个估计器所需的样本数量会成指数爆炸增长,而且从大数据中学校会耗费大量的时间,内存和处理能力,而且维度越高,数据的稀疏程度也就越高

我们使用PCA的技巧来缓和,估计器需要更多的样本从高维度数据中实现泛化

它通过将数据投影到低维度子空间,将一个高维度,可能相关的数据集降维到一个线性不相关主成分组成的低维度数据集

为什么我们要降维的另一个理由就是,高维数据我们无法可视化

这里使用鸢尾花
数据集来进行降维可视化

# 鸢尾花降维可视化
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.datasets import load_iris

data = load_iris()
y = data.target
x = data.data
pca = PCA(n_components=2)  # 减少到二维
reduced_x = pca.fit_transform(x)  # 返回减少维度后的数据矩阵
# print(reduced_x) 打印二维矩阵

red_x, red_y = [], []
blue_x, blue_y = [], []
green_x, green_y = [], []
for i in range(len(reduced_x)):
    if y[i] == 0:
        red_x.append(reduced_x[i][0])
        red_y.append(reduced_x[i][1])
    elif y[i] == 1:
        blue_x.append(reduced_x[i][0])
        blue_y.append(reduced_x[i][1])
    else:
        green_x.append(reduced_x[i][0])
        green_y.append(reduced_x[i][0])
plt.scatter(red_x, red_y, c='r', marker='x')
plt.scatter(blue_x, blue_y, c='b', marker='D')
plt.scatter(green_x, green_y, c='g', marker='.')
plt.show()

绘制图形:

在这里插入图片描述
我们可以很明显的将三个类别区分开来

感谢您的耐心阅读!努力变成自己想要变成的人吧!!!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

国家一级假勤奋研究牲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值