#r #regex #for-loop
#r #регулярное выражение #for-цикл
Вопрос:
Я работаю над разговорными оборотами в разговоре. Меня интересуют слова, которые повторяются от предыдущего хода к следующему ходу:
turnsX <- data.frame(
speaker = c("A","B","A","B"),
speech = c("let's have a look",
"yeah let's take a look",
"yeah okay so where to start",
"let's start here"), stringsAsFactors = F
)
Я хочу извлечь повторяющиеся словоформы. С этой целью я запустил for
цикл, итеративно определяя каждый speech
ход как шаблон регулярных выражений для следующего speech
хода и str_extract
вводя слова, которые повторяются от поворота к повороту:
library(stringr)
pattern <- c()
extracted <- c()
for(i in 1:nrow(turnsX)){
pattern[i] <- paste0(unlist(str_split(turnsX$speech[i], " ")), collapse = "|")
extracted[i 1] <- str_extract_all(turnsX$speech[i 1], pattern[i])
}
Однако результат частично неверен:
extracted
[[1]]
NULL
[[2]]
[1] "a" "let's" "a" "a" "look"
[[3]]
[1] "yeah" "a" "a"
[[4]]
[1] "start"
[[5]]
[1] NA
Правильный результат должен быть:
extracted
[[1]]
NULL
[[2]]
[1] "let's" "a" "look"
[[3]]
[1] "yeah"
[[4]]
[1] "start"
Где ошибка? Как можно исправить код или какой другой подход существует, чтобы получить правильный результат?
Ответ №1:
Может быть, вы можете использовать Map
и %in%
.
x <- strsplit(turnsX$speech, " ")
Map(function(y,z) y[y %in% z], x[-length(x)], x[-1])
#[[1]]
#[1] "let's" "a" "look"
#
#[[2]]
#[1] "yeah"
#
#[[3]]
#[1] "start"
Ответ №2:
Вот базовый подход R, использующий Map
:
tmp <- strsplit(turnsX$speech, ' ')
c(NA, Map(intersect, tmp[-1], tmp[-length(tmp)]))
#[[1]]
#[1] NA
#[[2]]
#[1] "let's" "a" "look"
#[[3]]
#[1] "yeah"
#[[4]]
#[1] "start"
Комментарии:
1. Очень хорошее лаконичное решение, большое спасибо. Любой намек на то, где мой код идет не так?
2. Я могу предложить пару вещей. 1) Ваш
for
цикл начинается с1:nrow(turnsX)
того, что он должен быть1:(nrow(turnsX) - 1)
, поскольку дляnrow(turnsX)
нетi 1
позиции. 2) Использование регулярных выражений делает эту вещь немного более сложной, чем она есть на самом деле. Однако, если вы хотите исправить свой подход, вам нужно обернутьunique
str_extract_all
выходные данные, инициализироватьextracted <- list()
и изменить последнюю строку наextracted[[i]] <- unique(str_extract_all(turnsX$speech[i 1], pattern[i])[[1]])
3. Извините, вам не нужны
unique
границы слов, как показано в решении @jay.sf.
Ответ №3:
Вам нужны границы слов "\b"
library(stringr)
pattern <- c()
extracted <- c()
for(i in 2:nrow(turnsX)){
pattern[i - 1] <- paste0(unlist(str_split(turnsX$speech[i - 1], " ")), collapse = "|\b")
extracted[i] <- str_extract_all(turnsX$speech[i], pattern[i - 1])
}
# [[1]]
# NULL
#
# [[2]]
# [1] "let's" "a" "look"
#
# [[3]]
# [1] "yeah"
#
# [[4]]
# [1] "start"
Комментарии:
1. Я изменил выражение шаблона так, чтобы
\b
оно находилось по обе стороны от слов :paste0("\b(", paste0(unlist(str_split(kdd$Turn[i-1], " ")), collapse = "|"), ")\b")
. В большем наборе данных это сильно меняет результаты.