【问题标题】:How to KMeans Cluster strings如何对字符串进行 KMeans 聚类
【发布时间】:2021-10-30 12:46:21
【问题描述】:

我是一名数据工程师,对 ML 方法的理解有限,我正在尝试在开始编码之前获得一个我理解的好策略。我想做的是用键值对创建集群,键是名称,值是某种字符串列表。

目标是根据各个字符串列表的相似性创建名称的自然集群。

import pandas as pd
df = pd.DataFrame({"name":['lion','leopard','racoon','possum'], 
"features":[
    ['mane', 'teeth', 'tail', 'carnivore'], 
    ['spots', 'teeth', 'tail', 'carnivore'], 
    ['stripes', 'teeth', 'omnivore', 'small'], 
    ['teeth', 'omnivore', 'small']]})
df

例如,在这个数据集中,我期望的自然分组会像狮子/豹和浣熊/负鼠,因为 teeth, tail and carnivore 两个词的相似性

我已经做过的一种方法是比较一个条目,例如Lion,遍历每个列表并将其与其他值进行比较,如果在另一个列表中找到一个值,则为其分配相似度分数。但是我很想使用类似 k-means 聚类算法的东西来学习如何主要使用它,而且我认为/希望它会提供更有意义的聚类系列。

我认为我被挂断的地方是将文本转换为数字表示以及如何最好地做到这一点,之后我觉得我可能会遵循一些 KMeans 教程,但如果有人有任何建议我对如何解决这个问题很感兴趣。

【问题讨论】:

  • 我添加了一些示例代码,说明您将如何解决这个问题。请检查一下,如果您有任何问题,请告诉我。

标签: machine-learning k-means


【解决方案1】:

更新,最接近我想要的东西本质上就是这个 jupyter notebook。 https://nbviewer.jupyter.org/github/LucasTurtle/national-anthems-clustering/blob/master/Cluster_Anthems.ipynb

基本上使用 sklearn 中的 tfdif 功能对列表进行矢量化,然后在该数组上运行 kmeans。

我还研究了 spaCy 库和 gensim 主题建模

我用第一种方法得到了结果,我认为这是有道理的。不过我更愿意了解我在做什么。

