2014-07-03 2 views
7

Ich habe eine CSV-Datei mit folgendem Format:Wie kann ich eine TF-IDF für die Textklassifikation mit Spark erstellen?

product_id1,product_title1 
product_id2,product_title2 
product_id3,product_title3 
product_id4,product_title4 
product_id5,product_title5 
[...] 

Die product_idX ist eine ganze Zahl und die product_titleX ist ein String, Beispiel:

453478692, Apple iPhone 4 8Go 

Ich versuche, den TF-IDF zu erstellen aus meiner Datei, damit ich sie für einen Naive Bayes Classifier in MLlib verwenden kann.

Ich benutze bisher Spark für Scala und benutze die Tutorials, die ich auf der offiziellen Seite und dem Berkley AmpCamp 3 und 4 gefunden habe.

So lese ich die Datei:

val file = sc.textFile("offers.csv") 

Dann Mapping ich es in Tupeln RDD[Array[String]]

val tuples = file.map(line => line.split(",")).cache 

und nachdem ich die Umwandlung der Tupel in Paare RDD[(Int, String)]

val pairs = tuples.(line => (line(0),line(1))) 

Aber ich stecke hier fest und ich weiß nicht, wie man den Vector her schafft m es, um es in TFIDF umzuwandeln.

Dank

+0

Wenn ich Ihr Problem gut verstehe, kann jedes Produkt mehrere Male vorhanden sein. Diese Anzahl von jedem Produkt ist Ihre Häufigkeit (TF), ich verstehe nicht, was die IDF in Ihrem Fall wäre. Können Sie das bitte näher ausführen? – fxm

+0

tf-idf, kurz für Begriff Häufigkeit-inverse Dokumenthäufigkeit, ist eine numerische Statistik, die widerspiegeln soll, wie wichtig ein Wort für ein Dokument in einer Sammlung oder einem Korpus ist. Es wird oft als Gewichtungsfaktor beim Information Retrieval und Text Mining verwendet. – eliasah

+0

Was ich nicht verstehe ist, dass ich in Ihrem Beispiel keine Erwähnung von * Sammlung oder Korpus * sehe. – fxm

Antwort

7

diesen selbst (mit pyspark) zu tun, ich durch die Schaffung von zwei Datenstrukturen aus dem Korpus zum ersten Mal gestartet. Der erste ist ein Schlüssel, Wert Struktur

document_id, [token_ids] 

Die zweite ist ein invertierter Index wie

token_id, [document_ids] 

I bzw. jene corpus und inv_index nennen werden.

Um tf zu erhalten, müssen wir die Anzahl der Vorkommen jedes Tokens in jedem Dokument zählen. Also

from collections import Counter 
def wc_per_row(row): 
    cnt = Counter() 
    for word in row: 
     cnt[word] += 1 
    return cnt.items() 

tf = corpus.map(lambda (x, y): (x, wc_per_row(y))) 

Die df ist einfach die Länge der invertierten Index jeder Begriff. Daraus können wir das IDF berechnen.

df = inv_index.map(lambda (x, y): (x, len(y))) 
num_documnents = tf.count() 

# At this step you can also apply some filters to make sure to keep 
# only terms within a 'good' range of df. 
import math.log10 
idf = df.map(lambda (k, v): (k, 1. + log10(num_documents/v))).collect() 

Jetzt müssen wir nur auf der term_id beitreten tun:

def calc_tfidf(tf_tuples, idf_tuples): 
    return [(k1, v1 * v2) for (k1, v1) in tf_tuples for 
     (k2, v2) in idf_tuples if k1 == k2] 

tfidf = tf.map(lambda (k, v): (k, calc_tfidf(v, idf))) 

Dies ist keine besonders performante Lösung, though. Calling Collect, um IDF in das Treiberprogramm zu bringen, so dass es für den Join verfügbar ist, scheint die falsche Sache zu sein.

Und natürlich erfordert es zuerst Tokenizing und Erstellen einer Zuordnung von jedem uniq Token im Vokabular zu einigen Token_id.

Wenn jemand das verbessern kann, bin ich sehr interessiert.

Verwandte Themen