机器学习实战_5_01_聚类算法K-means和Mean Shift原理 + 消费者画像分析

内容预告:

  1.K-Means算法

  2.Mean Shift算法

  3.算法评估

  4.python手动实现K-Means和Mean Shift

一、原理

1.什么是聚类算法?

  (1)聚类算法是一种非监督学习算法;

  (2)聚类是在没有给定划分类别的情况下,根据数据相似度进行样本分组的一种方法;

  (3) 理论上,相同的组的数据之间有相同的属性或者是特征,不同组的数据之间的属性或者特征相差就会比较大。 

2.聚类算法分类

  (1)划分方法【K-Means】

    通过优化一个划分标准的方式将数据集D组织成K个簇;

  (2)层次方法【SAHN】

    在不同粒度水平上为数据集D创造层次聚类,其中每层特定的聚类结果由相应粒度水平的阈值决定。

  (3)基于密度的方法【Mean Shift】

    从密度的角度构造簇类;

  (4)基于网格的方法【STING】

    将数据集D量化进数量有限的网格单元中,量化过程通常是多分辨率的。

  (5)基于模型的方法【GMM】

    假设存在一个数字模型能够对数据集D的性质进行描述,通过对数据和该模型的符合程度进行优化,可以得到聚类的结果。

3.K—Means算法

  (1)核心思想

    K-means聚类算法也称k均值聚类算法,采用距离作为相似性的评价指标,即认为两个对象的距离越近,其相似度就越大。

    

    k值的选择

  (2)算法实现(流程) 

    a.选择初始化的 k 个样本作为初始聚类中心 [公式] ;

    b.针对数据集中每个样本 [公式] 计算它到 k 个聚类中心的距离并将其分到距离最小的聚类中心所对应的类中;

    c.针对每个类别 [公式] ,重新计算它的聚类中心 [公式] (即属于该类的所有样本的质心);

    d.重复上面 2 3 两步操作,直到达到某个中止条件(迭代次数、最小误差变化等)。

  (3)K-Means算法优缺点

    优点 
    1)原理比较简单,实现也是很容易,收敛速度快。 
    2)聚类效果较优。 
    3)算法的可解释度比较强。 
    4)主要需要调参的参数仅仅是簇数k。

    缺点 ;
    1)K值的选取不好把握 
    2)对于不是凸的数据集比较难收敛 ;
    3)如果各隐含类别的数据不平衡,比如各隐含类别的数据量严重失衡,或者各隐含类别的方差不同,则聚类效果不佳。 
    4) 最终结果和初始点的选择有关,容易陷入局部最优。
    5) 对噪音和异常点比较的敏感。

4.Mean Shift算法

  (1)核心思想

    也叫均值漂移,通过感兴趣区域内的数据密度变化计算中心点的漂移向量,从而移动中心点进行下一次迭代,直到到达密度最大处(中心点不变)。

    从每个数据点出发都可以进行该操作,在这个过程,统计出现在ROI区域内的数据的次数,该参数将在最后作为分类的依据。

    

   (2)算法实现(流程)

    ①在未被标记的数据点中随机选择-一个点作为起始中心点center;

    ②找出以center为中心半径为radius的区域中出现的所有数据点,认为这些点同属于-一个聚类C,同时在该聚类中记录数据点出现的次数加1;

    ③以center为中心点,计算从center开始到集 合M中每个元素的向量,将这些向量相加,得到向量shift.;

    ④center = center + shift.即center沿 着shift的方向移动,移动距离是||shift||.

    ⑤重复步骤2、3. 4,直到shift的很小 (就是迭代到收敛),记住此时的center. 注意,这个迭代过程中遇到的点都应该归类到簇C.

    ⑥如果收敛时当前簇C的center.与其它已经存在的簇C2中心的距离小于阈值,那么把C2和C合并,数据点出现次数也对应合并。否则,把C作为新的聚类。

    ⑦重复1.2. 3. 4. 5直到所有的点都被标记为已访问。

    ⑧分类:根据每个类,对每个点的访问频率,取访问频率最大的那个类,作为当前点集的所属类.

  (3)Mean shift算法优缺点

    优点 
    1)与K-means算法不一样的是,Mean Shift算法可以自动决定类别的树木。 
    2)不受离异值影响。 
    3)没有局部最小值。 

    缺点 ;
    1)在高维空间数据下表现不佳。 
    2)无法指定聚类的数量 ;
 

