Регулярное выражение в R: как заполнить фрейм данных несколькими совпадениями слева и справа от целевой строки - PullRequest
0 голосов
/ 28 января 2020

(Это продолжение до Регулярное выражение в R: сопоставить словосочетания слова узла .)

Я хочу извлечь словосочетания (словосочетания) слева и справа целевого слова (узла) и сохраните три элемента в кадре данных.

Данные :

GO <- c("This little sentence went on and went on. It was going on for quite a while. Going on for ages. It's still going on. And will go on and on, and go on forever.")

Цель :

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

То, что я пробовал до сих пор :

Для извлечения левых коллокатов I ' мы использовали str_extract_all из stringr:

unlist(str_extract_all(GO, "((\\s)?\\w+\\b){1,3}(?=\\s((g|G)o(es|ing|ne)?|went))"))
[1] "This little sentence" " went on and"         " It was"              "s still"             
[5] " And will"            " and"

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

unlist(str_extract_all(GO, "(g|G)o(es|ing|ne)?|went"))
[1] "went"  "went"  "going" "Going" "going" "go"    "go"

Чтобы извлечь правую коллокацию:

unlist(str_extract_all(GO, "(?<=(g|G)o(es|ing|ne)?|went)(\\s\\w+\\b){1,3}"))
[1] " on and went"  " on"           " on for quite" " on for ages"  " on"           " on and on"   
[7] " on forever"

Снова совпадения неполные и включаются ненужные пробелы. И, наконец, сборка всех совпадений в кадре данных приводит к ошибке:

collocates <- data.frame(
  Left = unlist(str_extract_all(GO, "((\\s)?\\w+\\b){1,3}(?=\\s((g|G)o(es|ing|ne)?|went))")),
  Node = unlist(str_extract_all(GO, "(g|G)o(es|ing|ne)?|went")),
  Right = unlist(str_extract_all(GO, "(?<=(g|G)o(es|ing|ne)?|went)(\\s\\w+\\b){1,3}"))); collocates
Error in data.frame(Left = unlist(str_extract_all(GO, "((\\s)?\\w+\\b){1,3}(?=\\s((g|G)o(es|ing|ne)?|went))")),  : 
      arguments imply differing number of rows: 6, 7

Ожидаемый результат :

Left                    Node    Right
This little sentence    went    on and went
went on and             went    on It was
on It was              going    on for quite
quite a while          Going    on for ages
ages It’s still        going    on And will
on And will               go    on and on
and on and                go    on forever

Кто-нибудь знает, как это исправить? Предложения очень ценятся.

Ответы [ 2 ]

2 голосов
/ 28 января 2020

Если вы используете Quanteda, вы можете получить следующий результат. Когда вы имеете дело с текстами, вы хотите использовать маленькие буквы. Я конвертировал заглавные буквы с tolower(). Я также удалил . и , с gsub(). Затем я применил kwic() к тексту. Если вы не против потерять заглавные буквы, точки и запятые, вы получите почти то, что хотите.

library(quanteda)
library(dplyr)
library(splitstackshape)

myvec <- c("go", "going", "goes", "gone", "went")

mytext <- gsub(x = tolower(GO), pattern = "\\.|,", replacement = "")

mydf <- kwic(x = mytext, pattern = myvec, window = 3) %>% 
        as_tibble %>%
        select(pre, keyword, post) %>% 
        cSplit(splitCols = c("pre", "post"), sep = " ", direction = "wide", type.convert = FALSE) %>% 
        select(contains("pre"), keyword, contains("post"))

   pre_1  pre_2    pre_3 keyword post_1  post_2 post_3
1:  this little sentence    went     on     and   went
2:  went     on      and    went     on      it    was
3:    on     it      was   going     on     for  quite
4: quite      a    while   going     on     for   ages
5:  ages   it's    still   going     on     and   will
6:    on    and     will      go     on     and     on
7:   and     on      and      go     on forever   <NA>
1 голос
/ 29 января 2020

Немного поздно, но не слишком поздно для потомков или современников, проводящих совместное исследование аннотированного текста, вот мой собственный ответ на мой вопрос. Полный кредит отдается указателю @ jazzurro на quanteda и его ответу.

Мой вопрос был: как вычислить коллокации данного узла в тексте и сохранить результаты в фрейме данных (эта часть не рассматривается @jazzurro).

Данные :

GO <- c("This little sentence went on and went on. It was going on for quite a while. 
    Going on for ages. It's still going on. And will go on and on, and go on forever.")

Шаг 1 : подготовка данных для анализа

go <- gsub("[.!?;,:]", "", tolower(GO))   # get rid of punctuation
go <- gsub("'", " ", tolower(go))         # separate clitics from host

Шаг 2 : извлечение KWI C с использованием шаблона и аргумента регулярного выражения valuetype = "regex"

concord <- kwic(go, "go(es|ing|ne)?|went", window = 3, valuetype = "regex")
concord                                                       
  [text1, 4] this little sentence | went  | on and went 
  [text1, 7]          went on and | went  | on it was   
 [text1, 11]            on it was | going | on for quite
 [text1, 17]        quite a while | going | on for ages 
 [text1, 24]           it s still | going | on and will 
 [text1, 28]          on and will |  go   | on and on   
 [text1, 33]           and on and |  go   | on forever  

Шаг 3 : определение строк с меньшим количеством сопоставляет значения, определенные окном:

# Number of collocates on the left:
concord$nc_l <- unlist(lengths(strsplit(concordance$pre, " "))); concord$nc_l
[1] 3 3 3 3 3 3 3   # nothing missing here
# Number of collocates on the right:
concord$nc_r <- unlist(lengths(strsplit(concordance$post, " "))); concord$nc_r
[1] 3 3 3 3 3 3 2   # last string has only two collocates

шаг 4 : добавление NA к строкам с отсутствующими словосочетаниями:

# define window:
window <- 3
# change string:
concord$post[!concord$nc_r == window] <- paste(concord$post[!concord$nc_r == window], NA, sep = " ")

шаг 5 : Заполните фрейм данных слотами для коллокатов и узлов, используя str_extract из библиотеки stringr, а также регулярное выражение с поиском для определения точек разделения для коллокатов:

library(stringr)
L3toR3 <- data.frame(
  L3 = str_extract(concord$pre, "^\\w+\\b"),
  L2 = str_extract(concord$pre, "(?<=\\s)\\w+\\b(?=\\s)"),
  L1 = str_extract(concord$pre, "\\w+\\b$"),
  Node = concord$keyword,
  R1 = str_extract(concord$post, "^\\w+\\b"),
  R2 = str_extract(concord$post, "(?<=\\s)\\w+\\b(?=\\s)"),
  R3 = str_extract(concord$post, "\\w+\\b$")
)

Результат :

L3toR3
     L3     L2       L1  Node R1      R2    R3
1  this little sentence  went on     and  went
2  went     on      and  went on      it   was
3    on     it      was going on     for quite
4 quite      a    while going on     for  ages
5    it      s    still going on     and  will
6    on    and     will    go on     and    on
7   and     on      and    go on forever    NA
...