Подтвердить что ты не робот

Распаковка и объединение списков в столбце data.frame

У меня есть следующий data.frame:

id     name   altNames
1001   Joan   character(0)      
1002   Jane   c("Janie", "Janet", "Jan")
1003   John   Jon
1004   Bill   Will
1005   Tom    character(0)      

Столбец altNames может быть пустым (например, символ (0)), иметь только одно имя или список имен. То, что я хочу, это data.frame (или список), где каждая запись из name и/или altNames появляется только один раз вместе с соответствующим id, например:

id     name
1001   Joan
1002   Jane
1002   Janie
1002   Janet
1002   Jan
1003   John
1003   Jon
1004   Bill
1004   Will
1005   Tom

Какой самый эффективный способ сделать это? Еще лучше dplyr. Благодаря

Изменить: Здесь данные:

df <- data_frame(
  id = c("1001", "1002","1003", "1004", "1005"), 
  name = c("Joan", "Jane", "John", "Bill", "Tom"), 
  altNames = list(character(0), c("Janie", "Janet", "Jan"), "Jon", "Will", character(0))
)
4b9b3361

Ответ 1

Здесь возможен подход data.table

library(data.table)
setDT(dat)[, .(name = c(name, unlist(altNames))), by = id]
#       id  name
#  1: 1001  Joan
#  2: 1002  Jane
#  3: 1002 Janie
#  4: 1002 Janet
#  5: 1002   Jan
#  6: 1003  John
#  7: 1003   Jon
#  8: 1004  Bill
#  9: 1004  Will
# 10: 1005   Tom

Ответ 2

Базовая версия R (с использованием df, добавленной @rawr)

with(df, {
    ns <- mapply(c, name, altNames)
    data.frame(id = rep(id, times=lengths(ns)), name=unlist(ns), row.names=NULL)
})
#     id  name
#1  1001  Joan
#2  1002  Jane
#3  1002 Janie
#4  1002 Janet
#5  1002   Jan
#6  1003  John
#7  1003   Jon
#8  1004  Bill
#9  1004  Will
#10 1005   Tom

Ответ 3

Здесь полное решение dplyr + tidyr, как я его решал:

library(dplyr)
library(tidyr)

df <- data_frame(
  id = c("1001", "1002","1003", "1004", "1005"), 
  name = c("Joan", "Jane", "John", "Bill", "Tom"), 
  altNames = list(character(0), c("Janie", "Janet", "Jan"), "Jon", "Will", character(0))
)

# Need some way to concatenate a list of vectors with a vectors
# in a "rowwise" way
vector_c <- function(...) {
  Map(c, ...)
}

df %>% 
  mutate(
    names = vector_c(name, altNames),
    altNames = NULL,
    name = NULL
  ) %>% 
  unnest(names)
#> Source: local data frame [10 x 2]
#> 
#>      id names
#> 1  1001  Joan
#> 2  1002  Jane
#> 3  1002 Janie
#> 4  1002 Janet
#> 5  1002   Jan
#> 6  1003  John
#> 7  1003   Jon
#> 8  1004  Bill
#> 9  1004  Will
#> 10 1005   Tom

Большая часть тяжелой работы выполняется с помощью tidyr::unnest(): она предназначена для того, чтобы взять кадр данных со столбцом списка и отключить его, повторяя при необходимости другие столбцы.

Ответ 4

Используя tidyr, после очистки данных с помощью data.table:

Сначала исправьте данные:

library(data.table)
dat<-setDT(dat)
dat$altNames[sapply(dat$altNames, length) == 0] <- NA

Теперь unnest из tidyr и некоторая dplyr:

library(dplyr)
library(tidyr)
dat %>% unnest(altNames) %>%
        group_by(id) %>%
        do(unique(c(.[["name"]],.[["altNames"]])))

     id    V1
1  1001  Joan
2  1001    NA
3  1002  Jane
4  1002 Janie
5  1002 Janet
6  1002   Jan
7  1003  John
8  1003   Jon
9  1004  Bill
10 1004  Will
11 1005   Tom
12 1005    NA

у него есть NA, но они легко удаляются с помощью %>% na.omit.

Я считаю, что data.table является победителем на этом.