一、聚类

1.什么是聚类 

聚类(Clustering)是数据挖掘和机器学习中的一种无监督学习方法,是将对象集合中的对象分类到不同的类或者簇这样的一个过程,使得同一个簇中的对象有很大的相似性,而不同簇间的对象有很大的相异性。簇内的相似性越大,簇间差别越大,聚类就越好。 

聚类结果的好坏取决于该聚类方法采用的相似性评估方法以及该方法的具体实现,聚类方法的好坏还取决于该方法是能发现某些还是所有的隐含模式。

2.聚类类型

(1)划分聚类

对于给定的数据集,划分聚类方法首先创建一个初始划分,然后采用一种迭代的重定位技术,尝试通过对象在划分间的移动来改进划分,直到使评价聚类性能的评价函数的值达到最优为止。划分聚类方法以距离作为数据集中不同数据间的相似性度量,将数据集划分成多个簇。划分聚类方法是最基本的聚类方法,属于这样的聚类方法有 k 均值((k-means)、k中心点(k-medoids)等。

划分聚类方法的主要思想: 给定一个包含 n个数据对象的数据集,划分聚类方法将数据对象的数据集进行k个划分,每个划分表示一个簇(类),并且k≤n,同时满足下面两个条件:每个簇至少包含一个对象,每个对象属于且仅属于一个簇。对于给定的要构建的划分的数目 k,划分方法首先给出一个初始的划分,然后采用一种迭代的重定位技术,尝试通过对象在划分间移动来改进划分,使得每一次改进之后的划分方案都较前一次更好。好的划分是指同一簇中的对象之间尽可能“接近”,不同簇中的对象之间尽可能“远离”。

划分聚类方法的评价函数:评价划分聚类效果的评价函数着重考虑两方面,即每个簇中的对象应该是紧凑的,各个簇间的对象的距离应该尽可能远。实现这种考虑的一种直接方法就是观察聚类C 的类内差异w(C)和类间差异b(C)。类内差异衡量类内的对象之间的紧凑性,类间差异衡量不同类之间的距离。
类内差异可以用距离函数来表示,最简单的就是计算类内的每个对象点到它所属类的中心的距离的平方和,即

                        

类间差异定义为类中心之间距离的平方和,即

                           

两式中的 \overline {x}_{i}\overline {x}_{j} 分别是类类Cᵢ、Cⱼ的类中心。

聚类C的聚类质量可以用w(C)和b(C)的一个单调组合来表示,如w(C) / b(C)

(2)层次聚类

划分聚类获得的是单级聚类 ,而层次聚类是将数据集分解成多级进行聚类 ,层的分解可以用树状图来表示。根据层次的分解方法不同 ,层次聚类可以分为自底向上凝聚的聚集型(Agglomerative Clustering)和自顶向下分裂的分解型聚类(Divisive Clustering),凝聚型方法一开始就将每个对象作为单独的一簇,然后不断地合并相近的对象或簇。分裂型方法一开始把所有的对象置于一个簇中,在迭代的每一步中 ,一个簇被分裂为更小的簇 ,直到每个对象在一个单独的簇中,或者达到算法终止条件。 

(3)基于密度的聚类

绝大多数划分聚类基于对象之间的距离进行聚类 ,这样的方法只能发现球状的类,而在发现任意形状的类上遇到了困难。 基于密度的聚类的主要思想: 只要临近区域的密度(对象或数据点的数目)超过某个阈值就继续聚类。 这样的方法可以用来过滤噪声和孤立点数据,发现任意形状的类。 

3.聚类的应用领域

聚类分析的应用领域非常广泛,以下只是其中的一些应用场景。

(1)商业

聚类分析可以用来发现不同的客户群体,并通过用户行为模式刻画不同的客户群特征。聚类是细分市场的常用工具,同时也可以用于研究客户行为,寻找潜在市场。

(2)金融

通过利用客户的财务数据、交易记录等信息进行聚类,可以区分不同信用等级的客户群体;根据资产的风险收益特性将投资产品进行分类,可以优化投资策略

(3)供应链管理

聚类分析可以帮助识别供应链环节中的瓶颈或优化点,例如对运输路线、供应商表现等进行分类。

(4)电子商务

在电商网站中,通过分组聚类出具有相似浏览行为的客户,并分析客户的共同特征,可以更好地电商运营者了解自己的客户,从而提供更合适的服务。

二、K-Means 聚类

1.K-Means 聚类的原理

KMeans聚类算法也被称为k平均聚类算法,是一种广泛使用的聚类算法。k均值用质心来表示一个簇,质心就是一组数据对象点的平均值。k均值算法以k为输入参数,将n个数据对象划分为k个簇,使得簇内数据对象具有较高的相似度。

k均值聚类算法的思想是从包含n个数据对象的数据集中随机地挑选k个对象,每个对象代表一个簇的平均值或质心或中心,其中k是用户指定的参数,即所期望要划分的簇的个数;对剩余的每个数据对象点根据其与各个簇中心的距离,将它指派到最近的簇;然后根据指派到簇的数据对象点,更新每个簇的中心;重复指派和更新的步骤直到簇或中心不发生变化,或度量聚类质量的目标函数收敛。k均值算法的目标函数E如下:

                                        

其中X是空间中的点表示给定的数据对象,\overline {x}_{i} 是簇 Cᵢ 的数据对象平均值,d(X,\overline {x}_{i})表示X与\overline {x}_{i}之间的距离。例如三个二维点(1,3),(2,4),(3,5),它们的质心是((1+2+3)/3,(3+4+5)/3)=(2,4)。k均值算法的目标是最小化目标函数E,这个目标函数可以保证生成的簇尽可能的紧凑。

2.K-Means 聚类的优缺点

(1)优点

1.算法实现简单,易于理解,计算效率相对较高,对于大规模数据集尤其在具有合理结构的数据上表现良好。

2.处理数值型且数据分布比较均匀的数据集,特别适用于发现球状或凸形的聚类形状。

3.直观地通过簇中心来表示每个簇的特性,簇心可以被解释为该簇的代表或原型。

4.当簇是密集的、球状或团状的,且簇与簇之间区别明显时,算法的聚类效果更好

(2)缺点

1.需要预先确定簇的数量K。选择合适的K值是一个挑战,如果选择不当,则可能导致聚类效果不理想。实际应用中可能需要尝试不同的K值并结合领域知识和可视化工具进行评估。

2.对初始聚类中心敏感。算法的结果会依赖于初始化时随机选择的聚类中心,不同的初始化可能会导致不同的最终聚类结果。

3.无法处理非凸型聚类。当数据集中的聚类不是凸分布时,K-Means可能无法准确划分出这些聚类。

4.对异常值敏感。较大的离群点可能会影响聚类效果,因为算法是基于欧氏距离等度量方法,这类方法容易受到极端值的影响。

5.迭代收敛至局部最优解。由于是基于贪心策略的优化算法,K-Means往往只能达到局部最优而非全局最优。

三、K-Means 聚类的 python 实现

1.数据预处理

(1)数据观察

1.读取数据

import numpy as np
import pandas as pd
data1=pd.read_excel('电商数据.xlsx',sheet_name='平台2销售明细',encoding='utf-8-sig')
df1=data1

扩展库pandas中提供了用来读取Excel文件内容的read_excel()函数,要求使用者此时已安装xlrd和openpyxl。pandas常用的读写不同格式文件的函数如下:

 

 2.观察数据

df1.head(10)  #查看前十条数据
df1.shape     #查看数据现状
df1.info()    #查看列信息
df1.describe()  #查看数据统计性描述信息

 3.内容补充

通过.head (10)方法可以观察前十条数据,观察数据,发现通过“销售数量”字段和“订单金额/元”字段可以计算出销售金额,将销售金额作为一个新字段添加到数据集中。

df1['销售金额/元']=df1['销售数量']*df1['订单金额/元']

4.数据类型转换

 调用.info ( )方法观察列数据,发现‘订单编号’、‘顾客编号’为整型,将之替换为字符串类型。

df1['订单编号']=df1['订单编号'].astype('str')
df1['顾客编码']=df1['顾客编码'].astype('str')
df1[['销售金额/元','订单金额/元']]=df1[['销售金额/元','订单金额/元']].astype('float')
df1.info()

 

(2) 处理缺失值

在pandas库中,isnull ( ) 方法用于检查 DataFrame 或 Series 中的元素是否为缺失值(NaN),返回的结果是一个布尔型的 Series 或 DataFrame。在本实例中没有缺失值。

blank=df1.isnull().sum()
print(blank)

 

处理缺失值的方法主要有三类:删除元组、数据补齐和不处理。

删除元组。删除元组就是将存在遗漏属性值的对象删除,从而得到一个完备的信息表。DataFrame结构支持使用dropna()方法丢弃带有缺失值的数据行。

dropna(axis=0,how='any',thresh=None,subset=None,inplace=False)

 其中:

(1)参数 how='any'时表示只要某行包含缺失值就 “丢弃”,how='all'时表示某行全部为缺
失值才“丢弃”;
(2)参数thresh 用来指定保留包含几个非缺失值数据的行;
(3)参数subset 用来指定在判断缺失值时只考虑哪些列。

数据补齐。时只考虑哪些列。数据补齐是使用一定的值对缺失属性值进行补齐,从而使信息表完备化。数据补齐一般有均值补齐、同类均值补齐、就近填补和拟合补齐等方法。DataFrame结构支持使用fillna()方法对缺失值进行批量替换,也可以使用loc()、iloc()方法直接对符合条件的数据进行替换。

fillna(value=None,method=None,axis=None,inplace=False,limit=None,downcast=None)

其中:

(1) 参数value用来指定要替换的值, 该值可以是标量、字典、Series或DataFrame;
(2) 参数method用来指定填充缺失值的方式, 值为'pad'或'ffill'时表示使用扫描过程中遇到的最后 一个有效值一直填充到下一个有效值,值为 backfill'或bfill'时表示使用缺失值之后遇到的第一个有效值填充前面遇到的所有连续缺失值;
(3)参数limit用来指定设置了参数method时最多填充多少个连续的缺失值;
(4)参数inplace=True 时表示原地替换,inplace=False 时返回一个新的DataFrame对象而不对原来的DataFrame进行任何修改。

(3)处理重复值

当记录失误,可能会导致存在重复值的情况,一般采取的处理方法是直接丢弃重复值。DataFrame结构的duplicated()方法可以用来检测哪些行重复,其语法结构如下:

duplicated(subset=None,keep='first')

 其中:
(1)参数subset 用来指定判断不同行的数据是否重复时所依据的一列或多列,默认使用整行所有列的数据进行比较;
(2)参数keep='first'时表示重复数据的第一次出现标记为 False,keep='last'时表示重复数据的最后一次出现标记为False,keep=False 时表示标记所有重复数据为True。

除此之外, DataFrame结构的drop_duplicates()方法用来删除重复数据,其语法结构如下:

drop_duplicates(subset=None,keep='first',inplace=False)

其中

(1)参数subset的含义与 duplicated)方法类似;
(2)参数keep='first'时表示保留重复数据中第一次出现的数据,keep='last'时表示保留重复数据最后一次出现的数据。

