Проверка двух столбцов строк на соответствие по строкам в R

#r #data.table #grepl

#регулярное выражение #r #data.table

Вопрос:

Допустим, у меня есть два столбца строк:

 library(data.table)
DT <- data.table(x = c("a","aa","bb"), y = c("b","a","bbb"))
  

Для каждой строки я хочу знать, присутствует ли строка в x в столбце y. Циклический подход будет:

 for (i in 1:length(DT$x)){
  DT$test[i] <- DT[i,grepl(x,y)   0]
}

DT
    x   y test
1:  a   b    0
2: aa   a    0
3: bb bbb    1
  

Существует ли векторизованная реализация этого? grep(DT$x,DT$y) При использовании используется только первый элемент x.

Комментарии:

1. @LegalizeIt да, я не ищу ситуации, когда a == b, но когда у вас есть частичные совпадения строк по строкам. Вышеупомянутые тесты, если x находится в y, но вы можете повторно запустить другим способом, если это важно. Я не уверен, что вы подразумеваете под «Почему в столбце y нет «a»?»

2. @DavidArenburg хорошая мысль, но работает только тогда, когда x уникально. Я пытался DT[, test := grepl(x, y) 0, by = .I] , но получаю ту же argument 'pattern' has length > 1 and only the first element will be used ошибку. Тем не менее, может быть решение, в котором вы сначала вызываете DT[, RowI := .I], а затем используете by = rowI

3. Это работает не только тогда, когда x уникально. Отлично работает DT <- data.table(x = c("a","aa","aa","bb"), y = c("b","a","a", "bbb")) , например, для.

4. @DavidArenburg Вы правы… он будет передавать один и тот же аргумент в grepl для каждой группы x, что является одним и тем же вводом. Умно. Я сравниваю все ответы и отвечу лучшим.

5. О, я вижу, что вы там сделали. Вы задали это для вопроса о вознаграждении…

Ответ №1:

Вы можете просто сделать

 DT[, test := grepl(x, y), by = x]
  

Ответ №2:

Или mapply ( Vectorize на самом деле это просто оболочка для mapply )

 DT$test <- mapply(grepl, pattern=DT$x, x=DT$y)
  

Ответ №3:

Спасибо всем за ваши ответы. Я провел сравнительный анализ их всех и пришел к следующему:

 library(data.table)
library(microbenchmark)

DT <- data.table(x = rep(c("a","aa","bb"),1000), y = rep(c("b","a","bbb"),1000))

DT1 <- copy(DT)
DT2 <- copy(DT)
DT3 <- copy(DT)
DT4 <- copy(DT)

microbenchmark(
DT1[, test := grepl(x, y), by = x]
,
DT2$test <- apply(DT, 1, function(x) grepl(x[1], x[2]))
,
DT3$test <- mapply(grepl, pattern=DT3$x, x=DT3$y)
,
{vgrepl <- Vectorize(grepl)
DT4[, test := as.integer(vgrepl(x, y))]}
)
  

Результаты

 Unit: microseconds
                                                                               expr       min        lq       mean     median        uq        max neval
                                             DT1[, `:=`(test, grepl(x, y)), by = x]   758.339   908.106   982.1417   959.6115  1035.446   1883.872   100
                            DT2$test <- apply(DT, 1, function(x) grepl(x[1], x[2])) 16840.818 18032.683 18994.0858 18723.7410 19578.060  23730.106   100
                              DT3$test <- mapply(grepl, pattern = DT3$x, x = DT3$y) 14339.632 15068.320 16907.0582 15460.6040 15892.040 117110.286   100
 {     vgrepl <- Vectorize(grepl)     DT4[, `:=`(test, as.integer(vgrepl(x, y)))] } 14282.233 15170.003 16247.6799 15544.4205 16306.560  26648.284   100
  

Решение data.table не только наиболее синтаксически простое, но и самое быстрое.

Комментарии:

1. Я не уверен, какой здесь этикет (принять ответ Дэвида или мой). Независимо от того, 1 для всех, чтобы показать количество способов, которыми это можно сделать.

2. Для этого конкретного примера (с x повторением обоих y значений и) я вижу небольшое улучшение по сравнению с by=.(x,y) by=x первым.

Ответ №4:

Вы можете передать grepl функцию в функцию apply для работы с каждой строкой вашей таблицы данных, где первый столбец содержит строку для поиска, а второй столбец содержит строку для поиска. Это должно дать вам векторное решение вашей проблемы.

 > DT$test <- apply(DT, 1, function(x) as.integer(grepl(x[1], x[2])))
> DT
    x   y test
1:  a   b    0
2: aa   a    0
3: bb bbb    1
  

Ответ №5:

Вы можете использовать Vectorize :

 vgrepl <- Vectorize(grepl)
DT[, test := as.integer(vgrepl(x, y))]
DT
    x   y test
1:  a   b    0
2: aa   a    0
3: bb bbb    1