У меня есть текст с разными классами. Моя цель - определить и сохранить только те функции, которые имеют самое высокое значение tf_idf (верхние 20%) каждого класса.
В качестве примера я использую набор данных book_of_mormon
. text
- это текст, а book_title
- это класс.
Идея состоит в том, чтобы использовать пакет tidy_text и отфильтровать 20% лучших по каждому классу.
library(scriptuRs)
library(tidytext)
library(tidyverse)
Сначала я создаю значения tf_idf:
d = book_of_mormon %>%
select(book_title, text) %>%
unnest_tokens(word, text) %>%
group_by(book_title) %>%
count(word) %>%
bind_tf_idf(word, book_title, n)
head(d, 3)
# A tibble: 3 x 6
# Groups: book_title [1]
book_title word n tf idf tf_idf
<chr> <chr> <int> <dbl> <dbl> <dbl>
1 1 Nephi a 200 0.00795 0 0
2 1 Nephi abhorreth 1 0.0000398 2.01 0.0000801
3 1 Nephi abide 1 0.0000398 0.916 0.0000364
Затем отфильтруйте 20% верхних значений tf_idf для каждого класса.
d = d %>%
group_by(book_title) %>%
arrange(book_title, -tf_idf) %>%
filter(tf_idf > quantile(tf_idf, .8))
Наконец, я преобразовал фрейм данных в матрицу (dtm). Так что у меня есть книги в виде наблюдений и особенности в виде столбцов.
d = d %>%
cast_dtm(word, book_title, tf_idf)
d = as.data.frame(as.matrix(d))
Однако, если я приведу фрейм данных обратно к матрице, что необходимо для моей задачи, число строк уменьшится (т.е. некоторые документы / наблюдения будут удалены).
dim(d)
[1] 19099 6
dim(book_of_mormon)
[1] 6604 19
Другая идея заключается в использовании пакета tm
. Тем не менее, при использовании больших наборов данных (например, моего исходного) R не хватит памяти.
Сначала я создаю DTM и фрейм данных.
library(tm)
corpus = Corpus(VectorSource(book_of_mormon$text))
corpus = corpus %>%
tm_map(removeWords, stopwords("en")) %>%
tm_map(removeNumbers) %>%
tm_map(removePunctuation) %>%
tm_map(tolower)
dtm = DocumentTermMatrix(corpus)
dtm = weightTfIdf(dtm, normalize = TRUE)
dtm = as.data.frame(as.matrix(dtm))
dtm$book_title = book_of_mormon$book_title
Затем я фильтрую объекты с самыми высокими значениями для класса.
dict = dtm %>%
gather(Variable, Value, -book_title) %>%
group_by(book_title) %>%
arrange(book_title, -Value) %>%
top_n(5, Value) # I use top_n to keep the data small (i.e it´s
# computational expensive to filter out the top
# 20% which would lead to a long runtime in R in this
# example)
Наконец, я создаю отфильтрованный DTM с топ-20% (топ-5) объектов на класс.
dtm2 = DocumentTermMatrix(corpus, control=list(dictionary = paste(dict$Variable)))
dtm2 = weightTfIdf(dtm2, normalize = TRUE)
dtm2 = as.data.frame(as.matrix(dtm2))