Python中的聚类文本[关闭]

Posted

技术标签:

【中文标题】Python中的聚类文本[关闭]【英文标题】:Clustering text in Python [closed] 【发布时间】:2010-12-19 20:13:23 【问题描述】:

我需要对一些文本文档进行聚类,并且一直在研究各种选项。看起来 LingPipe 可以在没有事先转换(到向量空间等)的情况下对纯文本进行聚类,但它是我见过的唯一明确声称可以处理字符串的工具。

有没有可以直接聚类文本的 Python 工具?如果没有,最好的处理方法是什么?

【问题讨论】:

关于什么是“文本聚类”的信息:www2.parc.com/istl/projects/ia/sg-clustering.html 如果您在从各种文档类型中提取文本内容方面需要帮助,请添加另一个问题,因为我认为这是任务的另一部分。恕我直言,它可以更好地分离问题。 Mallet 也可以处理文本文件,而无需你做任何事情,假设你有一个完整的目录(每个文件一个文档)。我建议只使用 nltk,一个 python 库。您需要对文件进行一些预处理,但这并不痛苦。 【参考方案1】:

文本聚类的质量主要取决于两个因素:

    要聚类的文档之间的一些相似性概念。例如,通过 tfidf-cosine-distance 很容易区分向量空间中有关体育和政治的新闻文章。根据此衡量标准将产品评论归类为“好”或“坏”要困难得多。

    聚类方法本身。你知道会有多少个集群吗?好的,使用kmeans。您不关心准确性,但想显示一个漂亮的树结构来导航搜索结果?使用某种层次聚类。

没有在任何情况下都能正常工作的文本聚类解决方案。因此,开箱即用一些集群软件并将数据扔给它可能是不够的。

话虽如此,这是我前段时间用来玩文本聚类的一些实验性代码。文档被表示为标准化的 tfidf 向量,相似度被测量为余弦距离。聚类方法本身是majorclust。

import sys
from math import log, sqrt
from itertools import combinations

def cosine_distance(a, b):
    cos = 0.0
    a_tfidf = a["tfidf"]
    for token, tfidf in b["tfidf"].iteritems():
        if token in a_tfidf:
            cos += tfidf * a_tfidf[token]
    return cos

def normalize(features):
    norm = 1.0 / sqrt(sum(i**2 for i in features.itervalues()))
    for k, v in features.iteritems():
        features[k] = v * norm
    return features

def add_tfidf_to(documents):
    tokens = 
    for id, doc in enumerate(documents):
        tf = 
        doc["tfidf"] = 
        doc_tokens = doc.get("tokens", [])
        for token in doc_tokens:
            tf[token] = tf.get(token, 0) + 1
        num_tokens = len(doc_tokens)
        if num_tokens > 0:
            for token, freq in tf.iteritems():
                tokens.setdefault(token, []).append((id, float(freq) / num_tokens))

    doc_count = float(len(documents))
    for token, docs in tokens.iteritems():
        idf = log(doc_count / len(docs))
        for id, tf in docs:
            tfidf = tf * idf
            if tfidf > 0:
                documents[id]["tfidf"][token] = tfidf

    for doc in documents:
        doc["tfidf"] = normalize(doc["tfidf"])

def choose_cluster(node, cluster_lookup, edges):
    new = cluster_lookup[node]
    if node in edges:
        seen, num_seen = , 
        for target, weight in edges.get(node, []):
            seen[cluster_lookup[target]] = seen.get(
                cluster_lookup[target], 0.0) + weight
        for k, v in seen.iteritems():
            num_seen.setdefault(v, []).append(k)
        new = num_seen[max(num_seen)][0]
    return new

def majorclust(graph):
    cluster_lookup = dict((node, i) for i, node in enumerate(graph.nodes))

    count = 0
    movements = set()
    finished = False
    while not finished:
        finished = True
        for node in graph.nodes:
            new = choose_cluster(node, cluster_lookup, graph.edges)
            move = (node, cluster_lookup[node], new)
            if new != cluster_lookup[node] and move not in movements:
                movements.add(move)
                cluster_lookup[node] = new
                finished = False

    clusters = 
    for k, v in cluster_lookup.iteritems():
        clusters.setdefault(v, []).append(k)

    return clusters.values()

def get_distance_graph(documents):
    class Graph(object):
        def __init__(self):
            self.edges = 

        def add_edge(self, n1, n2, w):
            self.edges.setdefault(n1, []).append((n2, w))
            self.edges.setdefault(n2, []).append((n1, w))

    graph = Graph()
    doc_ids = range(len(documents))
    graph.nodes = set(doc_ids)
    for a, b in combinations(doc_ids, 2):
        graph.add_edge(a, b, cosine_distance(documents[a], documents[b]))
    return graph

def get_documents():
    texts = [
        "foo blub baz",
        "foo bar baz",
        "asdf bsdf csdf",
        "foo bab blub",
        "csdf hddf kjtz",
        "123 456 890",
        "321 890 456 foo",
        "123 890 uiop",
    ]
    return ["text": text, "tokens": text.split()
             for i, text in enumerate(texts)]

def main(args):
    documents = get_documents()
    add_tfidf_to(documents)
    dist_graph = get_distance_graph(documents)

    for cluster in majorclust(dist_graph):
        print "========="
        for doc_id in cluster:
            print documents[doc_id]["text"]

if __name__ == '__main__':
    main(sys.argv)

对于实际应用,你会使用一个像样的标记器,使用整数而不是标记字符串,并且不要计算 O(n^2) 距离矩阵...

【讨论】:

【参考方案2】:

似乎可以通过使用简单的 UNIX 命令行工具将这些文档的文本内容提取到文本文件中,然后使用纯 Python 解决方案进行实际集群。

我发现了一个代码 sn-p 用于一般聚类数据:

http://www.daniweb.com/code/snippet216641.html

为此的 Python 包:

http://python-cluster.sourceforge.net/

另一个python包(主要用于生物信息学):

http://bonsai.ims.u-tokyo.ac.jp/~mdehoon/software/cluster/software.htm#pycluster

【讨论】:

【参考方案3】:

有Python库NLTK支持语言分析,包括文本聚类

【讨论】:

以上是关于Python中的聚类文本[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

Python中的聚类——图像聚类

Python中的聚类

Pyspark Dataframes:创建要在 python 中的聚类中使用的特征列

数据分析系列 之python语言中的聚类分析

谁能告诉我SPSS中的K聚类分析怎么人为指定初始的聚类中心呢?内有截图,求大神告诉我怎么设置。

使用 scikit 选择层次凝聚聚类中的聚类数