通过duplicated().sum()方法可以统计重复值个数。在本实例中,有两条重复数据。

paral=df1.duplicated() .sum()
print(paral)
df1[df1.duplicated()]
df1.drop_duplicates(keep='first')

 

 (4)异常值处理

KMeans 聚类算法对异常值敏感,因此处理异常值是进行KMeans 聚类的重要步骤。异常值是指严重超出正常范围的数值, 这样的数据一般是数据采集错误或类似原因造成的。在数据分析时, 需要把这些数据删除或替换为特定的值(例如人为设定的正常范围边界值), 减小对最终数据分析结果的影响。 异常值处理的关键是根据实际情况准确定义正常范围边界值, 超出正常范围的数值认为是异常值。

在数据分析中,对数据进行描述性统计可以判断是否存在异常值。

df1.describe()

 

‘销售金额/元’字段在第三四分位数(70%)的数据为162,而其最大值(max)为531,由此可以判断数据存在异常值。为了进一步判断异常值,可以通过可视化方法来直观地观察。

import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
sales = df1['销售金额/元']
# 创建一个柱形图
plt.bar(range(len(sales)), sales)  # range(len(sales))用于生成x轴的刻度位置
# 添加标题和标签
plt.title('销售额柱状图')
plt.xlabel('产品/项目')
plt.ylabel('销售额')
plt.show()

