Как извлечь целые числа в фигурных скобках в R? - PullRequest
0 голосов
/ 02 мая 2018

У меня есть пример фрейма данных act с двумя переменными, которые выглядят примерно так:

   activity_id          activity_ids
1          227 {227,32,33,34,35,252}
2           32 {227,32,33,34,35,252}
3           33 {227,32,33,34,35,252}
4           34 {227,32,33,34,35,252}
5           35 {227,32,33,34,35,252}
6          252 {227,32,33,34,35,252}
7          227 {227,32,33,34,35,252}
8           32 {227,32,33,34,35,252}
9           33 {227,32,33,34,35,252}
10          34 {227,32,33,34,35,252}

activity_id - целочисленная переменная, а activity_ids - символьная переменная.

Теперь я хочу добавить новую логическую переменную, скажем last_activity, которая возвращает истину или ложь, проверяя, является ли значение activity_id последним числом среди набора чисел в фигурных скобках переменной activity_ids. Для данных этого примера новая переменная last_activity должна возвращать TRUE только для 6-й строки (поскольку 252 - последнее число) и возвращать FALSE для всех остальных строк. Кроме того, в данных этого примера переменная activity_ids содержит 6 чисел в фигурных скобках. Он может иметь любое количество значений в фигурных скобках. Итак, мне нужен код, который можно обобщить для любого числа значений.

Спасибо!

Ответы [ 5 ]

0 голосов
/ 02 мая 2018

Другой подход с использованием apply() по столбцам в базе R:

cols <- c('activity_id', 'activity_ids')
df$last_activity <- apply(df[cols], 1, function(col) {
  x <- unlist(strsplit(col['activity_ids'], "[{},]"))
  return(col['activity_id'] == x[length(x)])
})

Или используя mapply():

df$last_activity <- mapply(function(x,y) {x == y[length(y)]}, 
       x = df$activity_id, 
       y = strsplit(df$activity_ids, "[{},]")
)

Оба принесут

   activity_id          activity_ids last_activity
1          227 {227,32,33,34,35,252}         FALSE
2           32 {227,32,33,34,35,252}         FALSE
3           33 {227,32,33,34,35,252}         FALSE
4           34 {227,32,33,34,35,252}         FALSE
5           35 {227,32,33,34,35,252}         FALSE
6          252 {227,32,33,34,35,252}          TRUE
7          227 {227,32,33,34,35,252}         FALSE
8           32 {227,32,33,34,35,252}         FALSE
9           33 {227,32,33,34,35,252}         FALSE
10          34 {227,32,33,34,35,252}         FALSE
11         212              somejunk         FALSE
0 голосов
/ 02 мая 2018

База R:

transform(dat,s=Vectorize(grepl)(paste0(activity_id,"}"),activity_ids))
   activity_id          activity_ids     s
1          227 {227,32,33,34,35,252} FALSE
2           32 {227,32,33,34,35,252} FALSE
3           33 {227,32,33,34,35,252} FALSE
4           34 {227,32,33,34,35,252} FALSE
5           35 {227,32,33,34,35,252} FALSE
6          252 {227,32,33,34,35,252}  TRUE
7          227 {227,32,33,34,35,252} FALSE
8           32 {227,32,33,34,35,252} FALSE
9           33 {227,32,33,34,35,252} FALSE
10          34 {227,32,33,34,35,252} FALSE

Для более быстрого вычисления используйте пакет stringi

stringi::stri_detect_fixed(dat$activity_ids,paste0(dat$activity_id,"}"))
 [1] FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE
0 голосов
/ 02 мая 2018

EDIT

Я только что понял, что оригинальный подход имеет проблему, когда activity_ids содержит дополнительный бит информации. Например,

df$activity_ids[6] <- "{227,32,33,34,35,2521}"

mapply(function(x, y) grepl(y, tail(x, 1), fixed = TRUE),
       strsplit(df$activity_ids, ","), df$activity_id)

#[1] FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE

все равно вернет TRUE, что неправильно.

Чтобы преодолеть это, мы можем вместо этого извлечь числовую часть последнего значения и затем сравнить ее с activity_id

mapply(function(x, y) y == sub("[^0-9]","",tail(x, 1)),
       strsplit(df$activity_ids, ","), df$activity_id)

#[1] FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE

df$activity_ids[6] <- "{227,32,33,34,35,2521}"

mapply(function(x, y) y == sub("[^0-9]","",tail(x, 1)),
      strsplit(df$activity_ids, ","), df$activity_id)

#[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE

Оригинальный ответ

Опция без регулярного выражения будет разбивать строку на "," и принимать последнее значение, используя tail, и проверять, существует ли оно в activity_id с grepl.

df$last_activity <- mapply(function(x, y) grepl(y, tail(x, 1), fixed = TRUE),
                    strsplit(df$activity_ids, ","), df$activity_id)

#   activity_id          activity_ids last_activity
#1          227 {227,32,33,34,35,252}         FALSE
#2           32 {227,32,33,34,35,252}         FALSE
#3           33 {227,32,33,34,35,252}         FALSE
#4           34 {227,32,33,34,35,252}         FALSE
#5           35 {227,32,33,34,35,252}         FALSE
#6          252 {227,32,33,34,35,252}          TRUE
#7          227 {227,32,33,34,35,252}         FALSE
#8           32 {227,32,33,34,35,252}         FALSE
#9           33 {227,32,33,34,35,252}         FALSE
#10          34 {227,32,33,34,35,252}         FALSE
0 голосов
/ 02 мая 2018

Подход регулярного выражения заключается в извлечении последнего числа из строки с использованием stri_extract_last_regex из пакета stringi и сравнении его с activity_id

library(stringi)
df$activity_id == stri_extract_last_regex(df$activity_ids, "[0-9]+")

#[1] FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE
0 голосов
/ 02 мая 2018

Используя опцию base R, sub может работать здесь:

df <- data.frame(activity_id=c(227, 252),
                 activity_ids=c("{227,32,33,34,35,252}", "{227,32,33,34,35,252}"))

df$last_activity <- df$activity_id == sub(".*,(\\d+)\\}$", "\\1", df$activity_ids)
df

      activity_id          activity_ids last_activity
1             227 {227,32,33,34,35,252}         FALSE
2             252 {227,32,33,34,35,252}          TRUE

Демо

...