[机器学习笔记]k-means实战 (以wine数据集为例)

本博客将以wine数据集,一步一步的演示K-means实战的全过程,让大家学会和使用k-means方法进行聚类(大佬勿锤)


1.数据集来源

在这里插入图片描述
特征分别为:酒精 苹果酸 艾熙 灰分碱性 镁 总酚类 黄酮类 非淀粉酚类 原花青素 颜色强度 色调 稀释葡萄酒的OD280/OD315 脯氨酸
数据来自uci,点击此处即可下载


2.背景知识

1.评价聚类的常用指标指标

  • 兰德指数(Rand index)
  • 互信息(MI)
  • 同质化得分(Homogeneity)
  • 完整性得分(Complenteness)
  • v_meansure_score
  • 轮廓系数(Silhouette)
  • calinski-harabaz Index

这里解释两个常用的兰德指数和轮廓系数
兰德指数:假设U是外部评价标准即true_label,而V是聚类结果。设定四个统计量:

a为在U中为同一类且在V中也为同一类别的数据点对数
b为在U中为同一类但在V中却隶属于不同类别的数据点对数
c为在U中不在同一类但在V中为同一类别的数据点对数
d为在U中不在同一类且在V中也不属于同一类别的数据点对数

此时兰德指数为:

A R T = a + d a + b + c + d ART=\frac{a+d}{a+b+c+d} ART=a+b+c+da+d


轮廓系数:适用于实际类别信息未知的情况,用来计算所有样本的平均轮廓系数。对于单个样本,设a是该样本与它同类别中其他样本的平均距离,b是与它距离最近不同类别中样本的平均距离.
轮廓系数为:
s ( i ) = b − a m a x ( a , b ) s(i)=\frac{b-a}{max(a,b)} s(i)=max(a,b)ba


2.数据预处理的常用方法

  • 标准化,均值去除和按方差比例缩放
    • scale 零均值单位方差
    • StandardScaler计算训练集的平均值和标准差
  • 归一化,将数据特征缩放至某一范围
    • MinMaxScaler(最小最大值标准化)
    • MaxAbsScaler(绝对值最大标准化)

这些方法适用于不同地方:

  • 数据集的标准化:当个体特征太过或明显不遵从高斯正态分布时,标准化表现的效果较差。实际操作中,经常忽略特征数据的分布形状,移除每个特征均值,划分离散特征的标准差,从而等级化,进而实现数据中心化。
  • 数据集的归一化:有时数据集中数字差最大的属性对计算结果影响较大,或者有时数据集的标准差非常非常小,有时数据中有很多很多零(稀疏数据)需要保存住0元素。

这里介绍一下常用的归一化处理:
归一化:将任意取值范围内的特征值传换为[0,1]或者[-1,1]内的值
公式
n e w v a l u e s = o l d v a l u e s − m i n m a x − m i n newvalues=\frac{oldvalues - min}{max-min} newvalues=maxminoldvaluesmin
min和max分别为数据集的最小值和最大值


3.k的选择

常用方法是:肘方法
K_means参数的最优解是以成本函数最小化为目标,成本函数为各个类畸变程度之和,
每个类的畸变程度等于该类重心与其内部成员位置距离的平方和,
但是平均畸变程度会随着K的增大先减小后增大,所以可以求出最小的平均畸变程度。


3.实战应用

对于wine的数据,我们希望可以根据特征值聚类出不同的红酒。

第一次尝试,我们简单的读取数据,利用knn算法,计算兰德指数,同质化得分和平均轮廓系数,并绘制聚类图。
我们发现效果并不好
在这里插入图片描述
在这里插入图片描述


改进:

通过观察不难发现,特征值之间的数值相差过大,导致在利用欧式距离计算的时候,会使得部分特征值失去效果。
在这里插入图片描述
所以采用了归一化处理数据。

min_max_scaler = preprocessing.MinMaxScaler()
X = min_max_scaler.fit_transform(X)

另外,对于k的选择,本文也加上了肘方法。

K = range(1, 10)
meandistortions = []
for k in K:
    kmeans = KMeans(n_clusters=k)
    kmeans.fit(X)
    meandistortions.append(sum(np.min(cdist(X, kmeans.cluster_centers_, 'euclidean'), axis=1)) / X.shape[0])
plt.plot(K, meandistortions, 'bx-')
plt.xlabel('k')
plt.ylabel('meandistortions')
plt.title('best K of the model');
plt.show()

如图k选择3
在这里插入图片描述

此时加上。上面两步以后。效果得到了明显的提升。
但是数据聚类效果依然不够好。
分享原因可能是uci的数据特征值不够精准,数据存在噪声。
从下文可以看出wine原本特征值有30个,可是现在只有13个。
等到博主功力更深厚在回来改进。

I think that the initial data set had around 30 variables, but
for some reason I only have the 13 dimensional version.
I had a list of what the 30 or so variables were, but a.)
I lost it, and b.), I would not know which 13 variables
are included in the set.

在这里插入图片描述
在这里插入图片描述


下面是源码

#!/usr/bin/env python
#-*- coding:utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn import preprocessing
from scipy.spatial.distance import cdist
from sklearn import metrics

# 读取原始数据
X = []
y_true = []
id = []

f = open('wine.data')
for line in f:
    y = []
    for index,item in enumerate(line.split(",")):
        if index == 0:
            id.append(int(item))
            continue
        y.append(float(item))
    X.append(y)
# 转化为numpy array
X = np.array(X)
y_true = np.array(id)


min_max_scaler = preprocessing.MinMaxScaler()
X = min_max_scaler.fit_transform(X)


K = range(1, 10)
meandistortions = []
for k in K:
    kmeans = KMeans(n_clusters=k)
    kmeans.fit(X)
    meandistortions.append(sum(np.min(cdist(X, kmeans.cluster_centers_, 'euclidean'), axis=1)) / X.shape[0])
plt.plot(K, meandistortions, 'bx-')
plt.xlabel('k')
plt.ylabel('meandistortions')
plt.title('best K of the model');
plt.show()
n_clusters = 3


cls = KMeans(n_clusters).fit(X)
y_pre = cls.predict(X)

n_samples,n_features=X.shape     #总样本量,总特征数
inertias = cls.inertia_   #样本距离最近的聚类中心的总和
adjusted_rand_s=metrics.adjusted_rand_score(y_true,y_pre)           #调整后的兰德指数
homogeneity_s=metrics.homogeneity_score(y_true,y_pre)               #同质化得分
silhouette_s=metrics.silhouette_score(X,y_pre,metric='euclidean')   #平均轮廓系数
print("兰德指数ART",adjusted_rand_s)
print("同质化得分homo",homogeneity_s)
print("平均轮廓系数",silhouette_s)

centers=cls.cluster_centers_  #各类别中心

colors=['#ff0000','#00ff00','#0000ff']   #设置不同类别的颜色
plt.figure()    #建立画布
for i in range(n_clusters):    #循环读取类别
    index_sets=np.where(y_pre==i)  #找到相同类的索引集合、
    cluster=X[index_sets]   #将相同类的数据划分为一个聚类子集
    plt.scatter(cluster[:,0],cluster[:,1],c=colors[i],marker='.')   #展示聚类子集内的样本点
    plt.plot(centers[i][0],centers[i][1],'*',markerfacecolor=colors[i],markeredgecolor='k',markersize=6)
plt.show()


评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值