K均值聚类中各簇的高频词汇

4

我正在使用Python K-Means聚类算法对文档进行聚类。我已经创建了一个词项-文档矩阵。

   from sklearn.feature_extraction.text import TfidfVectorizer
   from sklearn.cluster import KMeans
   vectorizer = TfidfVectorizer(tokenizer=tokenize, encoding='latin-1',
                          stop_words='english')
    X = vectorizer.fit_transform(token_dict.values())

然后我使用以下代码应用了Kmean聚类

 km = KMeans(n_clusters=true_k, init='k-means++', max_iter=100, n_init=1)
 y=km.fit(X)

我的下一个任务是查看每个簇中的热门词汇,通过搜索Google发现许多人使用km.cluster_centers_.argsort()[:, ::-1]来查找以下代码中簇中的热门术语:

 print("Top terms per cluster:")
 order_centroids = km.cluster_centers_.argsort()[:, ::-1]
 terms = vectorizer.get_feature_names()
 for i in range(true_k):
     print("Cluster %d:" % i, end='')
     for ind in order_centroids[i, :10]:
         print(' %s' % terms[ind], end='')
         print()

现在我的问题是,据我理解,km.cluster_centers_ 返回聚类中心的坐标,因此例如如果有100个特征和三个聚类,它将为我们返回一个3行100列的矩阵,表示每个聚类的质心。我希望了解如何在上述代码中使用它来确定聚类中的前几个词语。 谢谢,期待您的回复。 Nadeem

我相信我可以查找,但是TfidfVectorizerKMeans库来自哪里?如果您将此问题针对该软件包的专家,您可能会获得更好的回答。具体而言,这些信息可以放在标签中,以及问题本身和正文中。 - Andrew Jaffe
我现在提到了我使用的库,它们是:从sklearn.feature_extraction.text中导入TfidfVectorizer 从sklearn.cluster中导入KMeans - Nhqazi
2个回答

6
您对于聚类中心的形状和含义的理解是正确的。因为您使用了Tf-Idf向量化程序,所以给定文档中的“特征”是单词(每个文档都是自己的向量)。因此,当您聚类文档向量时,质心的每个“特征”表示该单词与其相关性。“word”(在词汇表中)=“feature”(在您的向量空间中)=“column”(在您的质心矩阵中)。
get_feature_names调用获取列索引到表示它的单词的映射(从文档中获取),因此可以得到相同的结果。
然后,argsort()[:, ::-1]行将每个质心转换为按其最重要的列(高价值)排序的列表,因此是最相关的单词(因为单词=列)。
代码的其余部分仅仅是打印输出,我相信这不需要任何解释。所有代码实际上都是按照每个质心中最重要的特征/单词的降序排列,然后将这些列映射回原始单词并将其打印出来。

Scnerd,感谢您的解释,但我仍然有些困惑。我的担忧是,一个簇将有“n”个文档,每个文档由包含“M”个术语的特征向量表示。然而,一个簇的质心将有一个由“M”个特征组成的向量,那么在簇中的“n”个文档中存在的术语怎么办?上面代码中的前几个术语是通过反转质心提取出来的。当我们反转时,只会突出显示质心中存在的术语,而不是文档中的所有其他术语。 - Nhqazi
在K-means中,质心是簇中文档的平均值,在Tf-Idf中,所有值都是非负的,因此簇中每个文档中的每个单词都将在其质心中表示。因此,质心中显著的术语是在该簇中所有文档中最重要的术语。没有单词被遗漏,但很多变得不重要了。文档向量中最高的Tf-Idf值是对该文档最重要的单词;同样,质心中最高价值的单词是对整个簇最重要的单词。这有帮助吗? - scnerd
顺便说一下,如果你对基于文档中单词出现情况的聚类感兴趣,你考虑过研究LDA和主题建模吗? - scnerd
谢谢,那真的是一次很好的解释,澄清了我的困惑。是的,我对LDA建模很感兴趣,你有任何在Python上开始的链接吗? - Nhqazi
http://scikit-learn.org/stable/modules/generated/sklearn.decomposition.LatentDirichletAllocation.html 和 https://github.com/bmabey/pyLDAvis 用于可视化,也许可以考虑使用? - scnerd

1

我有点晚了解到这个问题,但我也有同样的疑问,却找不到令人满意的答案。

这是我所做的:

from sklearn.cluster import MiniBatchKMeans
from sklearn.feature_extraction.text import TfidfVectorizer

# documents you are clustering
docs = ['first document', 'second', 'third doc', 'etc.'] * 10

# init vectorizer
tfidf = TfidfVectorizer()

# fit vectorizer and get vecs
vecs = tfidf.fit_transform(docs)

# fit your kmeans cluster to vecs
# don't worry about the hyperparameters
clusters = MiniBatchKMeans(
    n_clusters=16, 
    init_size=1024, 
    batch_size=2048, 
    random_state=20
).fit_predict(vecs)

# get dict of {keyword id: keyword name}
labels = tfidf.get_feature_names()

def get_cluster_keywords(vecs, clusters, labels, top_n=10):
    # init a dict where we will count term occurence
    cluster_keyword_ids = {cluster_id: {} for cluster_id in set(clusters)}
    
    # loop through the vector and cluster of each doc
    for vec, cluster_id in zip(vecs, clusters):
        
        # inspect non zero elements of rows of sparse matrix
        for j in vec.nonzero()[1]:
            
            # check we have seen this keword in this cluster before
            if j not in cluster_keyword_ids[cluster_id]:
                cluster_keyword_ids[cluster_id][j] = 0
            
            # add a count
            cluster_keyword_ids[cluster_id][j] += 1

    # cluster_keyword_ids contains ids
    # we need to map back to keywords
    # do this with the labels param
    return {
        cluster_id: [
            labels[keyword_id] # map from kw id to keyword
            
            # sort through our keyword_id_counts
            # only return the top n per cluster
            for keyword_id, count in sorted(
                keyword_id_counts.items(),
                key=lambda x: x[1], # sort from highest count to lowest
                reverse=True
            )[:top_n]
        ] for cluster_id, keyword_id_counts in cluster_keyword_ids.items()
    }

然后您可以运行:
>>> get_cluster_keywords(vecs, clusters, labels, top_n=10)

{0: ['document', 'first'], 1: ['second'], 2: ['doc', 'third'], 3: ['etc']}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接