机器学习——K-means算法

一、聚类算法

1. 聚类问题

给定一个元素集合 D,其中每个元素具有 n 个可观察属性,使用某 种算法将 D 划分成 k 个子集,要求每个子集内部的元素之间相异度尽可能低,而不同子集的 元素相异度尽可能高。其中每个子集叫做一个簇。

2. 聚类和分类的区分

  • 聚类:而聚类是观察式学习,在聚类前可以 不知道类别甚至不给定类别数量,是无监督学习的一种
  • 分类:分类是示例式学习,要求分类前明确各个类别,并断言每个元素映射到一个类别

二、K-means介绍

K-means是K均值算法,需要提前指定K值,K值决定了数据集被分成多少个子集。
无监督算法中存在一种算法叫聚类算法,聚类算法中最经典的是K-means算法。

三、K-means原理

1、从 D 中随机取 k 个元素,作为 k 个簇的各自的中心(质心)。
2、分别计算剩下的元素到 k 个簇中心的相异度,将这些元素分别划归到相异度最低的簇。
3、根据聚类结果,重新计算 k 个簇各自的中心,计算方法是取簇中所有元素各自维度 的算术平均数。
4、将 D 中全部元素按照新的中心重新聚类。
5、重复第 4 步,直到聚类结果不再变化。
6、将结果输出。
n: 元素个数,k:第一步中选取的元素个数,m: 每个元素的特征项个数,T: 第 5 步中 迭代的次数


K-means聚类原理

四、K-means特点

  • 需要指定K值:预先指定的参数,称为超参数
  • 受初始值(初始聚类中心)的影响,达到局部最优效果
  • 受离群点(异常值)的影响。通常处理方式是剔除异常值
  • 距离表征相似度,特征量级不同,需要进行数据标准化
    注意:K-means算法之前,通常要进行数据预处理:数据异常值剔除、数据标准化

五、K-means简单代码示例

"""
步骤:
1. 第一次分类得到分组结果
2. 修改第一次的代码:得到最终分组结果
3. 代码优化:停止替换聚类中心的条件(有时候结果很接近但是达不到准确的相等结果所以增加了运算的次数)
4. 可视化,查看聚类的结果
5. 数据标准化,可视化,查看每次聚类时聚类中心的变化
"""

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

plt.rcParams["font.sans-serif"] = "SimHei"
# 本身可以支持负号,设置支持中文之后,负号无法正常显示,设置如下代码使其支持负号
plt.rcParams['axes.unicode_minus'] = False


def build_data():
    company = pd.read_csv('../data_ML/company.csv', encoding='ANSI')
    # 取有价值的特征
    data = company[['平均每次消费金额', '平均消费周期(天)']]
    return data


def stand_scalar(val):
    """标准差标准化"""
    mean_val = val.mean()
    std_val = val.std()
    return (val - mean_val) / std_val


# def min_max_scalar(val):
#     """离差标准化"""
#     return (val - val.min()) / (val.max() - val.min())


def main(center):
    """
    以旧的聚类中心为参数
    输出新的聚类中心
    """
    # 新建一个空列表,用来存放每条记录的类别
    label = []
    # 计算每条记录到K的距离,选出最小值,得到索引
    for sample in data[['平均每次消费金额', '平均消费周期(天)']].values:
        # 每个样本到K点的欧氏距离的平方
        dis = ((sample - center) ** 2).sum(axis=1)
        # 得到最小的举例的索引,索引表示分类
        ind = np.argmin(dis)
        label.append(ind)
    # 将分类添加data中
    data['label'] = label
    # 新的聚类中心
    new_center = data.groupby('label').mean()
    return new_center


def matp(center):
    """
    数据可视化
    :param data:
    :return:
    """
    # 画布清理
    plt.cla()

    for cls in range(3):
        part_data = data.loc[data['label'] == cls, :]
        plt.scatter(part_data['平均每次消费金额'], part_data['平均消费周期(天)'])

    # 聚类中心可视化
    print(center)
    plt.scatter(
        center[:, 0],
        center[:, 1],
        marker='*',
        s=200,
        c=['b', 'r', 'g'])

    plt.legend(["类0", "类1", "类2"])
    plt.xlabel('平均每次消费金额')
    plt.ylabel('平均每次消费金额')
    # 等待一秒
    plt.pause(1)


if __name__ == '__main__':
    # 打开开关
    plt.ion()
    # 取初始K值-聚类的中心
    data = build_data()
    center = np.array([[13, 1],
                       [100, 4],
                       [78, 9]])
    # 添加一条全零的label列表
    label = [0] * data.shape[0]
    times = 0
    data['label'] = 0
    while True:
        # 可视化
        matp(center)
        new_center = main(center)
        times += 1
        print('第%d次' % times)
        new_label = data['label']
        # if np.all(new_center.values == center) or np.all(new_label == label):
        if np.all(new_center.values == center):
            break
        # 替换聚类中心
        center = new_center.values
        label = new_label

    print('新的聚类中心', new_center)
    print('最终分组结果', data)
    # 关闭开关
    plt.ioff()
    # 展示
    plt.show()

