Termin częstotliwość / odwrotna częstotliwość dokumentów (TF / IDF): ważenie

12

Mam zestaw danych, który reprezentuje 1000 dokumentów i wszystkie słowa, które się w nim pojawiają. Tak więc wiersze reprezentują dokumenty, a kolumny - słowa. Na przykład wartość w komórce oznacza czas, w którym słowo występuje w dokumencie . Teraz muszę znaleźć „wagi” słów, używając metody tf / idf, ale tak naprawdę nie wiem, jak to zrobić. Czy ktoś mógłby mi pomóc?j i(ja,jot)jotja

ABC
źródło
Statystyka tf-idf do wyodrębniania słów kluczowych - joyofdata.de/blog/tf-idf-statistic-keyword-extraction
Raffael

Odpowiedzi:

12

Wikipedia ma dobry artykuł na ten temat, wraz z formułami. Wartości w macierzy są częstotliwościami. Musisz tylko znaleźć idf: (log((total documents)/(number of docs with the term))i pomnożyć 2 wartości.

W R możesz to zrobić w następujący sposób:

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

Oto zestawy danych:

> 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

Możesz także spojrzeć na idf każdego terminu:

> 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
źródło
Dzięki za pomoc! Ale czy można uzyskać jakąś wartość dla każdego słowa, która reprezentuje pewną wagę (zamiast całej macierzy)? Teraz mamy całą macierz wag. Dokonuję wyboru funkcji i chcę użyć tf / idf jako metody filtrowania ...
ABC
@ABC tf-idf z definicji odnosi się do pełnej macierzy wag. Być może interesują Cię same wagi idf, które byś uzyskał log((number of docs)/(number of docs containing the term)). Możesz także odfiltrować rzadkie warunki.
Zach.
Bardzo czyste! Naprawdę doceniony.
ABC,
13

jest pakiet tm (eksploracja tekstu) http://cran.r-project.org/web/packages/tm/index.html, który powinien zrobić dokładnie to, czego potrzebujesz:

#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 jest językiem funkcjonalnym, więc czytanie kodu może być trudne (np. X pod względem)

Xhudik
źródło
2

W kodzie występuje błąd: colSums oblicza liczbę wystąpień w korpusie, a nie liczbę tekstów ze słowem.

Wersja obliczeniowa taka to:

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)
  }
użytkownik46661
źródło
1

Istnieje nowy pakiet R, który może to zrobić: textir: Regresja odwrotna do analizy tekstu

Odpowiednim poleceniem jest tfidfprzykład z instrukcji:

data(we8there)
## 20 high-variance tf-idf terms
colnames(we8thereCounts)[
order(-sdev(tfidf(we8thereCounts)))[1:20]]
vonjd
źródło
1

Jestem spóźniony na tę imprezę, ale bawiłem się koncepcjami tc-idf (chcę podkreślić słowo „koncepcja”, ponieważ nie śledziłem żadnych książek do faktycznych obliczeń; więc mogą być nieco nie na pewno i zdecydowanie łatwiejsze do przeprowadzenia z pakietami {tm: Text Mining Package}, jak wspomniano), i myślę, że to, co otrzymałem, może być związane z tym pytaniem lub, w każdym razie, może to być dobre miejsce do opublikowania go.


SET-UP: Mam korpus z 5długimi paragrafach zaczerpniętych z mediów drukowanych, text 1przez 5takich jak The New York Times . Podobno jest to bardzo małe „ciało”, że tak powiem, mała biblioteka, ale wpisy w tej „cyfrowej” bibliotece nie są przypadkowe: Pierwsze i piąte wpisy dotyczą piłki nożnej (lub „piłki nożnej” w przypadku „klubu towarzyskiego” (?) tutaj), a dokładniej o dzisiejszym najlepszym zespole. Na przykład text 1zaczyna się jako ...

„W ciągu ostatnich dziewięciu lat Messi doprowadził FC Barcelona do krajowych i międzynarodowych tytułów, jednocześnie pobijając indywidualne rekordy w sposób, który wydaje się nieziemski ...”

Bardzo dobrze! Z drugiej strony zdecydowanie chciałbyś pominąć zawartość trzech wpisów pomiędzy. Oto przykład ( text 2):

„W ciągu kilku godzin w Teksasie pan Rubio zasugerował, że pan Trump oddał mocz w spodniach i użył nielegalnych imigrantów, aby wykasować swoje nieustające wiadomości na Twitterze ...”

Co więc zrobić, aby za wszelką cenę uniknąć „surfowania” od czasu text 1do text 2czasu, ciesząc się nadal literaturą o wszechmogącym FC Barcelona text 5?


TC-IDF: Wyizolowałem słowa w każdym textna długie wektory. Następnie policzył częstotliwość każdego słowa, tworząc pięć wektorów (po jednym dla każdego text), w których textzliczono tylko słowa napotkane w odpowiednim słowie - wszystkie pozostałe słowa należące do innych texts zostały wycenione na zero. Na przykład w pierwszym fragmencie text 1jego wektor miałby liczbę 1 dla słowa „Messi”, podczas gdy „Trump” miałby 0. To była część tc .

Część idf została również obliczona osobno dla każdego texti dała 5 „wektorów” (myślę, że potraktowałem je jak ramki danych), zawierające logarytmiczne przekształcenia liczby dokumentów (niestety, tylko od zera do pięciu, biorąc pod uwagę naszą małą bibliotekę ) zawierające dane słowo jak w:

log(Nie, dokumenty1+Nie. Dokumenty zawierające słowo)text01text

tc×idftext


PORÓWNANIA: Teraz wystarczyło wykonać produkty kropkowe wśród tych „wektorów o znaczeniu słownym”.

Jak można się spodziewać, iloczyn iloczynu text 1z text 5był 13.42645, podczas gdy text 1v. text2Był tylko 2.511799.

Niezgrabny kod R (nic do naśladowania) jest tutaj .

Ponownie, jest to bardzo prosta symulacja, ale myślę, że jest bardzo graficzna.

Antoni Parellada
źródło