Термин частота / обратная частота документа (TF / IDF): взвешивание


12

У меня есть набор данных, который представляет 1000 документов и все слова, которые появляются в нем. Таким образом, строки представляют документы, а столбцы представляют слова. Так, например, значение в ячейке обозначает время, когда слово встречается в документе(i,j)j . Теперь я должен найти «веса» слов, используя метод tf / idf, но на самом деле я не знаю, как это сделать. Может кто-нибудь помочь мне?i


Tf-idf-статистика для извлечения ключевых слов - joyofdata.de/blog/tf-idf-statistic-keyword-extraction
Рафаэль

Ответы:


12

В Википедии есть хорошая статья на эту тему, дополненная формулами. Значения в вашей матрице - это термин частоты. Вам просто нужно найти idf: (log((total documents)/(number of docs with the term))и умножить 2 значения.

В R вы можете сделать это следующим образом:

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

Вот наборы данных:

> 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

Вы также можете посмотреть на idf каждого термина:

> 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 

Спасибо за вашу помощь! Но возможно ли получить какое-то значение для каждого слова, которое представляет некоторый вес (вместо целой матрицы)? Теперь у нас есть целая матрица весов. Я делаю выбор некоторых функций и хочу использовать tf / idf в качестве метода фильтра ...
ABC

@ABC tf-idf по определению относится к полной матрице весов. Возможно, вас интересуют одни веса IDF, которые вы бы получили log((number of docs)/(number of docs containing the term)). Вы также можете просто отфильтровать редкие термины.
Зак

Очень ясно! Очень ценится
ABC

13

есть пакет tm (text mining) http://cran.r-project.org/web/packages/tm/index.html, который должен делать именно то, что вам нужно:

#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 - функциональный язык, поэтому чтение кода может быть сложным (например, х в терминах)


2

В вашем коде есть ошибка: colSums вычисляет количество вхождений в корпусе, а не количество текстов со словом.

Версия вычислений такая:

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

Я опаздываю на эту вечеринку, но я играл с концепциями tc-idf (я хочу подчеркнуть слово «концепция», потому что я не следовал никаким книгам для реальных вычислений; так что они могут быть несколько непонятными, и определенно это легче сделать с помощью таких пакетов, как {tm: Text Mining Package}, как уже упоминалось), и я думаю, что то, что я получил, может быть связано с этим вопросом, или, в любом случае, это может быть хорошим местом для публикации.


SET-UP: У меня есть корпус из 5длинных пунктов , взятых из печатных средств массовой информации, text 1через 5такие , как The New York Times . Предположительно, это очень маленькое «тело», крошечная библиотека, так сказать, но записи в этой «цифровой» библиотеке не случайны: первая и пятая записи имеют отношение к футболу (или «футбол» для «социального клуба») (?) где-то здесь), а точнее о самой великой команде сегодня. Так, например, text 1начинается как ...

«За последние девять лет Месси вывел« Барселону »на национальные и международные титулы, побив индивидуальные рекорды способами, которые кажутся потусторонними ...»

Очень хорошо! С другой стороны, вы определенно хотите пропустить содержимое трех записей между ними. Вот пример ( text 2):

«В течение нескольких часов по всему Техасу г-н Рубио предположил, что г-н Трамп мочился в его штаны и использовал нелегальных иммигрантов, чтобы прослушивать его непрерывные сообщения в Твиттере ...»

Так что же делать, чтобы любой ценой избежать «серфинга» от text 1до text 2, продолжая радоваться литературе о всемогущем «Барселоне» text 5?


TC-IDF: Я выделил слова в каждом textв длинные векторы. Затем посчитали частоту каждого слова, создав пять векторов (по одному для каждого text), в которых textбыли подсчитаны только слова, встречающиеся в соответствующем - все остальные слова, принадлежащие другим texts, были оценены в ноль. В первом фрагменте text 1, например, его вектор будет иметь значение 1 для слова «Месси», а для «Трампа» - 0. Это была часть tc .

Часть idf также рассчитывалась отдельно для каждого text, и в результате было получено 5 «векторов» (я думаю, что я рассматривал их как фреймы данных), содержащих логарифмические преобразования количества документов (к сожалению, от нуля до пяти, учитывая нашу небольшую библиотеку ) содержащее данное слово как в:

log(No. documents1+No. docs containing a word)text01text

tc×idftext


СРАВНЕНИЯ: Теперь это был просто вопрос выполнения точечных произведений среди этих «векторов важности слова».

Как и ожидалось, скалярное произведение text 1с text 5было 13.42645, а text 1v text2было только 2.511799.

Неуклюжий код R (нечего имитировать) находится здесь .

Опять же, это очень элементарная симуляция, но я думаю, что это очень наглядно.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.