【发布时间】:2021-12-03 13:00:28
【问题描述】:
我正在努力为基于 KMeans 的聚类算法绘制条形图。问题是我想以这样的方式演示集群,即可以在 x 轴的末端描绘非常异常的集群,而其余的集群保持相对相邻。我认为问题是xsticks,它们在x轴上平均分布:
---|---|---|-----------------> x-axis
0 1 2 3
在这种情况下,我想证明这一点,例如基于 Score 标记为 3 的集群预测的位置有点远,需要对 bin 宽度进行一些调整,可能如下所示:
---|---|--------------|------> x-axis
0 1 2 3
到目前为止,我得到了以下结果来展示基于 KM 的算法在异常值检测方面的结果:
from sklearn.cluster import KMeans
import seaborn as sns
import numpy as np
from pandas import DataFrame
from math import pow
import math
class ODKM:
def __init__(self,n_clusters=15,effectiveness=500,max_iter=2):
self.n_clusters=n_clusters
self.effectiveness=effectiveness
self.max_iter=max_iter
self.kmeans = {}
self.cluster_score = {}
#self.labels = {}
def fit(self, data):
length = len(data)
for column in data.columns:
kmeans = KMeans(n_clusters=self.n_clusters,max_iter=self.max_iter)
self.kmeans[column]=kmeans
kmeans.fit(data[column].values.reshape(-1,1))
assign = DataFrame(kmeans.predict(data[column].values.reshape(-1,1)),columns=['cluster'])
cluster_score=assign.groupby('cluster').apply(len).apply(lambda x:x/length)
ratio=cluster_score.copy()
sorted_centers = sorted(kmeans.cluster_centers_)
max_distance = ( sorted_centers[-1] - sorted_centers[0] )[ 0 ]
for i in range(self.n_clusters):
for k in range(self.n_clusters):
if i != k:
dist = abs(kmeans.cluster_centers_[i] - kmeans.cluster_centers_[k])/max_distance
effect = ratio[k]*(1/pow(self.effectiveness,dist))
cluster_score[i] = cluster_score[i]+effect
self.cluster_score[column] = cluster_score
def predict(self, data):
length = len(data)
score_array = np.zeros(length)
for column in data.columns:
kmeans = self.kmeans[ column ]
cluster_score = self.cluster_score[ column ]
#labels = kmeans.labels_
assign = kmeans.predict( data[ column ].values.reshape(-1,1) )
#print(assign)
for i in range(length):
score_array[i] = score_array[i] + math.log10( cluster_score[assign[i]] )
return score_array #,labels
def fit_predict(self,data):
self.fit(data)
return self.predict(data)
测试结果:
import pandas as pd
df = pd.DataFrame(data={'attr1':[1,1,1,1,2,2,2,2,2,2,2,2,3,5,5,6,6,7,7,7,7,7,7,7,15],
'attr2':[1,1,1,1,2,2,2,2,2,2,2,2,3,5,5,6,6,7,7,7,13,13,13,14,15]})
#generate score from KM-based algorithm via class ODKM
odkm_model = ODKM(n_clusters=3, max_iter=1)
result = odkm_model.fit_predict(df)
#include generated scores to the main frame to reach desired plot
df['ODKM_Score']= result
df
#for i in result:
# print(round(i,2))
#results
#-0.51, -0.51 , -0.51 , -0.51, -0.51, -0.51, -0.51, -0.51, -0.51, -0.51, -0.51, -0.51, -0.51
#-0.78, -0.78, -0.78, -0.78, -0.78, -0.78, -0.78
#-0.99, -0.99, -0.99, -0.99
#-1.99
您可以在colab notebook 中找到我的整个代码,包括这个基于 KM 的算法,以便快速调试。如果您需要,请随时在笔记本上实施您的解决方案或在单元格上发表评论,或者 ODKM 算法本身(执行 KM 集群的地方)的一些更改已被脚本化,可以以 @class ODKM 的形式访问。也许最好提取预测的集群标签并在 Cluster_label 的标题下添加一个新列 ODKM 算法 Score 以便更好地访问条形图。
预期的输出应该是这样的(相同集群中更好的 bin 具有相同的颜色,例如 1st cluster C1):
更新:除了条形图解决方案之外,我还可以绘制 Hist 和分布图,但我不知道如何着色和传递聚类标签以按预期在直方图中的 bin 上反映聚类结果.
##left output
# just plot 'Score' column (not all columsn in 1st phase) to simply the problem
#cols_ = df.columns[-1:]
ax1 = plt.subplot2grid((1,1), (0,0))
df['Score'].plot(kind='hist', ax=ax1 , color='b', alpha=0.4)
df['Score'].plot(kind='kde', ax=ax1, secondary_y=True, label='distribution', color='b', lw=2)
##Right output
sns.distplot(df['Score'] , color='b')
尽管在图表上反映了聚类结果,但我注意到存在一些差异,正如我在下图中强调的那样,这两个图 e。 G。 y 轴的比例和靠近 x 轴原点的主要 bin 之间的间隙问题:
我也发现了这个post,但我无法适应@class ODKM 来动态解决我的问题。
我最近也可以做到这一点:
df['Score'] = df['Score'].abs()
sns.displot(df,
x='Score',
hue='Cluster_labels',
palette=["#00f0f0","#ff0000","#00ff00"],
alpha=1)
【问题讨论】:
-
您想仅根据分数值分配集群标签,还是还想包括其他列?
-
这个问题和KMeans或聚类有什么关系吗?我建议您简化有关绘图的问题。
-
@warped Right,仅适用于
Score列上的所有列。但在此之前,我们需要使用.labels_属性返回@class ODKM:内部的预测标签,就像docs 中一样。 -
@mwaskom 我指的是 KM 聚类方法,如果有机会通过使用聚类计算以 条形图 达到所需的输出 e。 g,在 x 轴上操作以突出显示 out cluster(s) 的刻度。
标签: python matplotlib seaborn cluster-analysis k-means