在数据分析中,通常会使用统计方法来识别异常值。主要的统计方法有三倍标准差和四分位数规则,其中三倍标准差一般使用在正态分布中,四分位数规则则可以使用在非正态分布数据中。以下将通过实例解释这两种统计方法。

四分位数规则。四分位数规则(Quartile Rule)是一种用于识别数据集中潜在异常值的统计方法,特别是基于箱线图(Boxplot)进行可视化分析时。这个规则通常依据数据分布的四分位数来确定正常数据范围的上下界。

四分位数包括:

第一四分位数(Q1):将数据从小到大排列后,位于中间25%位置的数值,即数据集中的25%的数据点小于或等于它。

中位数(Q2 或者 Median):将数据排序后位于中间的数值,也就是50%位置的数,一半的数据点小于或等于中位数,另一半大于或等于中位数。

第三四分位数(Q3):将数据从小到大排列后,位于中间75%位置的数值,即数据集中有75%的数据点小于或等于它。

根据四分位数规则,一个常见的异常值判断标准是使用四分位距IQR(Interquartile Range),它是第三四分位数与第一四分位数之间的差值,它的计算公式为:IQR = Q3 - Q1。在箱线图中,异常值的标准定义为:

下限:Q1 - 1.5 * IQR

上限:Q3 + 1.5 * IQR

