Запись списка, разделенного точкой с запятой, в R - PullRequest
7 голосов
/ 27 марта 2020

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

Вот что я пытаюсь:

library("tidyverse")

colors <- c("red;blue", "red;green")
df <- data.frame(colors, stringsAsFactors = FALSE)
df %>%
  mutate(green = case_when("green" %in% strsplit(colors,";")[[1]] ~ 1, 
                         TRUE ~ 0))

Результат, который я получаю:

     colors green
1  red;blue     0
2 red;green     0

Я ожидал, что значение "green" во второй строке будет 1.

Чтобы попытаться отладить это, я попытался это:

> strsplit("red;green", ";")
[[1]]
[1] "red"   "green"

> "green" %in% strsplit("red;green",";")[[1]]
[1] TRUE

# and the negative case
> "green" %in% strsplit("red;blue",";")[[1]]
[1] FALSE

Чего мне не хватает?

Ответы [ 4 ]

5 голосов
/ 27 марта 2020

С решением data.table вы можете использовать tstrsplit:

library(data.table)

df <- data.table::data.table(
  color = c("red;blue", "red;green")
)

df[, c("col1","col2") := tstrsplit(color, ";", fixed = TRUE)] 
df[, "green" := (col2 == "green")]

df

#       color col1  col2 green
# 1:  red;blue  red  blue FALSE
# 2: red;green  red green  TRUE

Если вы не знакомы с data.table оператором обновления по ссылке :=, data.table виньетки хорошее место для начала. Опция fixed = TRUE в tstrsplit предполагает, что у вас всегда есть одинаковое количество элементов в списке, разделенном запятыми.

Существует решение, которое, я думаю, более приспособлено к ситуации, когда у вас больше чем несколько значений. Повторно используя lapply, вы можете добавить ряд столбцов к вашему data.table

Начиная с df:

df <- data.table::data.table(
  color = c("red;blue", "red;green")
)

Вызов lapply с grepl для сканирования для соответствующего цвета мы обновляем по ссылке наш объект (обратите внимание, что вы можете использовать более трех цветов):

lapply(c("red","green","blue"), function(x){
  df[grepl(x, color), c(as.character(x)) := TRUE]
})
#[[1]]

#[[2]]
#       color  red green blue
#1:  red;blue TRUE    NA TRUE
#2: red;green TRUE  TRUE   NA

#[[3]]
#       color  red green blue
#1:  red;blue TRUE    NA TRUE
#2: red;green TRUE  TRUE   NA

Нет необходимости переназначать фрейм данных. Он был обновлен по ссылке. Нас интересует только последний слот df. Наконец, выбрав этот параметр и установив NAs в FALSE:

df <- df[[length(df)]]
df[is.na(df)] <- FALSE

df
#       color  red green  blue
# 1:  red;blue TRUE FALSE  TRUE
# 2: red;green TRUE  TRUE FALSE

Надеюсь, это поможет

4 голосов
/ 27 марта 2020

Данные

colors <- c("red;blue", "red;green")
df <- data.frame(colors, stringsAsFactors = FALSE)

Код

cbind.data.frame(colors,
                 sapply( unique(unlist(strsplit( unlist(df), ";", fixed = TRUE))), 
                         function(x) as.integer(grepl(x, colors))))

Выход

#      colors red blue green
# 1  red;blue   1    1     0
# 2 red;green   1    0     1

Использование %in% и отсутствие регулярного выражения в другом наборе данных с похожими элементами: green и greeni sh

colors <- c("red;blue;greenish", "red;green")
df <- data.frame(colors, stringsAsFactors = FALSE)

myfun <- function(x) { unique(unlist(strsplit( unlist(x), ";", fixed = TRUE))) }
df2 <- t(sapply( df$colors, function(x) { as.integer(myfun(df) %in% myfun(x))}))
colnames(df2) <- myfun(df)
df2
#                   red blue greenish green
# red;blue;greenish   1    1        1     0
# red;green           1    0        0     1
4 голосов
/ 27 марта 2020

Мы можем использовать str_detect

library(dplyr)
library(stringr)
df %>% 
      mutate(green = +(str_detect(colors, 'green')))

Обновить

Если нам нужны новые столбцы

library(qdapTools)
cbind(df, mtabulate(strsplit(df$colors, ";")))
#     colors blue green red
#1  red;blue    1     0   1
#2 red;green    0     1   1

Или использовать base R

cbind(df, as.data.frame.matrix(table(stack(setNames(strsplit(df$colors, ";"), 
                 seq_along(df$colors)))[2:1])))

В коде OP выбирается первый элемент strsplit list ([[1]]) вместо циклического перемещения по списку, что приводит к повторному использованию элемента и получению FALSE по мере его появления. нет «зеленого» в первом list элементе

library(purrr)
df %>%
   mutate(green = map_int(strsplit(colors, ";"), 
               ~ case_when('green' %in% .x ~ 1L, TRUE ~ 0L)))
#     colors green
#1  red;blue     0
#2 red;green     1
3 голосов
/ 27 марта 2020

%in% не работает таким образом. Попробуйте grepl

df %>% mutate(green = case_when(grepl("green",colors) ~ 1,TRUE ~ 0)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...