3.算法评估 

  metrics.silhouette_score():

  为轮廓系数(Silhouette Coefficient)得分的指标。

二、实践

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from pandas import plotting
import seaborn as sns
import warnings
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
from sklearn.cluster import MeanShift, estimate_bandwidth
import plotly.graph_objs as go
import plotly.offline as po


plt.style.use("fivethirtyeight")

print("###############################step1: 数据探索###########################################
")
data = pd.read_csv("Mall_Customers.csv") #读取文件
pd.set_option('display.width', 1000)#加了这一行那表格的一行就不会分段出现了
pd.set_option('display.max_columns', None) #显示所有的列,配合前一行所有列可以显示在同一行
print(data.head())
print(data.info()) #需要括号
data.head()  #读取前5行
print("查看数据表是否有空值:")
print(data.isnull().any().any())  #查看数据表是否有空值

print("*******************************1.可视化:年收入分布,年龄分布************************************************")
warnings.filterwarnings('ignore')  #有一些报错就忽略掉
plt.rcParams['figure.figsize'] = (18, 8) # 画布大小

#  第一个图表
plt.subplot(1, 2, 1) # 1行2列1号位置
sns.set(style='whitegrid') # 格式设置
sns.distplot(data['Annual Income (k$)']) # 数据展示
plt.title('Distribution of Annual Income', fontsize=20) # 标题设置
plt.xlabel('Range of Annual Income') # 横轴
plt.ylabel('Count') # 纵轴

# 第二个图表
plt.subplot(1,2,2) # 1行2列2号位置
sns.set(style='whitegrid') # 格式设置
sns.distplot(data['Age'], color='red') # 数据展示
plt.title("Distribution of Age", fontsize=20) # 标题设置
plt.xlabel("Range of Age") # 横轴
plt.ylabel("Count") # 纵轴
#plt.show() # 显示
print("性别分布:")
print(data['Gender'].value_counts())

print("*******************************2.性别分布可视化************************************************")
labels = ['Female', 'Male'] # 性别标签
size = data['Gender'].value_counts() # 性别统计
colors = ['lightgreen', 'orange'] # 颜色配置
explode = [0, 0.1] # 饼图参数  间隔
plt.rcParams['figure.figsize'] = (9,9) # 画布大小
plt.pie(size, colors=colors, explode=explode, labels=labels, shadow=True, autopct='%.2f%%') # 饼图参数设置
plt.title('Gender', fontsize=20) # 标题
plt.axis('off') # 关闭坐标轴
plt.legend() # 显示标签
#plt.show() # 显示图

print("*******************************3.将数据表中的年龄可视化************************************************")
plt.rcParams['figure.figsize'] = (15,8) # 画布大小
sns.countplot(data['Age'], palette='hsv') # 以柱状图的形式展示每个类别的数量
plt.title("Distribution of Age", fontsize=20) # 标题
#plt.show()

print("*******************************4.费得分数据分布************************************************")
plt.rcParams['figure.figsize'] = (20,8) # 画布大小
sns.countplot(data['Spending Score (1-100)'], palette='hsv')# 数据展示
plt.title("Distribution of Spending Score", fontsize=20) # 标题
#plt.show()

print("*******************************5.数据之间的相关系数,热图heatMap展示************************************************")
plt.rcParams['figure.figsize'] = (15, 8) # 画布大小
sns.heatmap(data.corr(), cmap='Wistia', annot=True) # 数据展示
plt.title("HeatMap for the Data", fontsize=20) # 标题
#plt.show()

print("*******************************6.性别 VS 消费得分 之间的数据关联性 展示************************************************")
plt.rcParams['figure.figsize'] = (18, 7) # 画布大小
sns.boxenplot(data['Gender'], data['Spending Score (1-100)'], palette='hsv') # 数据抽取
plt.title("Gender vs Spending Score", fontsize=20) # 标题
#plt.show()

print("*******************************7.年收入 VS 年龄和消费得分之间的关系************************************************")
x = data['Annual Income (k$)'] # 年收入
y = data['Age'] # 年龄
z = data['Spending Score (1-100)'] # 消费得分

sns.lineplot(x, y, color='blue') # 年收入 vs 年龄
sns.lineplot(x, z, color='black') # 年收入 vs 消费得分
plt.title("Annual Income vs Age and Spending Score", fontsize=20) # 标题
#plt.show()

print("###############################step2: 聚类算法:K-means###########################################
")
#1 获取data的两个特征:Annual Income (k$) 和 Spending Score (1-100)
X = data.iloc[:, [3, 4]].values # 获取第3、4个特征数据

print(type(X))
print(X.shape)

#2 模型创建、训练, 选取最优聚类参数K
scores = []  # 得分
range_values = np.arange(2, 10)  # 初始聚类个数
for i in range_values:
    # 创建模型对象
    kmeans = KMeans(init='k-means++', n_clusters=i, max_iter=300, n_init=10, random_state=0)
    kmeans.fit(X)
    score = silhouette_score(X, kmeans.labels_, metric='euclidean', sample_size=len(X))  # 计算得分
    scores.append(score)

#3 绘制得分结果 : 柱状图
plt.rcParams['figure.figsize'] = (20, 10) # 画布大小
plt.subplot(2, 2, 1)
#plt.figure()
plt.bar(range_values, scores, width=0.6, color='b', align='center')
plt.title('Silhouette score')
#plt.show()

#4 绘制得分结果 :折线图
plt.subplot(2, 2, 2)
plt.plot(range_values, scores) # 数据
plt.title("Silhouette score") # 标题
plt.xlabel('Cluster', horizontalalignment='right') # 横轴
plt.ylabel('Score') # 纵轴
#plt.show()

#5 数据聚类,K=5
km = KMeans(init='k-means++',n_clusters=5,max_iter=300, n_init=10, random_state=0, n_jobs=-1) # 聚类对象

y_means = km.fit_predict(X) # 训练

#6 绘制聚类结果
plt.subplot(2, 2, 3)
plt.scatter(X[:,0], X[:,1], marker='o', facecolors='b', edgecolors='k', s=30) # 绘制特征数据
centroids = km.cluster_centers_ # 质心
plt.scatter(X[y_means == 0, 0], X[y_means == 0, 1], s = 100, c = 'pink', label = 'miser') # 标签:0
plt.scatter(X[y_means == 1, 0], X[y_means == 1, 1], s = 100, c = 'yellow', label = 'general') # 标签:1
plt.scatter(X[y_means == 2, 0], X[y_means == 2, 1], s = 100, c = 'cyan', label = 'target') # 标签:2
plt.scatter(X[y_means == 3, 0], X[y_means == 3, 1], s = 100, c = 'magenta', label = 'spendthrift') # 标签:3
plt.scatter(X[y_means == 4, 0], X[y_means == 4, 1], s = 100, c = 'orange', label = 'careful') # 标签:4
plt.scatter(centroids[:,0], centroids[:,1], marker='*', s=260, linewidths=3, color='black', label='centroid') # 质心
x_min, x_max = min(X[:,0])-1, max(X[:,0])+1 # 横轴坐标范围
y_min, y_max = min(X[:,1])-1, max(X[:,1])+1 # 纵轴坐标范围
plt.title("K-Means clustering") # 标题
plt.xlim(x_min, x_max) # 横轴
plt.ylim(y_min, y_max) # 纵轴
plt.xticks(())
plt.yticks(())
#plt.show()

print("###############################step3: 聚类算法:mean shift###########################################
")
#1 聚类算法实现

bandwidth = estimate_bandwidth(X, quantile=0.1) # 带宽(即半径),quantile默认为[0,1], 默认值为0.3
ms = MeanShift(bandwidth=bandwidth).fit(X) # 聚类

#2 绘制聚类结果
plt.subplot(2, 2, 4)
plt.scatter(X[:,0], X[:,1], marker='o', facecolors='b', edgecolors='k', s=30) # 绘制特征数据
centroids = ms.cluster_centers_ # 质心
plt.scatter(X[y_means == 0, 0], X[y_means == 0, 1], s = 100, c = 'pink', label = 'miser') # 标签:0
plt.scatter(X[y_means == 1, 0], X[y_means == 1, 1], s = 100, c = 'yellow', label = 'general') # 标签:1
plt.scatter(X[y_means == 2, 0], X[y_means == 2, 1], s = 100, c = 'cyan', label = 'target') # 标签:2
plt.scatter(X[y_means == 3, 0], X[y_means == 3, 1], s = 100, c = 'magenta', label = 'spendthrift') # 标签:3
plt.scatter(X[y_means == 4, 0], X[y_means == 4, 1], s = 100, c = 'orange', label = 'careful') # 标签:4
plt.scatter(centroids[:,0], centroids[:,1], marker='*', s=260, linewidths=3, color='black', label='centroid') # 质心
x_min, x_max = min(X[:,0])-1, max(X[:,0])+1 # 横轴坐标范围
y_min, y_max = min(X[:,1])-1, max(X[:,1])+1 # 纵轴坐标范围
plt.title("Mean Shift clustering", horizontalalignment='left') # 标题
plt.xlim(x_min, x_max) # 横轴
plt.ylim(y_min, y_max) # 纵轴
plt.xticks(())
plt.yticks(())
plt.show()

print("###############################step4:选取三个特征:Age,Annual Income,Spending Score进行聚类###########################################
")
X = data[['Age', 'Annual Income (k$)','Spending Score (1-100)']].values # 选取三个特征的数据
print(X.shape)

#1 KMeans 算法
km = KMeans(init='k-means++', n_clusters=5, max_iter=300) # 聚类对象
km.fit(X) # 训练

#2 获取聚类结果:标签和质心
labels = km.labels_ # 标签

centroids = km.cluster_centers_ # 质心
#3 为原始数据data,增加一列
print(data.head())

data['labels'] = labels # 增加一列

print(data.head())

#4 数据可视化
trace1 = go.Scatter3d(
    x = data['Age'],
    y = data['Spending Score (1-100)'],
    z = data['Annual Income (k$)'],
    mode='markers',
    marker=dict(
        color=data['labels'],
        size=10,
        line=dict(
            color=data['labels'],
            width=12
        ),
        opacity=0.8
    )
)

df = [trace1]

layout = go.Layout(
    title = '',
    margin = dict(
        l=0,
        r=0,
        b=0,
        t=0
    ),
    scene = dict(
        xaxis = dict(title = 'Age'),
        yaxis = dict(title = 'Spending Score'),
        zaxis = dict(title = 'Annual Income')
    )
)

fig = go.Figure(data = df, layout = layout)
#po.iplot(fig)  #ipython上调用
fig.show()

图1:

图2:

图3:

图4:

图5:

 图6:

 图7:

 图9:

 

图10:

三、Pycharm安装第三方库时出现Read timed out的解决办法

https://www.cnblogs.com/emanlee/p/12357746.html

1.在下载库的界面点击:Manage Repositories

2.添加下载源:

  常用的有:

    (1)http://pypi.douban.com/simple/   豆瓣

    (2)https://pypi.tuna.tsinghua.edu.cn/simple/     清华大学   (pip install 包名 -i https://pypi.tuna.tsinghua.edu.cn/simple/)

3.切换下载源,进行安装。

说明:

1.本文为个人学习笔记;

2.学习视频来源:https://space.bilibili.com/474347248/channel/detail?cid=143235

3.数据来源:唐国梁Tommy,为了方便志同道合的伙伴一起学习,我将数据上传到个人盘分享:

链接:https://pan.baidu.com/s/1YX1fAHmI1sD8PFOm0tiyIA
提取码:qw5a
复制这段内容后打开百度网盘手机App,操作更方便哦--来自百度网盘超级会员V1的分享

4.本文代码运行环境基于pycharm.(原代码是基于jupyter实现的);

5.代码的一些注释是为了理解,不太标准规范化,但不影响功能实现;

5.欢迎一起讨论学习:386825951@qq.com

原文地址:https://www.cnblogs.com/bltstop/p/14821639.html