zoukankan      html  css  js  c++  java
  • 机器学习笔记6:K-Means

    目标函数

    目标函数的表现函数

    假设:点集合为D,所有分类的中心点解和为M,如下:

    [D= [X_1,X_2,...X_n], X_iin R^{d} \ M=[mu_1,mu_2,...mu_k] \ ]

    其中向量(ar{r}),用来标识分类,如果点(X_i)(mu_j)最近,那么(ar{r}_i=(0,0,0...1....0)),即第j位是1,其他位都是0.

    [ar{r}=(x_1,x_2,..,x_k),x_i in {0,1} \ ]

    那么,K-mean的目标函数可以写为:

    [f(mu,r)= minsum_{i=1}^{n}sum_{k=1}^{k}r_ik(x_i-mu_k)^2 \ ]

    针对u和r求解:

    1. 假定u已知,寻找最优的r,即找到每个点离哪个中心点最近;
    2. 假定r已知,寻找最优的u,即知道一群点的分类之后,找到每群点的中心点
    3. 将1、2步骤多循环几次求得最优解

    最优解的表达式的意义:

    • 说白了,假设有n个点,点i到其所属分类(假设分类编号为1到k)的中心点的距离为(d_ik),那么让n个(d_ik)加在一起的值最小,就是结果。
    • K-means(K均值聚类算法),是一种迭代求解的聚类分析算法,就是把相似的成员弄到一起。

    K-means聚类的形象化展示

    素材引用自贪心学院:https://github.com/GreedyAIAcademy/Machine-Learning

    通俗地讲,就是先根据每个点距离哪个中心点最近就染成哪个中心点的颜色,然后再找到所有同一个颜色的点的中心点作为新的中心点,循环多次即得到想要的结果。
    什么是K-means++呢?K-means++就是在最初取中心点的时候,让中心点的距离相对远一些,这样可以减小循环的次数。

    聚类前

    第一轮循环

    第二轮循环

    第三轮循环

    最终结果

    演示代码:

    # 导入相应的包
    from copy import deepcopy
    import numpy as np
    import pandas as pd
    from matplotlib import pyplot as plt
    
    # 导入数据
    data = pd.read_csv('data.csv')
    print("Input Data and Shape")
    print(data.shape)
    data.head()
    
    # 提取字段并可视化数据,使用scatter plot
    f1 = data['V1'].values
    f2 = data['V2'].values
    X = np.random.random((200, 2))*10
    plt.scatter(X[:,0], X[:,1], c='black', s=6)
    
    
    # K-means里的K值
    k = 3
    # 随机初始化K个中心点,把结果存储在C
    C_x = np.random.randint(0, np.max(X), size=k)
    C_y = np.random.randint(0, np.max(X), size=k)
    C = np.array(list(zip(C_x, C_y)), dtype=np.float32)
    
    print("初始化之后的中心点:")
    print(C)
    
    # 把中心点也展示一下
    plt.scatter(X[:,0], X[:,1], c='#050505', s=7)
    plt.scatter(C[:,0], C[:,1], marker='*', s=300, c='g')
    
    # 存储之前的中心点
    C_old = np.zeros(C.shape)
    clusters = np.zeros(len(X)) # K=3,  clusters = [0,0,1,2,1,0]
    
    def dist(a, b, ax=1):
        return np.linalg.norm(a - b, axis=ax)
    
    error = dist(C, C_old, None)
    colors = ['r', 'g', 'b', 'y', 'c', 'm']
    # 循环算法,直到收敛。收敛的条件就是,判断当前的中心点与之前的中心点之间有没有变化,没有变化距离就会变成0,然后抛出异常
    while error != 0:
        # Assigning each value to its closest cluster
        for i in range(len(X)):
            distances = dist(X[i], C)
            cluster = np.argmin(distances)
            clusters[i] = cluster
        # 在计算新的中心点之前,先把旧的中心点存下来,以便计算距离
        fig, ax = plt.subplots()
    
        C_old = deepcopy(C)
        for i in range(k):
            points = np.array([X[j] for j in range(len(X)) if clusters[j] == i])
            ax.scatter(points[:, 0], points[:, 1], s=7, c=colors[i])
        ax.scatter(C_old[:, 0],C_old[:, 1], marker='*', s=200, c='#050505')
        # 计算新的中心点
        for i in range(k):
            points = [X[j] for j in range(len(X)) if clusters[j] == i]
            C[i] = np.mean(points, axis=0)
        error = dist(C, C_old, None)
    
    fig, ax = plt.subplots()
    for i in range(k):
            points = np.array([X[j] for j in range(len(X)) if clusters[j] == i])
            ax.scatter(points[:, 0], points[:, 1], s=7, c=colors[i])
    ax.scatter(C[:, 0], C[:, 1], marker='*', s=200, c='#050505')
    

    关于K-means的几个问题

    1. 一定会收敛么?
      答:一定会收敛,什么叫做收敛,当前后两次循环所计算出的中心点吻合时,我们就确定其为收敛。
    2. 不同初始化结果,会不会带来不一样的结果?
      答: 会,因为K-means的函数是非凸函数,存在多个极值点,因此最终的结果有一定的随机性;
    3. K-means的目标函数是什么?
      答: 见上文第一章。
    4. K值如何选择?
      答:超参,以K为横坐标,K-means的结果为纵坐标,得到一调递减的函数曲线,通过观察函数曲线在那个段放缓转变得最厉害,对应的横坐标就是哪个合适的K值。

    可以做的事情

    对用户进行分层

    %matplotlib inline
    import pandas as pd
    import sklearn
    import matplotlib.pyplot as plt
    import seaborn as sns
    
    data_offer = pd.read_excel("./WineKMC.xlsx", sheetname=0)
    data_offer.columns = ["offer_id", "campaign", "varietal", "min_qty", "discount", "origin", "past_peak"]
    data_offer.head()
    
    data_transactions = pd.read_excel("./WineKMC.xlsx", sheetname=1)
    data_transactions.columns = ["customer_name", "offer_id"]
    data_transactions['n'] = 1
    data_transactions.head()
    
    import numpy as np
    
    # 合并两个dataframe
    cust_compare = data_transactions.merge(data_offer, on = 'offer_id')
    
    #Drop unnecessary columns
    cust_compare = cust_compare.drop(['campaign', 'varietal', 'min_qty', 'discount', 'origin', 'past_peak'], axis = 1)
    
    #Create pivot table
    table = pd.pivot_table(cust_compare,  index = 'customer_name', columns = 'offer_id', aggfunc=np.sum, fill_value = 0)
    table
    
    #offers = table.columns.get_level_values('offer_id')
    #x_cols = np.matrix(offers)
    SS = []
    from sklearn.cluster import KMeans
    for K in range(2, 20):
        kmeans = KMeans(n_clusters = K).fit(table) #Using all default values from method
        SS.append(kmeans.inertia_)
        
    plt.plot(range(2,20), SS);
    plt.xlabel('K');
    plt.ylabel('SS');
    

    结果:

    #Choosing K=5
    kmeans_5 = KMeans(n_clusters = 5).fit_predict(table)
    points = list(kmeans_5)
    d = {x:points.count(x) for x in points}
    heights = list(d.values())
    plt.bar(range(5),heights)
    plt.xlabel('Clusters')
    plt.ylabel('# of samples')
    

    结果:

    利用降维的方法使数据可视化

    from sklearn.decomposition import PCA
    pca = PCA(n_components = 2)
    data_new = pca.fit_transform(table)
    
    print(table.shape)
    print(data_new.shape)
    
    colors = ['r', 'g', 'b', 'y', 'c', 'm']
    fig, ax = plt.subplots()
    
    for i in range(5):
            points = np.array([data_new[j] for j in range(len(data_new)) if kmeans_5[j] == i])
            ax.scatter(points[:, 0], points[:, 1], s=7, c=colors[i])
    

    结果:

    图像处理

    1. 代码

    from pylab import imread,imshow,figure,show,subplot
    from numpy import reshape,uint8,flipud
    from sklearn.cluster import KMeans
    from copy import deepcopy
    
    img = imread('sample.jpeg')  # img: 图片的数据 
     
    pixel = reshape(img,(img.shape[0]*img.shape[1],3))
    pixel_new = deepcopy(pixel)
    
    print (img.shape)
    
    model = KMeans(n_clusters=5)
    labels = model.fit_predict(pixel)
    palette = model.cluster_centers_
    
    for i in range(len(pixel)):
        pixel_new[i,:] = palette[labels[i]]
        
    imshow(reshape(pixel_new, (img.shape[0], img.shape[1],3)))
    

    2. 解释
    第一步:用像素shape[0]*shape[1]来对每个像素点进行标号;
    第二步:将描述每个像素点的RGB值作为一个向量(x,y,z),相当与把颜色值当成了一个立体坐标内的点了;
    第三步:对像素点的颜色值进行归类,将所有像素点的颜色值替换为其中心点的颜色值
    第四步:根据之前的标号生成图片并显示

    3. 结果

  • 相关阅读:
    macOS免费的NTFS读写软件
    Python模块和模块引用(一)
    Python Class (一)
    Ubuntu系统管理systemd
    Case Closed?
    The 'with' and 'as' Keywords
    Buffering Data
    rstrip
    堆排序
    堆 续9
  • 原文地址:https://www.cnblogs.com/bugutian/p/11214645.html
Copyright © 2011-2022 走看看