任何低于下限或高于上限的数据点被认为是可能的异常值。

import matplotlib.pyplot as plt
import pandas as pd
#支持显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']
# 读取销售额数据
sales = df1['销售金额/元']
# 绘制箱线图
plt.boxplot(sales)
plt.ylabel('销售额')
plt.title('销售额箱线图')

# 标记异常值
q1 = sales.quantile(0.25)
q3 = sales.quantile(0.75)
iqr = q3 - q1

#上根据1.5倍IQR原则确定异常值上下限
lower_bound = q1 - 1.5 * iqr
upper_bound = q3 + 1.5 * iqr

#筛选出超出上下界的异常值
outliers = sales[(sales < lower_bound) | (sales > upper_bound)]

for outlier in outliers:
    plt.plot([], [], 'ro', label=f'异常值: {outlier}')#为每个异常值创建一个标签
plt.legend(loc='best')#显示图例

# 显示图形
plt.show()

#返回异常值信息
df1[df1['销售金额/元'].isin(outliers)]

 

返回的异常值信息如下,调用drop方法删除异常值即可。

三倍标准差法。三倍标准差法是基于正态分布的一个常用异常检测方法。它的工作原理是根据正态分布的特点,将3σ作为“异常”的边界,也就是说,落在平均值±3σ范围内的数值都被认为是正常的,超出这个范围的数值被视为异常值。

计算平均数(均值):μ = (Σx) / N

计算标准差(σ):√[ Σ( x - μ )² / (N-1) ]

确定上下界:

上界:μ + 3σ 

下界:μ - 3σ

在本实例中,数据显非正态分布,因此采用Z-score(标准化分数)和三倍标准差法相结合的方法来识别异常值。在该方法中,主要分为两步:

1.计算变量'销售金额/元'的标准分数(Z-score),对每个观测值进行标准化处理。公式为

(观测值 - 平均值) / 标准差

