簡體   English   中英

如何對字符串進行 KMeans 聚類

[英]How to KMeans Cluster strings

我是數據工程師,對 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

例如,在這個數據集中,我期望的自然分組是 lion/leopard 和 racoon/possum,因為teeth, tail and carnivore等詞的相似性

我已經完成的一種方法是比較一個條目,例如 lion,遍歷每個列表並將其與其他值進行比較,如果在另一個列表中找到一個值,則為其分配一個相似性分數。 然而,我很想使用像 k-means 聚類算法這樣的東西來學習如何主要使用它,而且我認為/希望它會提供更有意義的聚類系列。

我認為我被掛斷的地方是將文本轉換為數字表示以及如何最好地做到這一點,在那之后我覺得我可能會遵循一些 KMeans 教程,但如果有人對如何做有任何建議解決這個問題我會很感興趣。

有多種方法可以解決此問題。 但總的來說,這里有一些簡單的選擇 -

  1. 向量表示——使用one-hot編碼或者TF-IDF來表示句子
  2. 特征提取(可選) ——在大型復雜句子的情況下,您可能希望使用主題 model 來提取主題級特征。
  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 的多標簽二值化器使用單熱編碼句子

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

如您所見,代表“食肉動物”動物主題的詞是第二個主題的一部分,而代表“雜食動物”動物的詞代表第一個主題。 根據您的數據和內容的復雜性模式,您的數據包含的潛在主題數量,最好使用網格搜索為您的 model 找到最佳主題數量。或者,您可以像我一樣做出假設。

4.聚類

最后,讓我們使用k-means 聚類根據特征的相似性對句子進行分桶。

首先,讓我們在不使用 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,反之亦然。

更新,最接近我想要的東西本質上是這個 jupyter notebook。 https://nbviewer.jupyter.org/github/LucasTurtle/national-anthems-clustering/blob/master/Cluster_Anthems.ipynb

本質上是使用 sklearn 的 tfdif 功能對列表進行矢量化,然后在該數組上運行 kmeans。

我還研究了 spaCy 庫和 gensim 主題建模

我用第一種方法得到了結果,我認為這是有道理的。 但是,我更願意了解更多我在做什么。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM