Frequenza termine / frequenza inversa del documento (TF / IDF): ponderazione


12

Ho un set di dati che rappresenta 1000 documenti e tutte le parole che appaiono in esso. Quindi le righe rappresentano i documenti e le colonne rappresentano le parole. Ad esempio, il valore nella cella sta per i tempi in cui la parola presenta nel documento . Ora, devo trovare "pesi" delle parole, usando il metodo tf / idf, ma in realtà non so come farlo. Qualcuno può aiutarmi per favore?(io,j)jio


La statistica tf-idf per l'estrazione di parole chiave - joyofdata.de/blog/tf-idf-statistic-keyword-extraction
Raffael

Risposte:


12

Wikipedia ha un buon articolo sull'argomento, completo di formule. I valori nella tua matrice sono i termini frequenze. Devi solo trovare l'idf: (log((total documents)/(number of docs with the term))e moltiplicare i 2 valori.

In R, potresti farlo nel modo seguente:

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]
}

Ecco i set di dati:

> 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

Puoi anche guardare l'ID di ogni termine:

> 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 

Grazie per l'aiuto! Ma è possibile ottenere un valore per ogni parola che rappresenta un certo peso (anziché un'intera matrice)? Ora abbiamo un'intera matrice di pesi. Sto facendo alcune selezioni di funzionalità e voglio usare tf / idf come metodo di filtro ...
ABC

@ABC tf-idf per definizione si riferisce alla matrice completa dei pesi. Forse ti interessano solo i pesi dell'idf, che faresti passare log((number of docs)/(number of docs containing the term)). Potresti anche semplicemente filtrare i termini poco frequenti.
Zach,

Molto chiaro! Molto apprezzato.
ABC

13

c'è il pacchetto tm (text mining) http://cran.r-project.org/web/packages/tm/index.html che dovrebbe fare esattamente ciò di cui hai bisogno:

#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 è un linguaggio funzionale, quindi leggere il codice può essere complicato (ad es. X in termini)


2

Il tuo codice ha un errore: colSums calcola il numero di occorrenze nel corpus, non il numero di testi con la parola.

Una versione informatica tale sarebbe:

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)
  }


1

Sono in ritardo a questa festa, ma stavo giocando con i concetti di tc-idf (voglio enfatizzare la parola "concetto" perché non ho seguito alcun libro per i calcoli reali; quindi potrebbero essere un po 'fuori, e sicuramente più facilmente realizzato con pacchetti come {tm: Text Mining Package}, come detto), e penso che ciò che ho ottenuto possa essere correlato a questa domanda, o, in ogni caso, questo potrebbe essere un buon posto per pubblicarlo.


SET-UP: Ho un corpus di 5lunghi paragrafi tratti da carta stampata, text 1attraverso la 5quale il New York Times . Presumibilmente, è un "corpo" molto piccolo, una minuscola biblioteca, per così dire, ma le voci in questa biblioteca "digitale" non sono casuali: la prima e la quinta voce riguardano il calcio (o il "calcio" per "club sociale" (?) qui intorno), e più specificamente sulla squadra più grande di oggi. Quindi, per esempio, text 1inizia come ...

"Negli ultimi nove anni, Messi ha portato l'FC Barcelona a titoli nazionali e internazionali, battendo i record individuali in modi che sembrano ultraterreni ..."

Molto bella! D'altra parte vorresti sicuramente saltare il contenuto delle tre voci in mezzo. Ecco un esempio ( text 2):

"Nel giro di poche ore in tutto il Texas, il signor Rubio ha suggerito che il signor Trump aveva urinato nei suoi pantaloni e usato immigrati clandestini per dare voce ai suoi incessanti messaggi su Twitter ..."

Quindi cosa fare per evitare a tutti i costi di "navigare" dal text 1a text 2, continuando a rallegrarsi della letteratura sull'onnipotente Barcellona FC text 5?


TC-IDF: ho isolato le parole in ognuna textin lunghi vettori. Quindi ha contato la frequenza di ogni parola, creando cinque vettori (uno per ciascuno text) in cui textsono state contate solo le parole incontrate nel corrispondente - tutte le altre parole, appartenenti ad altre texts, sono state valutate a zero. Nel primo frammento di text 1, ad esempio, il suo vettore avrebbe un conteggio di 1 per la parola "Messi", mentre "Trump" avrebbe avuto 0. Questa era la parte tc .

Anche la parte idf è stata calcolata separatamente per ciascuna texte ha prodotto 5 "vettori" (penso di averli trattati come frame di dati), contenenti le trasformazioni logaritmiche dei conteggi dei documenti (purtroppo, da zero a cinque, data la nostra piccola libreria ) contenente una determinata parola come in:

log(No. documenti1+No. documenti contenenti una parola)text01text

tc×IDFtext


CONFRONTI: Ora si trattava solo di eseguire prodotti a punti tra questi "vettori di importanza verbale".

Com'era prevedibile, il prodotto punto di text 1con text 5era 13.42645, mentre text 1v. text2Era solo 2.511799.

Il grosso codice R (niente da imitare) è qui .

Ancora una volta, questa è una simulazione molto rudimentale, ma penso che sia molto grafica.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.