Termhäufigkeit / Inverse Document Frequency (TF / IDF): Gewichtung

12

Ich habe einen Datensatz, der 1000 Dokumente und alle darin enthaltenen Wörter darstellt. So repräsentieren die Zeilen die Dokumente und die Spalten die Wörter. So steht beispielsweise der Wert in Zelle für die Zeiten, in denen das Wort in Dokument . Jetzt muss ich mithilfe der tf / idf-Methode die "Gewichte" der Wörter finden, aber ich weiß eigentlich nicht, wie ich das machen soll. Kann mir bitte jemand weiterhelfen?(ich,j)jich

ABC
quelle
Die tf-idf-Statistik zur Keyword-Extraktion - joyofdata.de/blog/tf-idf-statistic-keyword-extraction
Raffael

Antworten:

12

Wikipedia hat einen guten Artikel zum Thema, komplett mit Formeln. Die Werte in Ihrer Matrix sind die Termhäufigkeiten. Sie müssen nur die IDF finden: (log((total documents)/(number of docs with the term))und die 2 Werte multiplizieren .

In R können Sie dies folgendermaßen tun:

set.seed(42)
d <- data.frame(w=sample(LETTERS, 50, replace=TRUE))
d <- model.matrix(~0+w, data=d)

tf <- d
idf <- log(nrow(d)/colSums(d))
tfidf <- d

for(word in names(idf)){
  tfidf[,word] <- tf[,word] * idf[word]
}

Hier sind die Datensätze:

> colSums(d)
wA wC wD wF wG wH wJ wK wL wM wN wO wP wQ wR wS wT wV wX wY wZ 
 3  1  3  1  1  1  1  2  4  2  2  1  1  3  2  2  2  4  5  5  4 
> head(d)
  wA wC wD wF wG wH wJ wK wL wM wN wO wP wQ wR wS wT wV wX wY wZ
1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1  0  0
2  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1  0
3  0  0  0  0  0  1  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
4  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1  0  0  0
5  0  0  0  0  0  0  0  0  0  0  0  0  0  1  0  0  0  0  0  0  0
6  0  0  0  0  0  0  0  0  0  0  1  0  0  0  0  0  0  0  0  0  0
> head(round(tfidf, 2))
  wA wC wD wF wG   wH wJ wK wL wM   wN wO wP   wQ wR wS wT   wV  wX  wY wZ
1  0  0  0  0  0 0.00  0  0  0  0 0.00  0  0 0.00  0  0  0 0.00 2.3 0.0  0
2  0  0  0  0  0 0.00  0  0  0  0 0.00  0  0 0.00  0  0  0 0.00 0.0 2.3  0
3  0  0  0  0  0 3.91  0  0  0  0 0.00  0  0 0.00  0  0  0 0.00 0.0 0.0  0
4  0  0  0  0  0 0.00  0  0  0  0 0.00  0  0 0.00  0  0  0 2.53 0.0 0.0  0
5  0  0  0  0  0 0.00  0  0  0  0 0.00  0  0 2.81  0  0  0 0.00 0.0 0.0  0
6  0  0  0  0  0 0.00  0  0  0  0 3.22  0  0 0.00  0  0  0 0.00 0.0 0.0  0

Sie können sich auch die IDs der einzelnen Begriffe ansehen:

> log(nrow(d)/colSums(d))
      wA       wC       wD       wF       wG       wH       wJ       wK       wL       wM       wN       wO       wP       wQ       wR       wS       wT       wV       wX       wY       wZ 
2.813411 3.912023 2.813411 3.912023 3.912023 3.912023 3.912023 3.218876 2.525729 3.218876 3.218876 3.912023 3.912023 2.813411 3.218876 3.218876 3.218876 2.525729 2.302585 2.302585 2.525729 
Zach
quelle
Danke für Ihre Hilfe! Aber ist es möglich, für jedes Wort einen Wert zu erhalten, der eine Gewichtung darstellt (anstelle einer ganzen Matrix)? Jetzt haben wir eine ganze Matrix von Gewichten. Ich mache eine Featureauswahl und möchte tf / idf als Filtermethode verwenden ...
ABC
@ABC tf-idf bezieht sich per definitionem auf die vollständige Gewichtsmatrix. Vielleicht interessieren Sie sich nur für die IDF-Gewichte, mit denen Sie zurechtkommen würden log((number of docs)/(number of docs containing the term)). Sie können auch nur die seltenen Begriffe herausfiltern.
Zach
Sehr deutlich! Sehr geschätzt.
ABC
13

Es gibt das Paket tm (Text Mining) http://cran.r-project.org/web/packages/tm/index.html, das genau das tun sollte, was Sie brauchen:

#read 1000 txt articles from directory data/txt
corpus  <-Corpus(DirSource("data/txt"), readerControl = list(blank.lines.skip=TRUE));
#some preprocessing
corpus <- tm_map(corpus, removeWords, stopwords("english"))
corpus <- tm_map(corpus, stripWhitespace)
corpus <- tm_map(corpus, stemDocument, language="english")
#creating term matrix with TF-IDF weighting
terms <-DocumentTermMatrix(corpus,control = list(weighting = function(x) weightTfIdf(x, normalize = FALSE)))

#or compute cosine distance among documents
dissimilarity(tdm, method = "cosine")

R ist eine funktionale Sprache, daher kann das Lesen von Code schwierig sein (z. B. x in Begriffen).

xhudik
quelle
2

Ihr Code hat einen Fehler: colSums berechnet die Anzahl der Vorkommen im Korpus, nicht die Anzahl der Texte mit dem Wort.

Eine solche Version wäre:

tfidf=function(mat){
  tf <- mat
  id=function(col){sum(!col==0)}
  idf <- log(nrow(mat)/apply(mat, 2, id))
  tfidf <- mat
  for(word in names(idf)){tfidf[,word] <- tf[,word] * idf[word]}
  return(tfidf)
  }
user46661
quelle
1

Dazu gibt es ein neues R-Paket: textir: Inverse Regression für die Textanalyse

Der relevante Befehl ist tfidfdas Beispiel aus dem Handbuch:

data(we8there)
## 20 high-variance tf-idf terms
colnames(we8thereCounts)[
order(-sdev(tfidf(we8thereCounts)))[1:20]]
vonjd
quelle
1

Ich komme zu spät zu dieser Party, aber ich habe mit den Konzepten von tc-idf gespielt (ich möchte das Wort 'concept' hervorheben, weil ich für die eigentlichen Berechnungen keinen Büchern gefolgt bin; sie sind also möglicherweise etwas abweichend und definitiv einfacher durchgeführt mit Paketen wie {tm: Text Mining Package}, wie erwähnt), und ich denke, was ich bekommen habe, könnte mit dieser Frage zusammenhängen, oder auf jeden Fall könnte dies ein guter Ort sein, um sie zu posten.


SET-UP: Ich habe einen Korpus von 5langen Absätzen von gedruckten Medien entnommen, text 1durch 5wie die New York Times . Angeblich ist es ein sehr kleiner "Körper", sozusagen eine winzige Bibliothek, aber die Einträge in dieser "digitalen" Bibliothek sind nicht zufällig: Die ersten und fünften Einträge befassen sich mit Fußball (oder "Fußball" für "Social Club"). (?) hier) und genauer gesagt über das größte Team von heute. So text 1beginnt zum Beispiel als ...