【讨论】:

    【解决方案2】:

    有很多方法可以解决这个问题。但总的来说,这里有一些简单的替代方案 -

    1. 向量表示 - 使用 one-hot 编码或 TF-IDF 来表示句子
    2. 特征提取(可选) - 对于大型复杂句子,您可能希望使用主题模型来提取主题级特征。
    3. 聚类 - 可以使用任何聚类方法,例如 K-means

    这是一个示例代码。

    1。导入和数据

    from sklearn.preprocessing import MultiLabelBinarizer
    from sklearn.feature_extraction.text import TfidfVectorizer
    from sklearn.decomposition import LatentDirichletAllocation
    from sklearn.cluster import KMeans
    import pandas as pd
    
    df = pd.DataFrame({"name":['lion','leopard','racoon','possum'], 
    "features":[
        ['mane', 'teeth', 'tail', 'carnivore'], 
        ['spots', 'teeth', 'tail', 'carnivore'], 
        ['stripes', 'teeth', 'omnivore', 'small'], 
        ['teeth', 'omnivore', 'small']]})
    
    print(df)
    
          name                           features
    0     lion     [mane, teeth, tail, carnivore]
    1  leopard    [spots, teeth, tail, carnivore]
    2   racoon  [stripes, teeth, omnivore, small]
    3   possum           [teeth, omnivore, small]
    

    2。向量表示

    您可以使用来自 sklearn 的 multi-label binarizer 使用 one-hot 编码句子

    mlb = MultiLabelBinarizer()
    vec = mlb.fit_transform(df['features'])
    vectors = pd.DataFrame(vec, columns=mlb.classes_)
    vectors
    
       carnivore  mane  omnivore  small  spots  stripes  tail  teeth
    0          1     1         0      0      0        0     1      1
    1          1     0         0      0      1        0     1      1
    2          0     0         1      1      0        1     0      1
    3          0     0         1      1      0        0     0      1
    

    或者您可以使用来自 sklearn 的 tf-idf vectorizer

    tfidf = TfidfVectorizer()
    vec = tfidf.fit_transform(df['features'].apply(' '.join).to_list())
    vectors = pd.DataFrame(vec.todense(), columns=tfidf.get_feature_names())
    print(vectors)
    
       carnivore      mane  omnivore     small     spots   stripes      tail  \
    0   0.497096  0.630504  0.000000  0.000000  0.000000  0.000000  0.497096   
    1   0.497096  0.000000  0.000000  0.000000  0.630504  0.000000  0.497096   
    2   0.000000  0.000000  0.497096  0.497096  0.000000  0.630504  0.000000   
    3   0.000000  0.000000  0.640434  0.640434  0.000000  0.000000  0.000000   
    
          teeth  
    0  0.329023  
    1  0.329023  
    2  0.329023  
    3  0.423897  
    

    3。特征提取(可选)

    接下来,我们可以选择使用来自 sklearn 的LDA 来创建主题作为下一步聚类的特征。请注意,您可以在此处使用其他降维或分解方法,但 LDA 专门用于主题建模并且具有高度可解释性(如下所示),因此我正在使用它。

    假设数据有 2 个主题。

    #Using LDA to create topic level features
    
    lda = LatentDirichletAllocation(n_components=2, verbose=0)
    lda_features = lda.fit_transform(vec)
    lda_features
    
    array([[0.19035075, 0.80964925],
           [0.19035062, 0.80964938],
           [0.81496776, 0.18503224],
           [0.79598858, 0.20401142]])
    

    要了解 LDA 如何决定主题,检查主题词矩阵以了解主题的构成很有用。

    #Topic-word matrix
    
    pd.DataFrame(lda.components_, 
                 index=['topic1', 'topic2'], 
                 columns=tfidf.get_feature_names()).round(1)
    
            carnivore  mane  omnivore  small  spots  stripes  tail  teeth
    topic1        0.5   0.5       1.6    1.6    0.5      1.1   0.5    1.3
    topic2        1.5   1.1       0.5    0.5    1.1      0.5   1.5    1.1
    

    如您所见,代表“食肉”动物主题的词属于第二个主题,而代表“杂食”动物的词代表第一个主题。根据您的数据和内容中的复杂性模式,您的数据包含的潜​​在主题数量最好使用grid search 为您的模型找到最佳主题数量。或者,您可以像我一样做出假设。

    4。聚类

    最后,让我们使用k-means clustering按特征相似度对句子进行分桶。

    首先,让我们在不使用 LDA 的情况下进行集群。

    #Using k-means directly on the one-hot vectors OR Tfidf Vectors
    
    kmeans = KMeans(n_clusters=2)
    kmeans.fit(vec)
    df['pred'] = kmeans.predict(vec)
    print(df)
    
          name                           features  pred
    0     lion     [mane, teeth, tail, carnivore]     0
    1  leopard    [spots, teeth, tail, carnivore]     0
    2   racoon  [stripes, teeth, omnivore, small]     1
    3   possum           [teeth, omnivore, small]     1
    

    接下来,我们做同样的事情,但这次使用的是 LDA 功能。

    # clustering the topic level features
    
    kmeans = KMeans(n_clusters=2)
    kmeans.fit(lda_features)
    df['pred'] = kmeans.predict(lda_features)
    
          name                           features  pred
    0     lion     [mane, teeth, tail, carnivore]     0
    1  leopard    [spots, teeth, tail, carnivore]     0
    2   racoon  [stripes, teeth, omnivore, small]     1
    3   possum           [teeth, omnivore, small]     1
    

    注意:使用任何集群时,标签往往会在每次重新运行时发生变化,但除非数据/参数发生变化,否则不要干扰集群。这意味着,有时您可能会看到集群 0 被标记为集群 1,反之亦然。

    【讨论】:

      猜你喜欢
      • 2017-09-02
      • 1970-01-01
      • 2021-11-27
      • 2015-02-05
      • 2019-11-27
      • 2017-10-05
      • 2019-01-07
      • 1970-01-01
      • 2019-01-06
      相关资源
      最近更新 更多