Получение уникального количества строк из текстовой строки - PullRequest
0 голосов
/ 25 февраля 2019

Мне интересно, как получить уникальное количество символов из текстовой строки.Допустим, я ищу подсчет повторений слов яблоки, бананы, ананасы, виноград в этой строке.

 A<- c('I have a lot of pineapples, apples and grapes. One day the pineapples person gave the apples person two baskets of grapes')

 df<- data.frame(A) 

Допустим, я хочу получить все уникальные числа фруктов, перечисленных в тексте.

  library(stringr)
  df$fruituniquecount<- str_count(df$A, "apples|pineapples|grapes|bananas")

Я пробовал это, но я получил все.Я хотел бы получить ответ как «3».Пожалуйста, предложите свои идеи.

Ответы [ 8 ]

0 голосов
/ 03 марта 2019

Зачем изобретать велосипед?Для этого создан пакет quanteda .

Определите вектор ваших фруктов, который в качестве бонуса я использовал с типом соответствия (по умолчанию) glob чтобы поймать как формы единственного, так и множественного числа.

A <- c("I have a lot of pineapples, apples and grapes. One day the pineapples person gave the apples person two baskets of grapes")
fruits <- c("apple*", "pineapple*", "grape*", "banana*")

library("quanteda", warn.conflicts = FALSE)
## Package version: 1.4.2
## Parallel computing: 2 of 12 threads used.
## See https://quanteda.io for tutorials and examples.

Затем, когда вы разбили его на слова с помощью tokens(), вы можете отправить результат на tokens_select(), используя ваш вектор fruits, чтобы выбрать только эти типы.

toks <- tokens(A) %>%
  tokens_select(pattern = fruits)
toks
## tokens from 1 document.
## text1 :
## [1] "pineapples" "apples"     "grapes"     "pineapples" "apples"    
## [6] "grapes"

Наконец, ntype() сообщит вам количество слов типов (уникальных слов), что является вашим желаемым выходным значением 3.

ntype(toks)
## text1 
##     3

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

ntoken(toks)
## text1 
##     6

Обе функции векторизованы, чтобы вернуть именованный целочисленный вектор, где имя элемента будет именем вашего документа (здесь quanteda по умолчанию "text1" для отдельного документа), так что это также легко и эффективно работает на большом корпусе.

Преимущества? Легче (иболее читабельным), чем регулярные выражения, плюс выДоступ к дополнительной функции для токенов.Например, предположим, что вы хотели рассматривать шаблоны фруктов в единственном и множественном числе как эквивалентные.Вы можете сделать это двумя способами в quanteda : путем замены рисунка на каноническую форму вручную, используя tokens_replace(), или путем ограничения названий фруктов, используя tokens_wordstem().

, используя * 1039.*:

B <- "one apple, two apples, one grape two grapes, three pineapples."

toksrepl <- tokens(B) %>%
  tokens_select(pattern = fruits) %>%
  tokens_replace(
    pattern = fruits,
    replacement = c("apple", "pineapple", "grape", "banana")
  )
toksrepl
## tokens from 1 document.
## text1 :
## [1] "apple"     "apple"     "grape"     "grape"     "pineapple"
ntype(toksrepl)
## text1 
##     3

Использование tokens_wordstem():

toksstem <- tokens(B) %>%
  tokens_select(pattern = fruits) %>%
  tokens_wordstem()
toksstem
## tokens from 1 document.
## text1 :
## [1] "appl"     "appl"     "grape"    "grape"    "pineappl"
ntype(toksstem)
## text1 
##     3
0 голосов
/ 25 февраля 2019

Ну, вот и базовое R решение без регулярных выражений,

sum(unique(strsplit(A, ' ')[[1]]) %in% c('apples', 'pineapples', 'grapes', 'bananas'))
#[1] 3
0 голосов
/ 25 февраля 2019

Мы можем использовать комбинацию stringr и stringi:

target<-"apples|pineapples|grapes|bananas"#inspired by @markus ' solution
length(stringi::stri_unique(stringr::str_extract_all(A,target,simplify=TRUE)))
#[1] 3
0 голосов
/ 25 февраля 2019

Может также сделать:

A <- c('I have a lot of pineapples, apples and grapes. One day the pineapples person gave the apples person two baskets of grapes')

df <- data.frame(A) 

fruits <- c("apples", "pineapples", "grapes", "bananas")

df$count <- sum(tolower(unique(unlist(strsplit(as.character(df$A), "\\.|,| ")))) %in% fruits)

Вывод:

[1] 3
0 голосов
/ 25 февраля 2019

Одна базовая возможность может быть:

length(unique(unlist(regmatches(A, gregexpr("apples|pineapples|grapes|bananas", A, perl = TRUE)))))

[1] 3

или в сокращенном виде:

fruits <- c("apples|pineapples|grapes|bananas")
length(unique(unlist(regmatches(A, gregexpr(fruits, A, perl = TRUE)))))
0 голосов
/ 25 февраля 2019

Возможно, лучший способ сделать это - сначала разбить слова, а затем подсчитать.

library(tokenizers)
library(magrittr)
df$fruituniquecount <- tokenize_words(A) %>% unlist(.) %>% unique(.) %>% 
       stringr::str_count(., "apples|pineapples|grapes|bananas") %>% sum(.)
0 голосов
/ 25 февраля 2019

Вы можете использовать str_extract_all, а затем вычислить длину уникальных элементов.

Ввод:

A <- c('I have a lot of pineapples, apples and grapes. One day the pineapples person gave the apples person two baskets of grapes')
fruits <- "apples|pineapples|grapes|bananas"

Результат

length(unique(c(stringr::str_extract_all(A, fruits, simplify = TRUE))))
# [1] 3
0 голосов
/ 25 февраля 2019

Не совсем элегантно, но вы можете использовать str_detect вот так.

sum(str_detect(df$A, "apples"), 
    str_detect(df$A, "pineapples"), 
    str_detect(df$A, "grapes"), 
    str_detect(df$A, "bananas"))

Или, основываясь на комментариях ниже, если вы поместите все эти термины в их собственный вектор, вы можете использовать функцию apply:

fruits <- c("apples", "pineapples", "grapes", "bananas")
sum(sapply(fruits, function(x) str_detect(df$A, x)))
...