#标准化观测值
sta=(df1['销售金额/元']-df1['销售金额/元'].mean())/df1['销售金额/元'].std()
print(sta)

2.利用三倍标准差原则,检查经过标准化后的数值是否超过3个标准差。通过判断标准化结果的绝对值是否大于3,若满足条件,则表明该观测值在原始数据集中距离平均值超过了3个标准差,按照经验法则,这样的观测值可以被认为是潜在的异常值。

df1[sta.abs()>3]

返回的异常值结果与四分位数规则法的结果相同 :

删除异常值:

df1.drop(df1[sta.abs()>3].index)
(5) 重置索引

在进行数据清洗后,数据集索引会随着删除数据而出现索引不连续的情况,因此在结束数据清洗后,要对索引进行重置。Pandas库中提供了reset_index()方法,它主要用于重置数据帧的索引。在执行此操作后,原始的索引将被转换为一个普通列,并生成一个新的默认整数索引。

df1=df1.reset_index(drop=True)

 

2.特征编码

  KMeans是一种基于欧氏距离或余弦相似度等数学距离度量的聚类算法。这些距离度量方法适用于数值型数据,而许多实际数据集中包含分类变量(如性别、地区、产品类别等),这些非数值类型的特征无法直接用于计算距离。特征编码是为了将非数值型特征转化为适合KMeans聚类算法处理的形式,同时也确保了数据的一致性和公平性,从而提高聚类的效果和模型的解释性。 

导入Python库sklearn中需要的模块 LabelEncoder

from sklearn.preprocessing import LabelEncoder

LabelEncoder是Python的scikit-learn库中的一种预处理工具,主要用于将分类变量(如字符串标签或类别)转换为数值形式。 

添加消费频次和消费星期两个客户特征 :

#统计消费频次,通过统计顾客编码出现次数实现
df1['frequency'] = df1.groupby('顾客编码')['顾客编码'].transform('count')

#统计购买星期
#.dt用于提取和操作datetime类型的列的各种日期或时间属性。
#.dayofweek 是一个方法,它返回的是给定日期是一周中的第几天,0-6代表从星期一到星期天
df1['week']=df1['下单时间'].dt.dayofweek 
df1.head(5)

 对 “支付方式” 和 “促销方式” 进行特征编码:

coding=LabelEncoder()
df1['encoded_pay']=coding.fit_transform(df1['支付方式'])

df1['encooded_discount']=coding.fit_transform(df1['促销方式'])
df1.head(5)

 

在对数据集进行特征编码结束后,选择用于聚类的特征。这里选择 '销售数量'、'订单金额/元'、'frequency'、'week'、'encoded_pay'、'encooded_discount' 和 '销售金额/元' 7个特征作为聚类特征集。

X=df1[['销售数量','订单金额/元','frequency','week','encoded_pay','encooded_discount','销售金额/元']]

3.数据标准化 

 在K-means聚类之前,首先应该对数据进行标准化处理。这是因为K-means算法基于欧氏距离计算样本之间的相似性,如果不同特征的尺度差异很大,那么这种差异将主导距离度量,从而影响最终聚类结果。通过标准化确保所有特征具有相同的尺度和单位,可以使得各个特征同等重要地参与聚类过程。本实例采用Python的scikit-learn库中的StandardScaler类对数据进行标准化处理。

 导入StandardScaler类:

from sklearn.preprocessing import StandardScaler

 对聚类特征集进行拟合:

scaler=StandardScaler()
X_scaler=scaler.fit_transform(X)

4.数据降维 

 数据降维是机器学习和数据分析中的一种重要技术,其目的是在保留数据主要结构或信息的前提下减少数据的维度。KMeans聚类处理高维数据时性能会下降,对数据进行降维可以减少计算复杂度,提高算法性能。在本实例中,采用PCA(主成分分析)法进行数据降维。

导入PCA模块:

from sklearn.decomposition import PCA

对标准化后的特征集进行拟合:

