赞
踩
目录
利用AgglomerativeClustering对凝聚层次聚类剪枝
轮廓系数(silhouette coefficient)编辑
K均值聚类是一种常见的无监督学习算法,用于将一组数据点分组,使得每个组内的数据点尽可能相似,而组间的数据点尽可能不同。
数据点(Data Points):这些是我们要聚类的基本单位,通常在二维或三维空间中表示为点。每个数据点都有多个特征,这些特征决定了它在空间中的位置。
聚类(Clusters):聚类是数据点的集合,这些数据点在某些特征上相似。一个聚类中的数据点彼此之间差别不大,而与其它聚类中的数据点差别较大。
簇(Cluster):指一组由相似数据点组成的对象。簇内的数据点之间相互之间比较相似,而与簇外的数据点相比较不相似。聚类分析的目的之一就是识别出这样的簇。
K值(K):这是我们要将数据点划分的聚类数目。在K均值算法中,我们需要事先指定K的值,然后算法会试图找到最佳的K个聚类中心。
聚类中心(Cluster Centers):每个聚类都有一个中心点,这个中心点是该聚类中所有数据点的平均值。在K均值算法中,聚类中心是不断更新的,以便最小化每个数据点到其中心点的距离之和。
初始质心(Initial Centroid):指在开始迭代之前随机选择的K个数据点,它们被用作每个簇的初始中心。质心代表了簇的平均位置,它是簇内所有数据点的中心点。
距离(Distance):用来衡量两个数据点或数据点与聚类中心之间的相似度。在K均值中,通常使用欧几里得距离(直线距离)来计算这种相似度。
K均值算法步骤:
肘部方法(Elbow Method):这是一种确定最佳K值的方法。通过绘制不同K值下的聚类总误差(通常是簇内误差平方和SSE)的图表,我们可以找到一个“肘部”区域,在这个区域,增加聚类数目不会再显著减少误差。
市场细分:通过分析消费者的购买行为、偏好和特征,将市场划分为几个不同的群体,以便于 targeted marketing 和产品定位。
客户分群:在金融服务行业中,根据客户的行为、财富状况和需求将客户分为不同的群体,以便提供个性化的服务和产品。
社交网络分析:在社交网络中,对用户进行聚类,可以发现社区结构、兴趣小组或者有影响力的用户群体。
图像和视频处理:在图像识别和视频分析中,K均值可以用来对图像像素或视频帧进行聚类,从而进行图像分割、对象识别和视频压缩等。
基因数据分析:在生物信息学中,K均值聚类可以用来对基因表达数据进行聚类分析,帮助科学家发现基因群体的模式和关联。
城市规划:在城市规划和交通管理中,K均值聚类可以用来对人口、建筑或者交通流量进行分类,以便更好地规划城市基础设施。
推荐系统:在推荐系统中,通过用户和物品的聚类,可以发现用户之间的相似性或者物品之间的关联性,从而提供个性化的推荐。
异常检测:在网络安全和金融领域,K均值聚类可以用来检测异常行为或欺诈行为,通过识别不符合正常模式的数据点来预警潜在的风险。
文本挖掘:在自然语言处理中,K均值聚类可以用来对文本数据进行分类,从而进行主题建模、情感分析等。
教育数据分析:在教育领域,通过对学生的成绩、行为和兴趣进行聚类,可以为学生提供个性化的学习计划和资源。
医疗健康:在医疗数据分析中,K均值聚类可以用来对病人的症状、治疗方案或者医疗费用进行分类,以便于疾病管理和资源分配。
Python
实现- from sklearn.cluster import KMeans
- KMeans(n_clusters=8, init=’k-means++’, max_iter=300, random_state=None)
n_clusters
:int
类型,簇的个数。
init
:初始质心的方法,可以选择k-means++
或random
max_iter
:最大迭代次数
random_state
:初始质心的随机生成种子
iris
数据- irisdf = pd.read_csv('./data/visualization/iris.csv',header=0)
- irisdf.head()
- irisdf.shape
- irisdf.plot(y=['sepal_length','sepal_width','petal_length','petal_width'],
- kind='box',figsize=(12,6))
- irisKmeans = KMeans(n_clusters=3,random_state=0)
- irisKmeans
- #X:需要聚类的数据集
- kmeans.fit(X)
- irisX = irisdf.iloc[:,:-1]
- irisX.head()
-
- irisKmeans.fit(irisX)
irisKmeans.labels_
labels_
:每个数据点(样本)的标签,即所属的簇irisKmeans.inertia_
inertia_
:簇内误差平方和kmean.predict(X)
[n_samples]
- irisLabel = irisKmeans.predict(irisX)
- irisLabel
随着K值的增大,簇内误差平方和(SSE)会降低
SSE:在给定的聚类划分下,簇内数据点与它们的簇中心之间的平均差异。
SSE的值越小,说明簇内的数据点与它们的簇中心越接近,聚类的质量越好
肘部(elbow)法则:识别SSE开始快速增大处的K值
- sse = [] ###记录每个k值对应的SSE
- for each in range(1,11):
- km = KMeans(n_clusters=each,random_state=0)
- km.fit(irisX)
- sse.append(km.inertia_)
- ax = pd.Series(sse).plot(kind='line',figsize=(12,6),
- marker='o',grid=True,xticks=range(0,10)) #xticks:在哪些位置显示x轴刻度标签
- _ = ax.set(xticklabels=range(1,11)) # 改变x轴标签显示,默认是从0开始
scikit-learn
可视化软件包- pip install -U yellowbrick
- conda install -c districtdatalabs yellowbrick
Yellowbrick
:基于scikit-learn
与matplotlib
- from yellowbrick.cluster import KElbowVisualizer
-
- kviz = KElbowVisualizer(KMeans(), k=(1,11), metric='distortion',
- timings=True, locate_elbow=True)
-
- kviz.fit(X)
- kviz.show()
k
:需要检验的k
值序列
k=(1,11)
表示要评估的聚类中心数量的范围,从1到11。这个范围可以通过调整来查看不同聚类数目下的效果。metric
:检验的标准,默认是“距离误差平方和”,还可以是'silhouette`
metric='distortion'
指定了使用distortion(误差平方和,也称为簇内误差平方和SSE)作为评估聚类质量的指标。timeings
:是否绘制计算每个k
值对应的聚类时间
timings=True
表示开启计算每个聚类中心所需时间的计时。locate_elbow
:是否显示肘部位置
locate_elbow=True
表示开启寻找“肘部”点,即聚类质量开始下降的点,这个点通常被认为是最优聚类数目的一个良好估计。- kmodel = KMeans(random_state=10)
- elbowViz = KElbowVisualizer(kmodel, k=(1,11))
- elbowViz.fit(irisX)
- elbowViz.show()
凝聚层次聚类(Agglomerative Hierarchical Clustering)是一种自底向上的聚类方法,它通过逐步合并相似度高的聚类来构建一个嵌套的聚类层次结构。
层次结构(Hierarchy):凝聚层次聚类建立了一个从简单到复杂的层次结构,其中较低层次的聚类合并形成较高层次的聚类。这种结构可以表示为树状图,也称为dendrogram。
聚类(Clusters):在凝聚层次聚类中,聚类可以看作是由数据点组成的集合,这些数据点在某些特征上相似。聚类可以是任意形状和大小的,不一定是紧凑的。
合并(Merging):凝聚层次聚类通过合并相似的聚类来构建层次结构。合并是指将两个或多个聚类组合成一个更大的聚类,这个更大的聚类包含了原来聚类的所有数据点。
相似度(Similarity):相似度是一个度量标准,用于评估两个聚类之间的接近程度。在凝聚层次聚类中,常用的相似度度量是距离,比如欧几里得距离或者曼哈顿距离。
距离矩阵(Distance Matrix):距离矩阵是一个二维数组,用于存储每个聚类对之间的相似度(距离)。在凝聚层次聚类中,距离矩阵随着聚类的合并而更新。
链接(Linkage):链接是指决定如何合并聚类的方法。凝聚层次聚类有几种不同的链接方式,如单链接(single linkage)、完全链接(complete linkage)和平均链接(average linkage)。
单链接(Single Linkage):单链接是最常用的链接方法之一,它会选择两个聚类中最近的数据点对来合并聚类。
完全链接(Complete Linkage):完全链接是另一种链接方法,它会选择两个聚类中最远的 data point 对来合并聚类。
平均链接(Average Linkage):平均链接方法会计算两个聚类中所有数据点对之间的平均距离,以此作为合并聚类的依据。
距离阈值(Distance Threshold):在凝聚层次聚类中,可以设置一个距离阈值,只有当两个聚类的平均距离小于这个阈值时,它们才会被合并。
聚类原理:
适用场景:
结果表示:
簇的数量:
算法复杂度:
硬聚类与软聚类:
Python
实现- from scipy.cluster import hierarchy
- hierarchy.linkage(y, method='single', metric='euclidean')
这行代码告诉scikit-learn
使用single
链接方法和euclidean
距离度量来对数据进行层次聚类分析。执行后,它会返回一个聚类树(dendrogram),表示数据点随着聚类合并的层次结构。
y
:利用pdist()
函数得到的两两样本之间的距离数组,或者是原始数据
y
是一个二维数组或距离矩阵,表示数据点之间的相似度或距离。每个元素 y[i][j]
表示数据点 i
和 j
之间的距离或相似度。
method
:簇之间的近邻性度量方法,可取的值包括single
,complete
,average
等
method='single'
是链接方法(Linkage Method)的参数。在层次聚类中,链接方法决定了如何合并两个聚类。single
链接方法是指在合并两个聚类时,只考虑两个聚类中最近的数据点对之间的距离。换句话说,它会选择两个聚类中距离最近的两个点,并将它们作为新的聚类中心。
metric
:选用的距离
metric='euclidean'
是距离度量(Distance Metric)的参数。它定义了计算数据点之间距离的方法。euclidean
距离是指欧几里得距离,它是两点之间的直线距离,适用于各维度具有同等重要性的情况。
linkage
矩阵,层次聚类的结果- cityDf = pd.read_csv('./data/clustering/cities_10.csv',header=0)
- cityDf.head()
-
- cityDf.set_index(cityDf.pop('AREA'),inplace=True)
- cityDf
cityDf.plot(y=[f'X{i}' for i in range(1,10)],kind='box',figsize=(12,6))
- from sklearn.preprocessing import StandardScaler
-
- cityScaler = StandardScaler()
- cityX = cityScaler.fit_transform(cityDf)
- cityX
- from scipy.cluster import hierarchy
-
- cityAve = hierarchy.linkage(cityX,method='average',metric='euclidean')
- cityAve
- pd.DataFrame(squareform(pdist(cityX,metric='euclidean')),
- columns=cityDf.index,index=cityDf.index)
这段代码是使用Python的pandas和scipy库来生成一个DataFrame,其中包含了城市之间的欧几里得距离矩阵。目的是计算城市之间的欧几里得距离,并将这些距离存储在一个DataFrame中,以便进一步分析或可视化城市之间的空间关系。
cityX
是一个包含城市数据的列表或数组,假设每个城市是一个数据点,城市之间的数据可以是一个二维数组,其中行代表城市,列代表不同的特征。
pdist(cityX, metric='euclidean')
是scipy.spatial.distance.pdist函数的调用,用于计算城市之间的成对距离。metric='euclidean'
参数指定使用欧几里得距离作为距离度量。欧几里得距离是指在多维空间中两点之间的直线距离。
squareform(pdist(cityX, metric='euclidean'))
是scipy.spatial.distance.squareform函数的调用,用于将成对距离转换成方阵形式。在方阵中,行和列都代表城市,对角线上的元素是城市与自己之间的距离,非对角线上的元素是城市之间的距离。
pd.DataFrame()
是pandas库中的DataFrame构造函数,用于将上述生成的距离方阵转换成pandas的DataFrame对象。DataFrame是一个二维标签化数据结构,可以方便地进行数据操作和分析。
columns=cityDf.index, index=cityDf.index
是DataFrame构造函数的参数,它们分别指定了DataFrame的列名和行名。这里假设cityDf
是另一个包含城市信息的DataFrame,cityDf.index
包含了城市的名称或标识符。
[(each,idx) for idx,each in enumerate(cityDf.index)]
这行代码 [(each, idx) for idx, each in enumerate(cityDf.index)]
是一个Python列表推导式,它的作用是创建一个包含元组的列表,每个元组包含两个元素:each
和 idx
。
cityDf.index
是 pandas DataFrame 的一个属性,它包含了 DataFrame 中所有行的标签。例如,如果 DataFrame 有三行,标签可能是 ['A', 'B', 'C']
。enumerate(cityDf.index)
函数会遍历 cityDf.index
中的每个元素,并返回一个包含索引和元素值的元组。例如,对于上面的标签,enumerate(cityDf.index)
会返回 [(0, 'A'), (1, 'B'), (2, 'C')]
。for idx, each in enumerate(cityDf.index)
部分遍历由 enumerate(cityDf.index)
生成的每个元组,idx
是每个元素的索引,each
是每个元素的值。 所以,这个列表推导式生成的列表是一个包含所有城市及其索引的元组列表。例如,如果 cityDf.index
是 ['纽约', '洛杉矶', '芝加哥']
,那么列表推导式生成的列表将是 [('纽约', 0), ('洛杉矶', 1), ('芝加哥', 2)]
。
- pd.DataFrame(cityAve,columns=['行号','行号','距离','簇中包含的样本数量'],
- index=[f'簇{i}' for i in range(cityAve.shape[0])])
cityAve
是一个 NumPy 数组,可能包含了每个城市的一些平均值或者聚类结果。columns=['行号','行号','距离','簇中包含的样本数量']
指定了新创建的 DataFrame 的列名。这里有四列,两列名为 ‘行号’,可能是因为 DataFrame 是对称的,每行和每列代表同一个城市的不同信息。'距离’和’簇中包含的样本数量’是其他两列的名称。cityAve.shape[0]
:这是 NumPy 数组 cityAve
的第一个维度的大小,即数组中的元素或行数。这个值通常代表了聚类的簇数,因为在聚类分析中,每个簇通常会有一个对应的行。for i in range(cityAve.shape[0])
:这个循环会遍历从 0
到 cityAve.shape[0] - 1
的整数,即从 0
到 cityAve.shape[0] - 1
。f'簇{i}'
:这是一个格式化字符串,其中 {i}
会被循环变量 i
的值替换。所以,当 i
为 0
时,字符串是 '簇0'
;当 i
为 1
时,字符串是 '簇1'
,以此类推。index=[f'簇{i}' for i in range(cityAve.shape[0])]
:列表推导式创建了一个新的列表,其中包含了上述生成的所有字符串。这个列表最终被用作 DataFrame 的行索引。- from scipy.cluster import hierarchy
- hierarchy.dendrogram(Z, orientation='top', labels=None, ax=None)
Z
:linkage
矩阵,层次聚类结果orientation
:根结点的位置,可选`{"top", "bottom","left","right"}
labels
:原始数据点的标签,默认为None
,即原始数据样本默认的行标签ax
:matplotlib Axes
对象,
matplotlib.axes._subplots.Axes
实例,用于绘制谱系图。如果提供了这个参数,谱系图将在指定的轴上绘制,而不是创建一个新的图形。- import matplotlib.pyplot as plt
-
- fig, ax = plt.subplots(figsize=(12,6))
- cityDn = hierarchy.dendrogram(cityAve,ax=ax,labels=cityDf.index)
- plt.show()
‘single’(单链接):这是最简单的链接度量方法之一。在单链接聚类中,两个聚类之间的链接距离是两个聚类中最接近的两个点的距离。换句话说,它选择了两个聚类中最近的点对作为聚类间的距离。这种方法倾向于形成较大的聚类。
‘complete’(完全链接):与单链接方法相反,完全链接聚类中,两个聚类之间的链接距离是两个聚类中最远的两个点的距离。这种方法倾向于形成较小的聚类。
‘average’(平均链接):平均链接聚类中,两个聚类之间的链接距离是所有成对点的距离的平均值。这种方法试图找到一个中间点的距离,作为两个聚类间的平均距离。
- # 初始化一个空列表来存储链接矩阵
- cityLinkages = []
-
- # 创建一个图形和一个轴的集合,用于绘制三个谱系图
- # 3行1列,每个轴用于绘制一种不同的链接方法
- fig, axes = plt.subplots(3, 1, figsize=(12, 12))
-
- # 遍历三种不同的链接方法
- for idx, linkage in enumerate(['single', 'complete', 'average']):
- # 使用scipy的hierarchy模块中的linkage函数进行层次聚类
- # cityX是一个距离矩阵,metric='euclidean'指定使用欧几里得距离作为相似度度量
- lnk = hierarchy.linkage(cityX, method=linkage, metric='euclidean')
-
- # 使用hierarchy模块中的dendrogram函数绘制谱系图
- # lnk是上一步计算的链接矩阵,ax=axes[idx]指定在哪个轴上绘制,labels=cityDf.index提供了每个簇的标签
- dn = hierarchy.dendrogram(lnk, ax=axes[idx], labels=cityDf.index)
-
- # 显示图形
- plt.show()
sklearn
中的凝聚层次聚类 - from sklearn.cluster import AgglomerativeClustering
- AgglomerativeClustering(n_clusters=2, affinity=’euclidean’, linkage=’ward’)
这行代码创建了一个层次聚类器,指定要生成两个簇,使用欧几里得距离作为相似性度量,使用ward方法作为链接方式。
AgglomerativeClustering
是scikit-learn库中的一种聚类算法,它是一种层次聚类算法。n_clusters
:int
类型,簇的个数,指定要生成的簇的数量affinity
:近邻度的度量,指定用于计算相似性的度量,可以选择'euclidean', 'manhattan', 'cosine'
等
affinity='euclidean'
表示使用欧几里得距离作为度量。欧几里得距离是一种衡量两点之间直线距离的方法,适用于空间中点的距离计算。linkage
:str
类型,簇之间的链接类型,指定用于合并相似性度的链接方法,可以选择'ward', 'complete', 'average', 'single'
linkage='ward'
表示使用ward方法。Ward方法是一种优化类间距离的方法,目的是减少类内的平方误差和最大化类间的平方误差。这种方法通常用于聚类分析,特别是在处理数据点数量较多且维度较高时。AgglomerativeClustering
对凝聚层次聚类剪枝- from sklearn.cluster import AgglomerativeClustering
-
- cityAc = AgglomerativeClustering(n_clusters=4,affinity='euclidean',linkage='average')
- cityAc
- cityLabels = cityAc.fit_predict(cityX)
- cityLabels
-
- cityDf['cluster']=cityLabels
- cityDf
基于密度的聚类(Density-Based Clustering)是一种聚类算法,它主要根据数据点的密度来划分簇。与传统的聚类方法(如K-Means)相比,基于密度的聚类方法在处理复杂数据结构时能更好地发现簇的形状和大小。
密度:密度反映了数据点在空间中的分布。在基于密度的聚类中,密度高的区域表示数据点较为集中,而密度低的区域则表示数据点较为稀疏。
核心点(Core Points):核心点是指在一个簇中,至少要有足够的邻居(根据预设的邻域半径)来满足某个密度阈值的数据点。核心点是构成簇的基础。
边界点(Border Points):边界点是指那些邻居不足以满足密度阈值的数据点,它们可能属于某个簇,但也可能接近另一个簇的边界。
邻域(Neighborhood):邻域是指在数据空间中,一个数据点周围的一定范围内的点。邻域的大小通常由一个距离阈值来决定。
基于密度的聚类算法通常包括以下步骤:
一些著名的基于密度的聚类算法包括:
基于密度的聚类(Density-Based Clustering):
凝聚层次聚类(Agglomerative Hierarchical Clustering):
K均值聚类(K-Means Clustering):
总结:
Python
实现- from sklearn.cluster import DBSCAN
- DBSCAN(eps=0.5, min_samples=5, metric='euclidean', n_jobs=None)
eps
:float
类型,半径,两个数据点被认为属于同一个邻域的最大距离
eps
,它们被视为邻近点。eps
的选择取决于数据集的特性,通常需要通过实验来确定一个合适的值。min_samples
:int
类型,核心点所在邻域所要包含的数据点的最小数量,核心点包括在内
min_samples
个点,这样才能被认定为核心点。这个值也需要根据具体的数据集来确定。metric
:距离的度量,可以选择'minkowski','euclidean'
等
euclidean
表示使用欧几里得距离。还有其他距离度量方法,如曼哈顿距离(manhattan
)、切比雪夫距离(chebyshev
)等。n_jobs=None
:这个参数用于并行计算,如果设置为-1
,则表示使用所有可用的处理器来进行并行计算。这可以加快算法的执行速度,特别是对于大规模数据集。如果设置为其他值,表示使用指定数量的处理器。
- from sklearn.cluster import DBSCAN
-
- irisDB = DBSCAN(eps=1,min_samples=30,metric='euclidean',n_jobs=-1)
- irisLabelsDB = irisDB.fit_predict(irisX)
- irisLabelsDB
min_samples
min_samples
过小,簇数量过多min_samples
过大,簇数量过少min_samples
应当增大eps
半径eps
- from sklearn.neighbors import NearestNeighbors
- NearestNeighbors(n_neighbors=5, n_jobs=None)
n_neighbors
:邻近点数量n_jobs
:用多少个核并行计算,-1为所有核- nbrsIris = NearestNeighbors(n_neighbors=5) # 建立近邻模型
- nbrsIris.fit(irisX)
- distancesIris, indicesIris = nbrsIris.kneighbors(irisX)
- distancesIris # 与最邻近点之间的距离
-
- indicesIris # 最邻近点的索引
- distancesIris = np.sort(distancesIris[:,-1], axis=0)
-
- axDistIris = pd.Series(distancesIris).plot(kind='line')
- axDistIris.set(ylabel='Distance')
- pip install kneed[plot]
-
- from kneed import KneeLocator
-
- KneeLocator(x,y,S=1,curve='convex',direction='increasing')
x
:待检测数据对应的横轴数据序列,一系列的值,通常是对应于聚类数量的 x 轴数据。y
:待检测数据序列,一系列的值,通常是对应于某种性能指标的 y 轴数据。这个性能指标可以是聚类质量、轮廓系数、内部凝聚度等S
:敏感度参数,越小对应拐点被检测出得越快,建议值1,这个参数是用来平滑曲线的。S
越小,曲线越尖锐,拐点越容易识别。默认值为 1,通常不需要调整。curve
:曲线类型,可以是concave(凹函数),也可以是convex(凸函数),指定曲线的形状。'convex'
表示凸曲线,'concave'
表示凹曲线。默认值为 'convex'
。direction
:曲线趋势,指定寻找拐点的方式。可以是increasing或decreasing'increasing'
表示随着 x 增加,y 也增加;'decreasing'
表示随着 x 增加,y 减少。默认值为 'increasing'
。- kneeIris = KneeLocator(range(len(distancesIris)),distancesIris,S=1,
- curve='convex',direction='increasing',online=False)
-
- kneeIris.plot_knee() # 绘制曲线与拐点位置(肘部图)
- distancesIris[kneeIris.elbow]
- irisDBNew = DBSCAN(eps=0.678,min_samples=5,metric='euclidean',n_jobs=-1)
- irisDBNew.fit_predict(irisX)
eps
(epsilon):这是DBSCAN算法中的一个关键参数,它表示邻域的大小。在这个例子中,eps=0.678
意味着如果一个点到核心点的距离小于或等于0.678,那么这个点将被视为属于同一个邻域。
min_samples
:这是另一个重要参数,它表示一个聚类需要的最小样本数。在这个例子中,min_samples=5
意味着只有当一个核心点周围至少有5个点时,它才会被用于形成一个聚类。
metric='euclidean'
:这指定了距离度量方法,euclidean
表示欧几里得距离,这是一种在多维空间中测量两点之间直线距离的方法。
n_jobs=-1
:这个参数用于并行计算,-1
表示使用所有可用的处理器,以便加快算法的执行速度。这对于拥有多个核心的现代计算机是非常有用的,可以显著减少计算时间。
- from sklearn.datasets import make_moons
-
- X,y = make_moons(n_samples=200,noise=0.05,random_state=0)
- X[:5,:]
- y[:5]
-
- pd.DataFrame(X).plot(kind='scatter',x=0,y=1,figsize=(12,6),c='steelblue')
- km = KMeans(n_clusters=2,random_state=0)
- y_km = km.fit_predict(X)
-
- ax_km = pd.DataFrame(X[y_km==0,:]).plot(kind='scatter',x=0,y=1,figsize=
- (12,6),c='lightblue',edgecolor='black',marker='o',s=40,label='cluster 1')
-
- pd.DataFrame(X[y_km==1,:]).plot(kind='scatter',x=0,y=1,ax=ax_km,
- c='red',edgecolor='black',marker='s',s=40,label='cluster 2')
-
- ax_km.set(title='K-means clustering')
- ac = AgglomerativeClustering(n_clusters=2,affinity='euclidean',linkage='complete')
- y_ac = ac.fit_predict(X)
-
- ax_ac = pd.DataFrame(X[y_ac==0,:]).plot(kind='scatter',x=0,y=1,figsize=
- (12,6),c='lightblue',edgecolor='black',marker='o',s=40,label='cluster 1')
-
- pd.DataFrame(X[y_ac==1,:]).plot(kind='scatter',x=0,y=1,ax=ax_ac,c='red',edgecolor='black',marker='s',s=40,label='cluster 2')
-
- ax_ac.set(title='Agglomerative clustering')
- db = DBSCAN(eps=0.2,min_samples=5,metric='euclidean')
- y_db = db.fit_predict(X)
-
- ax_db = pd.DataFrame(X[y_db==0,:]).plot(kind='scatter',x=0,y=1,
- figsize=(12,6),c='lightblue',edgecolor='black',marker='o',s=40,label='cluster 1')
-
- pd.DataFrame(X[y_db==1,:]).plot(kind='scatter',x=0,y=1,ax=ax_db,
- c='red',edgecolor='black',marker='s',s=40,label='cluster 2')
-
- ax_db.set(title='DBSCAN clustering')
聚类检验:检验聚类效果的优劣
凝聚度(cohesion):簇内数据点之间的密切程度
分离度(separation):某个簇不同于其他簇的程度
轮廓系数的Python
实现- from sklearn.metrics import silouette_samples, silhouette_score
- silhouette_samples(X, labels, metric=’euclidean’)
sklearn.metrics.silhouette_samples
这个函数用于计算每个样本的轮廓系数
X
:用于聚类的数据,是一个二维数组,其中包含了用于聚类的数据点。每个数据点是一个样本,而每行代表了单个样本的所有特征。labels
:用聚类技术计算的每个数据样本所属的簇,是一个一维数组,包含了每个样本的聚类标签。数组的长度应该与X
中样本的数量相匹配。metric='euclidean'
:这是一个字符串参数,指定了用于计算距离的度量方法。在这个例子中,'euclidean'
表示使用欧几里得距离来计算样本之间的相似度。
[n_samples]
silhouette_score(X, labels, metric=’euclidean’)
这串代码是一个函数调用,用于计算整个数据集的轮廓系数平均值
X
:用于聚类的数据labels
:用聚类技术计算的每个数据样本所属的簇float
类型,所有数据样本的轮廓系数的平均值- from sklearn.metrics import silhouette_samples, silhouette_score
-
- irisSilhouetteVals = silhouette_samples(irisX,irisKmeans.labels_)
- irisSilhouetteVals
-
- irisSilhouetteScore = silhouette_score(irisdf.iloc[:,:-1],irisKmeans.labels_)
- irisSilhouetteScore
-
- irisSilhouetteVals.mean()
silhouette_score
实际上等于silhouette_samples
返回值的均值轮廓系数图:将每个簇中的样本的轮廓系数按升序排序,绘制成的水平柱状图
- from matplotlib import cm
-
- def silhouette_plot(clusterLabels, X):
- """绘制轮廓系数图,clusterLabels是聚类预测得到的簇标签,X是原始数据集"""
- silhouetteVals = silhouette_samples(X,clusterLabels) # 计算所有样本的轮廓系数
- fig,ax = plt.subplots(figsize=(12,12))
- yLower = 10 # 每个簇纵坐标的下界
- yTicks = [] # 记录纵坐标标记的位置
- uniqueClusters = np.unique(clusterLabels) #获得独特的簇标签
- for k in uniqueClusters:
- # 筛选出第k簇样本的所有轮廓系数
- kthClusterSilhouetteVals = silhouetteVals[clusterLabels==k]
- # 对筛选出的第k簇的轮廓系数排序
- kthClusterSilhouetteVals.sort()
- # 每个簇纵坐标的上界
- yUpper = yLower + len(kthClusterSilhouetteVals)
- # 为每个簇设定一个颜色
- colors = cm.nipy_spectral(k / len(uniqueClusters))
- # 绘制水平柱状图
- ax.barh(range(yLower,yUpper),kthClusterSilhouetteVals,height=1.0,edgecolor='b',color=colors)
- # 设置纵坐标标记的显示位置
- yTicks.append((yLower+yUpper)/2)
- # 更新下一个簇的纵坐标的下界
- yLower = yUpper + 10
- ax.set(xticks=np.linspace(-0.1,1,12), yticks=yTicks,yticklabels=uniqueClusters,xlabel='轮廓系数',ylabel='簇标签',xlim=[-0.1,1])
- # 将平均轮廓系数用垂直线绘制在图中
- ax.axvline(x=silhouetteVals.mean(), color="red", linestyle="--")
- plt.show()
-
- silhouette_plot(irisLabel,irisX)
Yellowbrick
中的轮廓系数图Yellowbrick 是一个可视化库,它提供了用于数据可视化和模型评估的工具。
- from yellowbrick.cluster import SilhouetteVisualizer
- silviz = SilhouetteVisualizer(estimator, colors=None)
- silviz.fit(X)
- silviz.show()
estimator
:是一个已经训练好的聚类模型,它应该是一个scikit-learn聚类 estimator 对象,例如KMeans
、DBSCAN
等。这个 estimator 对象用于计算聚类结果和轮廓系数。color
:轮廓图颜色,是一个可选参数,用于指定聚类中心的颜色。如果提供,它应该是一个颜色字符串列表或者颜色映射,例如['red', 'blue', 'green']
或者plt.cm.Set1
。如果未提供,Yellowbrick 会使用默认的颜色映射。可以是Yellowbrick
或者matplotlib
的颜色地图,例如Yellowbrick
的颜色地图参考,Colors and Style — Yellowbrick v1.5 documentation- silViz = SilhouetteVisualizer(i ,color='yellowbrick')
- silViz.fit(irisX)
- silViz.show()
MDS
t-SNE
将高维空间数据投射到低维(2维或3维)空间,并保持高维空间中点之间的相似关系,实际上是维度规约(Dimensionality Reduction)的一个具体应用。维度规约是指将数据从高维空间转换到较低维空间的过程,旨在通过去除不重要或不显著的变量来简化数据集,同时尽可能保留原始数据中的信息和结构。
在这个背景下,核心概念是:
保持相似性:在降低维度的过程中,确保数据点在低维空间中的相对位置和距离与他们在高维空间中的相对位置和距离尽可能相似。这意味着,如果两个点在高维空间中是接近的,它们在低维空间中也应该是接近的。
数据结构保留:在降维后的空间中,数据的结构和模式应该仍然明显,这样聚类分析等任务就可以在低维空间中有效地进行,而不会失去重要的信息。
可视化:在2维或3维空间中可视化高维数据,使得人类分析师能够直观地理解和解释数据。
因此,将数据投射到低维空间并保持相似关系是维度规约的一部分,特别是在聚类和数据挖掘的上下文中。这个过程对于分析复杂数据集、识别模式和趋势以及进行有效的数据可视化至关重要。选择合适的降维算法对于实现这些目标至关重要,因为不同的算法在保留数据结构方面有不同的效果。
- from yellowbrick.cluster import InterclusterDistance
- InterclusterDistance(estimator,embedding='mds',scoring='membership',random_state=None)
estimator
:这是一个已经训练好的聚类模型,它应该是一个scikit-learn聚类 estimator 对象,例如KMeans
、DBSCAN
等。这个 estimator 对象用于计算聚类结果。
embedding
:高维空间到低维空间的投射方法,这个参数指定了用于将聚类结果映射到低维空间的嵌入方法。在这里,'mds'
表示使用多维尺度变换(Multidimensional Scaling,MDS)这种方法。MDS是一种无监督学习算法,用于将高维数据映射到低维空间,同时尽可能地保持数据点之间的相似性。相似性通常指的是数据点之间的接近程度
scoring
:决定簇在图上展现的大小,‘membership’计算每个簇中样本数量
random_state
:这是一个可选参数,用于指定随机状态,以保证结果的可重复性。如果提供了整数值,那么算法将使用这个随机状态;如果没有提供,那么算法可能会使用一个默认的随机状态或者不使用随机状态。
- idVis = InterclusterDistance(irisKmeans,emdding='tsne',random_state=10)
- idVis.fit(irisX)
- idVis.show()
某企业由于投放的广告渠道比较多,需要对其做广告效果分析以实现有针对性的广告效果测量和优化工作。
要求:将广告分类并找出重点特征,为后续的业务讨论提供支持。
- adRaw = pd.read_csv('./data/clustering/ad_performance.txt',sep='\t')
- adRaw.head()
- adRaw.shape
- adRaw.dtypes
adRaw.describe()
- for colName in adRaw.columns[-5:]:
- adRaw[colName].value_counts(normalize=True)
这段代码的目的是遍历DataFrame中最后五个列,并计算每个列中不同值的出现频率,归一化到概率分布。
adRaw
:这是一个Pandas DataFrame对象,它包含了数据。
adRaw.columns[-5:]
:这个表达式获取DataFrame中的列名列表,并且只选择最后五个列。[-5:]
是一个切片操作,它从列列表的末尾开始,选择最后一个到倒数第五个元素。
for colName in adRaw.columns[-5:]:
:这是一个for循环,它遍历刚才选择的列名列表。colName
是循环中的临时变量,用于存储当前的列名。
adRaw[colName].value_counts(normalize=True)
:在循环体内,对每一列执行value_counts
方法。这个方法用于计算列中每个唯一值的出现次数。normalize=True
参数表示将计数结果归一化,即转换为概率分布。这意味着每个值的计数将被 normalized 为该列的总值的比例。
- _ = adRaw.plot(y=['日均UV','平均注册率','平均搜索量','访问深度',
- '平均停留时间','订单转化率','投放总时间'],
- kind='hist',bins=50,figsize=(12,12),subplots=True,layou
y=['日均UV','平均注册率','平均搜索量','访问深度','平均停留时间','订单转化率','投放总时间']
:这个参数指定了要绘制直方图的列名列表。
bins=50
:这个参数指定了直方图的柱状数量。bins
的数量会影响直方图的分辨率,即每个柱状表示的数据范围。
subplots=True
:这个参数指示函数创建一个子图网格,每个指定的列将在不同的子图上绘制直方图。
layout
:这个参数可能是用于指定子图的布局,但是这里的代码片段中没有提供完整的参数值,所以具体布局无法确定。通常,layout
参数可以是一个字典,用于指定子图的排列方式,例如layout={'rows': 2, 'cols': 3}
,表示创建一个2行3列的子图网格。
- colNames = ['日均UV','平均注册率','平均搜索量','访问深度',
- '平均停留时间','订单转化率','投放总时间']
-
- fig,axes = plt.subplots(len(colNames),1,figsize=(12,36))
-
- for i,colName in enumerate(colNames):
- _ = adRaw[colName].plot(y=colName,kind='hist',bins=50,ax=axes[i],
- color=cm.gist_earth(i/len(colNames)))
-
- _ = axes[i].set(xlabel=colName)
日均UV
,平均注册率
,平均搜索量
,访问深度
,平均停留时间
,订单转化率
均呈现偏态分布_ = adRaw.plot(y=colNames,kind='box',figsize=(12,6))
日均UV
有较多的异常点adRaw.isna().sum()
adRaw.loc[adRaw['平均停留时间'].isna(),:]
- adRaw.fillna({'平均停留时间':adRaw['平均停留时间'].mean()},inplace=True)
- adRaw.isna().sum()
adRaw.duplicated().unique()
- adX = adRaw.copy()
- for colName in adRaw.columns[-5:]:
- codes,_ = pd.factorize(adX[colName])
- adX[colName] = codes
- adX.head()
- adX.set_index(keys='渠道代号',inplace=True)
- adX.head()
- from sklearn.preprocessing import MinMaxScaler
-
- adScale = MinMaxScaler()
- scaleDat = adScale.fit_transform(adX.iloc[:,:7])
- scaleDf = pd.DataFrame(scaleDat,columns = adX.columns[:7],index=adX.index)
- scaleDf.head()
- adXScale = scaleDf.merge(right=adX.iloc[:,-5:],left_index=True,right_index=True)
- adXScale.head()
- adXScale = scaleDf.merge(right=adX.iloc[:,7:],left_index=True,right_index=True)
- adXScale.head()
- kwebElbowViz = KElbowVisualizer(KMeans(random_state=10),k=(1,21))
- kwebElbowViz.fit(adXScale)
- kwebElbowViz.show()
- inertias = []
- for k in range(2,21):
- km = KMeans(n_clusters=k,random_state=20,n_jobs=-1)
- _ = km.fit(adXScale)
- inertias.append(km.inertia_)
- adAx = pd.Series(inertias).plot(kind='line',marker='o',grid=True,figsize=(12,6))
- _ = adAx.set(xticks=range(0,20),xticklabels=range(2,21),xlabel='$K$',ylabel='SSE')
- kwebElbowVizSil = KElbowVisualizer(KMeans(random_state=10),k=(2,21),metric='silhouette')
- kwebElbowVizSil.fit(adXScale)
- kwebElbowVizSil.show()
- sil = []
- K = range(2,21)
- for k in K:
- km = KMeans(n_clusters=k,random_state=20,n_jobs=-1)
- kmPred = km.fit_predict(adXScale)
- sil.append(silhouette_score(adXScale,kmPred))
- adAx = pd.Series(sil).plot(kind='line',marker='o',grid=True,figsize=(12,6))
- _ = adAx.set(xticks=range(0,20),xticklabels=range(2,21),xlabel='$K$',ylabel='轮廓系数')
选择K=4
- adKm = KMeans(n_clusters=4,random_state=20)
- adClusters = adKm.fit_predict(adXScale)
- pd.Series(adClusters).value_counts()
silhouette_score(X=adXScale,labels=adClusters)
- webSilViz = SilhouetteVisualizer(adKm,color='yellowbrick')
- webSilViz.fit(adXScale)
- webSilViz.show()
- adKmIcVis = InterclusterDistance(adKm,embedding='tsne',random_state=10)
- adKmIcVis.fit(adXScale)
- adKmIcVis.show()
silhouette_plot(adClusters,adXScale)
- from scipy.cluster import hierarchy
- adLinkage = hierarchy.linkage(adXScale,method='average')
- fig,axe = plt.subplots(figsize=(36,24))
- _ = hierarchy.dendrogram(adLinkage,ax=axe,labels=adX.index)
- adHierarchy = AgglomerativeClustering(n_clusters=5,linkage='average')
- adHierarchyClusters = adHierarchy.fit_predict(adXScale)
silhouette_score(adXScale,adHierarchyClusters)
silhouette_plot(adHierarchyClusters,adXScale)
- nbrs = NearestNeighbors(n_neighbors=13).fit(adXScale) # 有12个属性,所以n_neighbors设置维13
- distances, indices = nbrs.kneighbors(adXScale)
- distances
- distances = np.sort(distances[:,-1], axis=0)
-
- knee = KneeLocator(range(len(distances)),distances,S=1,curve='convex',
- direction='increasing',online=True) # online=True会遍历每个x,找到最优的拐点
-
- knee.plot_knee()
- knearest[knee.elbow]
- adDB = DBSCAN(eps=0.413,min_samples=13,metric='euclidean',n_jobs=-1)
- adLabels = adDB.fit_predict(adXScale)
silhouette_score(X=adXScale,labels=adLabels)
silhouette_plot(adLabels,adXScale)
- adXSel = adXScale.loc[adLabels>=0,:]
- adLabelSel = adLabels[adLabels>=0]
-
- silhouette_score(X=adXSel,labels=adLabelSel)
silhouette_plot(adLabelSel,adXSel)
- adDf = adRaw.copy()
- adDf.set_index('渠道代号',inplace=True)
- adDf['cluster'] = adClusters
- adDf.head()
- adGps = adDf.groupby(by='cluster')
-
- resLst = []
- for gp in adGps:
- realCol = gp[1].iloc[:,:7].describe() # 得到数值型属性的描述性统计
- typeCol = gp[1].iloc[:,-6:-1].describe(include='all') # 得到标称型属性的描述性统计
- combCol = pd.concat([realCol.loc['mean',:],typeCol.loc['top',:]])
- # 取数值型属性的均值,与标称型属性的频繁类别,并合并为新列
-
- resLst.append(pd.concat([pd.Series(realCol.loc['count','日均UV'],
- index=['样本数量']),combCol])) # 把合并后的新列追加到列表中
-
- pd.concat(resLst,axis=1) # 把存有4个簇各个属性特征的series合并成一个dataframe
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。