2009-11-24 48 views
22

Necesito agrupar algunos documentos de texto y he estado investigando varias opciones. Parece que LingPipe puede agrupar texto plano sin conversión previa (a espacio vectorial, etc.), pero es la única herramienta que he visto que afirma explícitamente que funciona en cadenas.Agrupación de texto en Python

¿Hay alguna herramienta de Python que pueda agrupar texto directamente? Si no, ¿cuál es la mejor manera de manejar esto?

+1

Información sobre qué "agrupación de texto" es: http://www2.parc.com/istl/projects/ia/sg-clustering.html – fviktor

+0

Si necesita ayuda en la extracción de los contenidos de texto de varios tipos de documentos, luego agregue otra pregunta, ya que esa es otra parte de la tarea, creo. Permitiría una mejor separación de los problemas en mi humilde opinión. – fviktor

+0

Mallet también funcionará en archivos de texto sin tener que hacer nada, suponiendo que tiene un directorio lleno de ellos (con un documento por archivo). Recomiendo solo usar nltk, una biblioteca de python.Tendrá que hacer un pequeño preprocesamiento en los archivos, pero no es doloroso. – ealdent

Respuesta

44

La calidad del texto agrupación depende principalmente de dos factores:

  1. alguna noción de similitud entre los documentos que desea agrupar. Por ejemplo, es fácil distinguir entre nuevos artículos sobre deportes y política en el espacio vectorial a través de tfidf-cosine-distance. Es mucho más difícil agrupar los comentarios de los productos en "buenos" o "malos" según esta medida.

  2. El método de agrupación en sí. ¿Sabes cuántos clústers habrá? Ok, usa kmeans. ¿No le importa la precisión, pero quiere mostrar una buena estructura de árbol para la navegación de los resultados de búsqueda? Use algún tipo de agrupamiento jerárquico.

No existe una solución de agrupamiento de texto que funcione bien bajo ninguna circunstancia. Y, por lo tanto, probablemente no sea suficiente tomar algún software de agrupación de la caja y arrojar sus datos sobre él.

Dicho esto, he aquí un código experimental que utilicé hace algún tiempo para jugar con el agrupamiento de texto. Los documentos se representan como vectores tfidf normalizados y la similitud se mide como la distancia del coseno. El método de agrupamiento en sí es 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) 

Para aplicaciones reales, se utilizaría un tokenizer decente, el uso de números enteros en lugar de token-cuerdas y no Calc un O (n^2) distancia de matriz ...

2

Parece que es posible usar herramientas simples de línea de comandos de UNIX para extraer los contenidos de texto de esos documentos en archivos de texto, y luego usar una solución pura de Python para la agrupación real.

I conocer un fragmento de código para los datos de agrupación en general:

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

paquete A Python para esto:

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

Otro paquete pitón (usado principalmente para la bioinformática):

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

0

No es Python NLTK biblioteca que soporta el análisis lingüístico incluyendo texto agrupación

Cuestiones relacionadas