小拓展-动态可视化matplotlib

    1. 打开开关:plt.ion()
    1. 画布清理:plt.cla()
    1. 画图:
    1. 关闭开关:plt.ioff()
    1. 展示:plt.show()

六、sklearn的K-means算法应用

导包:
# 导包:kmeans
from sklearn.cluster import KMeans
# 预处理
from sklearn.preprocessing import StandardScaler  # 标准差标准化
from sklearn.preprocessing import MinMaxScaler  # 离差标准化
from sklearn.preprocessing import MaxAbsScaler  # 小数定标标准化
函数:km = KMeans()
参数:
  • n_clusters:K值的设置(聚类中心的数量)
  • init:聚类中心初始化的方式,默认值k-means++
  • max_iter:最大迭代次数
  • random_state:相当于数组里面的随机种子,随机生成后的值不再变化
方法:

最终的聚类中心:km.cluster_centers_
聚类中心初始化——k-means++:

  1. 随机选取一个点作为聚类中心1
  2. 选择与该点最远的一个点作为聚类中心2
  3. 选择距离前两个聚类中心和最远的点作为聚类中心3
简单代码示例:
import pandas as pd
import matplotlib.pyplot as plt
# 导包:kmeans
from sklearn.cluster import KMeans
# 预处理
from sklearn.preprocessing import StandardScaler  # 标准差标准化
from sklearn.preprocessing import MinMaxScaler  # 离差标准化
from sklearn.preprocessing import MaxAbsScaler  # 小数定标标准化

# 默认不支持中文,可以设置rc参数,使其显示中文
plt.rcParams["font.sans-serif"] = "SimHei"
# 本身可以支持负号,设置支持中文之后,负号无法正常显示,设置如下代码使其支持负号
plt.rcParams['axes.unicode_minus'] = False


def build_data():
    company = pd.read_csv('../data_ML/company.csv', encoding='ANSI')
    # 取有价值的特征
    data = company[['平均每次消费金额', '平均消费周期(天)']]
    return data


def k_means(data):
    """
    K均值处理
    :return: 返回最终的聚类中心
    """
    # 1. 实例化算法
    # n_clusters:K值的设置
    # random_state:相当于数组里面的随机种子,随机生成后的值不再变化
    km = KMeans(n_clusters=3, random_state=1)
    # 2.拟合:无监督算法没有标签,参数为数据的特征
    km.fit(data)
    # 3.预测
    y_pred = km.predict(data)
    data['类别'] = y_pred
    print(data)
    print('预测结果:', y_pred)
    # 最终的聚类中心
    print(km.cluster_centers_)
    return km.cluster_centers_


def show_result(data, center):
    for cls in range(3):
        part_data = data.loc[data["类别"] == cls, :]
        plt.scatter(part_data["平均每次消费金额"], part_data["平均消费周期(天)"])
        # print(part_data)
    # 聚类中心可视化
    plt.scatter(center[:, 0], center[:, 1],
                marker='*', s=200, c=['b', 'r', 'g'],
                alpha=0.2)

    plt.legend(["类0", "类1", "类2"])
    plt.xlabel("平均每次消费金额")
    plt.ylabel("平均消费周期(天)")
    plt.show()


def main():
    """
    主函数:主要写实现的逻辑
    :return:
    """
    # 获取数据
    data = build_data()
    # 数据标准化
    std = StandardScaler()
    data_std = std.fit_transform(data)
    print('转换后:\n', data_std)  # sklearn 返回值通常为数组
    data["平均每次消费金额"] = data_std[:, 0]
    data["平均消费周期(天)"] = data_std[:, 1]
    # kmeans处理
    new_center = k_means(data)
    # 可视化
    show_result(data, new_center)


if __name__ == '__main__':
    main()

七、轮廓系数

1. 轮廓系数的目的:对聚类中心的效果进行评估

2. 原理

轮廓系数原理

3. 轮廓系数结论

i为已聚类数据中的样本
bi为i到其他类中所有点的距离平均值,越大越好(说明类与类之间距离较远)
ai为i到其内部类中所有点的距离的平均值,越小越好(说明类内连接紧密)
轮廓系数的范围是[-1, 1],值越大,效果越好。

4.sklearn应用

# 导入
from sklearn.metrics import silhouette_score
# 计算轮廓系数
# 参数1:参与聚类的所有数据的样本
# 参数2:经过K-means算法预测的预测结果
score = silhouette_score(data, y_pred)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 230,527评论 6 544
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,687评论 3 429
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 178,640评论 0 383
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,957评论 1 318
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,682评论 6 413
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 56,011评论 1 329
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 44,009评论 3 449
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 43,183评论 0 290
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,714评论 1 336
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,435评论 3 359
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,665评论 1 374
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 39,148评论 5 365
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,838评论 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,251评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,588评论 1 295
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,379评论 3 400
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,627评论 2 380

推荐阅读更多精彩内容