【问题标题】:How would one use Kernel Density Estimation as a 1D clustering method in scikit learn?如何在 scikit learn 中使用核密度估计作为一维聚类方法?
【发布时间】:2016-05-07 18:35:23
【问题描述】:

我需要将一个简单的单变量数据集聚类到预设数量的聚类中。从技术上讲,它更接近于对数据进行分箱或排序,因为它只是一维的,但我的老板称之为聚类,所以我将坚持使用这个名称。 我当前使用的系统使用的方法是 K-means,但这似乎有点过头了。

有没有更好的方法来执行这项任务?

其他一些帖子的答案提到了 KDE(内核密度估计),但这是一种密度估计方法,它是如何工作的?

我看到了 KDE 如何返回密度,但我如何告诉它将数据拆分为 bin?

我如何拥有独立于数据的固定数量的 bin(这是我的要求之一)?

更具体地说,如何使用 scikit learn 实现这一目标?

我的输入文件如下所示:

 str ID     sls
 1           10
 2           11 
 3            9
 4           23
 5           21
 6           11  
 7           45
 8           20
 9           11
 10          12

我想将 sls 编号分组到簇或箱中,这样:

Cluster 1: [10 11 9 11 11 12] 
Cluster 2: [23 21 20] 
Cluster 3: [45] 

我的输出文件将如下所示:

 str ID     sls    Cluster ID  Cluster centroid
    1        10       1               10.66
    2        11       1               10.66
    3         9       1               10.66 
    4        23       2               21.33   
    5        21       2               21.33
    6        11       1               10.66
    7        45       3               45
    8        20       2               21.33
    9        11       1               10.66 
    10       12       1               10.66

【问题讨论】:

  • k-means 有什么问题?性能?
  • kmeans 比 kde 更高效
  • @DavidMaust 1) 当我尝试在单变量数据上运行 sklearn 的 k-means 时,我开始遇到错误。我不得不通过将它聚集在 2d 数据上来欺骗它,这是原始 1d 数据的相同副本。 2)根据这个post这是一个坏主意。
  • @lejlot 查看我对 David Maust 的回复。
  • 你试过写一些代码吗?

标签: machine-learning scikit-learn cluster-analysis data-mining kernel-density


【解决方案1】:

@Has QUIT--Anony-Mousse 接受的答案有一点错误(由于我的声誉,我无法评论或建议编辑)。

行:

print(a[a < mi[0]], a[(a >= mi[0]) * (a <= mi[1])], a[a >= mi[1]])

应该编辑成:

print(a[a < s[mi][0]], a[(a >= s[mi][0]) * (a <= s[mi][1])], a[a >= s[mi][1]])

这是因为mima 是一个索引,其中s[mi]s[ma] 是值。如果您使用mi[0] 作为限制,如果您的上下 linspace >> 您的上限和下限数据,您将面临分裂的风险和错误。例如,运行这段代码,看看拆分结果的不同:

import numpy as np
from numpy import array, linspace
from sklearn.neighbors import KernelDensity
from matplotlib.pyplot import plot
from scipy.signal import argrelextrema

a = array([10,11,9,23,21,11,45,20,11,12]).reshape(-1, 1)
kde = KernelDensity(kernel='gaussian', bandwidth=3).fit(a)
s = linspace(0,100)
e = kde.score_samples(s.reshape(-1,1))
mi, ma = argrelextrema(e, np.less)[0], argrelextrema(e, np.greater)[0]

print('Grouping by HAS QUIT:')
print(a[a < mi[0]], a[(a >= mi[0]) * (a <= mi[1])], a[a >= mi[1]])
print('Grouping by yasirroni:')
print(a[a < s[mi][0]], a[(a >= s[mi][0]) * (a < s[mi][1])], a[a >= s[mi][1]])

结果:

Grouping by Has QUIT:
[] [10 11  9 11 11 12] [23 21 45 20]
Grouping by yasirroni:
[10 11  9 11 11 12] [23 21 20] [45]

【讨论】:

    【解决方案2】:

    自己编写代码。那么它最适合您的问题!

    样板:永远不要假设您从网上下载的代码是正确的或最佳的……请确保在使用之前完全理解它。

    %matplotlib inline
    
    from numpy import array, linspace
    from sklearn.neighbors.kde import KernelDensity
    from matplotlib.pyplot import plot
    
    a = array([10,11,9,23,21,11,45,20,11,12]).reshape(-1, 1)
    kde = KernelDensity(kernel='gaussian', bandwidth=3).fit(a)
    s = linspace(0,50)
    e = kde.score_samples(s.reshape(-1,1))
    plot(s, e)
    

    from scipy.signal import argrelextrema
    mi, ma = argrelextrema(e, np.less)[0], argrelextrema(e, np.greater)[0]
    print "Minima:", s[mi]
    print "Maxima:", s[ma]
    > Minima: [ 17.34693878  33.67346939]
    > Maxima: [ 10.20408163  21.42857143  44.89795918]
    

    因此,您的集群是

    print a[a < mi[0]], a[(a >= mi[0]) * (a <= mi[1])], a[a >= mi[1]]
    > [10 11  9 11 11 12] [23 21 20] [45]
    

    在视觉上,我们做了这样的拆分:

    plot(s[:mi[0]+1], e[:mi[0]+1], 'r',
         s[mi[0]:mi[1]+1], e[mi[0]:mi[1]+1], 'g',
         s[mi[1]:], e[mi[1]:], 'b',
         s[ma], e[ma], 'go',
         s[mi], e[mi], 'ro')
    

    我们切断了红色标记。绿色标记是我们对聚类中心的最佳估计。

    【讨论】:

    • 我会犹豫将此方法称为比 k-means 更好的方法。它确实涉及选择任意带宽,然后计算 50 个密度估计值。话虽如此,我不知道是否有更好的方法来进行核密度估计。
    • 你不必知道k。您不仅可以获得更好的中心(受异常值影响较小),而且还可以获得 sound 分裂点(不仅在中途)。有很多关于带宽的文献,例如 Silverman 规则。还。谁在乎计算 50 个密度估计值?您可以预先计算内核并在快速卷积中执行此操作。
    • 我还要补充一点,这是一维聚类的一种特别快速的非线性缩放方法。
    • 嗨我已经发布了一个关于这个答案的问题,你能帮我解决一下吗? stackoverflow.com/questions/60355497/…
    • 这个被接受的回答有一个小错误(由于我的等级,我之前不能评论)。请参阅下面的答案。
    猜你喜欢
    • 2016-10-14
    • 2015-06-30
    • 2016-09-07
    • 2015-11-25
    • 1970-01-01
    • 2017-05-25
    • 2014-10-03
    • 2015-12-20
    • 2013-07-23
    相关资源
    最近更新 更多