R: найти конкретную строку рядом с другой строкой с циклом for - PullRequest
1 голос
/ 12 марта 2019

У меня есть текст романа в одном векторе, он разбит на слова novel.vector.words Я ищу все экземпляры строки "кровь". Однако, поскольку вектор разбит по словам, каждое слово является собственной строкой, и я не знаю, чтобы искать соседние строки в векторе.

У меня есть общее представление о том, что делают циклы, и, следуя некоторым инструкциям из учебника, я могу использовать этот цикл for для нацеливания на все позиции «крови» и контекста вокруг него, чтобы создать выделенный табуляцией дисплей KWIC (ключевые слова в контексте).

node.positions <- grep("blood", novel.vector.words)

output.conc <- "D:/School/U Alberta/Classes/Winter 2019/LING 603/dracula_conc.txt"
cat("LEFT CONTEXT\tNODE\tRIGHT CONTEXT\n", file=output.conc) # tab-delimited header

#This establishes the range of how many words we can see in our KWIC display
context <- 10 # specify a window of ten words before and after the match

for (i in 1:length(node.positions)){ # access each match...
  # access the current match
  node <- novel.vector.words[node.positions[i]]
  # access the left context of the current match
  left.context <- novel.vector.words[(node.positions[i]-context):(node.positions[i]-1)]
  # access the right context of the current match
  right.context <- novel.vector.words[(node.positions[i]+1):(node.positions[i]+context)]
  # concatenate and print the results
  cat(left.context,"\t", node, "\t", right.context, "\n", file=output.conc, append=TRUE)}

Однако я не уверен, как это сделать, - использовать что-то вроде оператора if или что-то, чтобы захватывать только случаи «крови», за которыми следует «of». Нужна ли другая переменная в цикле for? В основном, я хочу, чтобы для каждого найденного им экземпляра «крови» я хотел видеть, является ли слово, следующее непосредственно за ним, «из». Я хочу, чтобы цикл нашел все эти экземпляры и сказал, сколько их в моем векторе.

1 Ответ

1 голос
/ 12 марта 2019

Вы можете создать индекс, используя dplyr::lead для соответствия 'из' следующей 'крови':

library(dplyr)

novel.vector.words <- c("blood", "of", "blood", "red", "blood", "of", "blue", "blood")

which(grepl("blood", novel.vector.words) & grepl("of", lead(novel.vector.words)))

[1] 1 5

В ответ на вопрос в комментариях:

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

Вот пример того, как найтикак часто слова «кровь» и «о» встречаются в пяти словах друг друга в «Дракуле» Брэма Стокера с использованием пакета tidytext.

library(tidytext)
library(dplyr)
library(stringr)

## Read Dracula into dataframe and add explicit line numbers
fulltext <- data.frame(text=readLines("https://www.gutenberg.org/ebooks/345.txt.utf-8", encoding = "UTF-8"), stringsAsFactors = FALSE) %>%
  mutate(line = row_number())

## Pair of words to search for and word distance
word1 <- "blood"
word2 <- "of"
word_distance <- 5

## Create ngrams using skip_ngrams token
blood_of <- fulltext %>% 
  unnest_tokens(output = ngram, input = text,  token = "skip_ngrams", n = 2, k = word_distance - 1) %>%
  filter(str_detect(ngram, paste0("\\b", word1, "\\b")) & str_detect(ngram, paste0("\\b", word2, "\\b"))) 

## Return count
blood_of %>%
  nrow

[1] 54

## Inspect first six line number indices
head(blood_of$line)

[1]  999 1279 1309 2192 3844 4135
...