"In den letzten neun Jahren hat Messi den FC Barcelona zu nationalen und internationalen Titeln geführt und dabei einzelne Rekorde auf eine Weise gebrochen, die jenseits der Welt zu liegen scheint ..."

Sehr schön! Auf der anderen Seite möchten Sie auf jeden Fall den Inhalt der drei dazwischen liegenden Einträge überspringen. Hier ist ein Beispiel ( text 2):

"Innerhalb weniger Stunden in ganz Texas schlug Herr Rubio vor, dass Herr Trump in seine Hosen gepinkelt und illegale Einwanderer eingesetzt habe, um seine unaufhörlichen Twitter-Nachrichten abzuhören ..."

Was also zu tun , um jeden Preis „Surfen“ aus der zu vermeiden , text 1zu text 2, während sie weiterhin in der Literatur über allmächtiges Barcelona FC freuen in text 5?


TC-IDF: Ich habe die Wörter in jedem textin lange Vektoren unterteilt. Zählte dann die Häufigkeit jedes Wortes und erzeugte fünf Vektoren (einen für jedes text), in denen nur die Wörter textgezählt wurden, die in dem entsprechenden angetroffen wurden - alle anderen Wörter, die zu anderen texts gehörten, wurden mit Null bewertet. Im ersten Snippet von text 1zum Beispiel hätte sein Vektor eine Zählung von 1 für das Wort "Messi", während "Trump" 0 hätte. Dies war der tc- Teil.

Der IDF- Teil wurde auch für jeden einzeln berechnet textund ergab 5 "Vektoren" (ich glaube, ich habe sie als Datenrahmen behandelt), die die logarithmischen Transformationen der Anzahl der Dokumente enthielten (leider nur von null auf fünf, angesichts unserer kleinen Bibliothek) ) mit einem bestimmten Wort wie in:

Log(Nr. Dokumente1+Nr. Dokumente, die ein Wort enthalten). Die Anzahl der Dokumente ist 5. Hier kommt der Teil, der das OP beantworten kann: Für jede IDF-Berechnung wurde der betreffendetext Teil von der Zählung ausgeschlossen . Aber wenn ein Wort in allen Dokumenten auftauchte, war sein Idf still0 Danke an die 1im Nenner - zB das Wort "the" hatte die Bedeutung 0, weil es in allen texts vorhanden war.

Die eintrittsweise Multiplikation von tc×idffür jeden textwar die Wichtigkeit jedes Wortes für jeden der Bibliothekselemente - lokal vorherrschende, weltweit seltene Wörter .


VERGLEICHE: Jetzt ging es nur noch darum, zwischen diesen "Vektoren von Wortbedeutung" Punktprodukte zu erzeugen .

Wie vorauszusehen war , das Skalarprodukt text 1mit text 5war 13.42645, während text 1v. text2Nur war 2.511799.

Der klobige R-Code (nichts zu imitieren) ist hier .

Auch dies ist eine sehr rudimentäre Simulation, aber ich denke, es ist sehr anschaulich.

Antoni Parellada
quelle