pca=PCA(n_components=0.90)  #保留能够解释原始数据至少90%总方差的主成分数量
pca.fit(X)
X_pca=pca.transform(X)
tzxl=pca.components_   #主成分向量
tz=pca.explained_variance_   #主成分方差值
gxl=pca.explained_variance_ratio_   #主成分方差比例

5.肘部法则确定最优k值

在KMeans聚类中,需要预先确定簇的数量k,正确的k值能够确保聚类算法能有效地发现数据集中的模式,并且得到的结果具有较高的实用性和解释力。常用的方法包括肘部法则(Elbol Method)、轮廓系数、交叉验证、Davies-Bouldin Index (DBI)以及基于领域知识判断。本实例采用肘部法则确定 最优k值。

from sklearn.cluster import KMeans
sse = []
# 循环尝试不同的聚类数量
for k in range(1, 11):
    kmeans = KMeans(n_clusters=k,init='k-means++', random_state=0)
    kmeans.fit(X_scaler)
    
    # 计算并存储当前聚类数量下的SSE
    sse.append(kmeans.inertia_)

# 绘制SSE与聚类数量的关系图
plt.plot(range(1, 11), sse)
plt.title('Elbow Method For Optimal k')
plt.xlabel('Number of clusters (k)')
plt.ylabel('Sum of squared distances')
plt.grid(True)
plt.show()
# '肘部'即SSE下降速率明显减缓的那个点

根据可视化图示,当k为2时。sse下降速率明显减缓,因此最优k值为2。 

 

6.K-Means 聚类拟合

 

best_k=2

#初始化方法K-means++可以选择更优的初始聚类中心
model = KMeans(n_clusters=best_k,init='k-means++', random_state=0)
labels = model.fit_predict(X_scaler)

# 将聚类结果添加到原始数据中
df1['cluster'] = labels
#将聚类结果添加到原始数据框(df1)中,并对每个簇进行统计描述
for i in range(best_k):
    cluster_data = df1[df1['cluster'] == i]
    print(f"簇{i+1}的顾客行为特征统计信息:")
    print(cluster_data.describe())

 

7.解释结果

以下只对簇1的描述性统计进行解释说明:

销售数量: 平均每个客户在考察期内购买的商品数量大约为1.35件,标准差较小(0.48),表明该簇中的顾客购买行为较为集中,多数人的购买数量接近平均值。最小值和25%分位数均为1.0,说明至少四分之一的顾客每次只购买一件商品;而75%分位数为2.0,表示有约四分之三的顾客购买数量不超过两件。

订单金额与销售金额:平均每笔订单金额约为28.19元,总销售额平均每位顾客贡献约40.79元。这两个指标的标准差相对较大,说明在簇1中顾客的消费能力存在一定的波动性。最低单笔订单金额为12元,最高为59元,中位数是29元,显示大多数订单集中在较低到中等价位区间。

消费频次(frequency):   顾客平均购物频率为2.74次,标准差为1.89,说明该簇内顾客购物频次差异也较大,但整体上活跃度适中,部分顾客频繁购买,但也有一部分顾客购买次数较少。

消费星期(week) :顾客购买行为分布于每周的不同时间点,平均周数为3.12,范围从0到6,这可能代表了顾客的购买周期或活动参与程度,75%分位数为5,说明大部分顾客在考察期间内有较为均衡的购买记录,最活跃的顾客在6周内均有购买行为。

支付方式和促销方式: 平均值分别为2.08和2.28,最大值分别为4.0和5.0,这意味着此簇中的顾客在支付方式和享受折扣方面有一定的多样性,但多数顾客选择的支付方式是银行卡且更青睐于赠品的促销方式。

总结起来,簇1内的顾客具有以下特点:

  • 购买行为相对稳定且偏向小额多次购买。
  • 订单金额普遍不高,消费水平中等偏下。
  • 活跃度中等,大多数顾客会在几周的时间内多次购物。
  • 在支付方式和折扣利用方面有一定变化,但总体来说倾向于银行卡支付以及赠品的促销方式。

 

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