Как добавить столбцы из списка фреймов данных? - PullRequest
4 голосов
/ 16 апреля 2020

Предположим, у меня есть следующий список данных:

lst <- list(
a=data.frame(key=c(1,2,3), val=c(10,20,30)), 
b=data.frame(key=c(1,2,3), val=c(100,200,300)), 
c=data.frame(key=c(1,2,3), val=c(1000,2000,3000)), 
d=data.frame(key=c(1,2), val=c(10000,20000)))

Как мне создать файл data.frame следующим образом? (или аналогичный):

  key val.a val.b val.c val.d
1   1    10   100  1000 10000
2   2    20   200  2000 20000
3   3    30   300  3000 NA

Я пытался сделать это таким образом (но не удалось):

Browse[2]> Reduce(function(x,y) merge(x, y, by = 'key', all.x = T), lst)
  key val.x val.y val.x val.y
1   1    10   100  1000 10000
2   2    20   200  2000 20000
3   3    30   300  3000 NA
Warning message:
In merge.data.frame(x, y, by = "key", all.x = T) :
  column names ‘val.x’, ‘val.y’ are duplicated in the result

ПРИМЕЧАНИЕ. Я бы предпочел решение base-R, но я интересуются другими способами сделать это

Ответы [ 4 ]

4 голосов
/ 16 апреля 2020

Мы можем использовать inner_join с reduce после renaming второго столбца с соответствующим list именем

library(purrr)
library(dplyr)
library(stringr)
imap(lst, ~ { nm <- .y
              .x %>% 
                rename_at(vars(val), ~ str_c(., ".", nm))}) %>% 
    reduce(full_join, by = 'key')
#    key val.a val.b val.c val.d
#1   1    10   100  1000 10000
#2   2    20   200  2000 20000
#3   3    30   300  3000 30000

Или в base R мы используем Map чтобы сделать переименование столбца, затем, как в сообщении ОП, выполните merge в Reduce

Reduce(function(...) merge(..., by = 'key', all = TRUE), 
       Map(function(x, y) setNames(x, c('key',
           paste0(names(x)[-1], ".", y))), lst, names(lst)))
#  key val.a val.b val.c val.d
#1   1    10   100  1000 10000
#2   2    20   200  2000 20000
#3   3    30   300  3000 30000
2 голосов
/ 16 апреля 2020

Если вы не слишком беспокоитесь об именах столбцов и т. Д. c, выглядящих точно так, как они есть у вас, вы можете использовать следующее:

df_merged = do.call(cbind,lst) %>% 
  select(key = a.key, 2,4,6,8) 

с выводом:

   key a.val b.val c.val d.val
1     1    10   100  1000 10000
2     2    20   200  2000 20000
3     3    30   300  3000 30000
1 голос
/ 16 апреля 2020

Более надежное решение в Base R с показанными крайними случаями. Это решение ищет каждый уникальный ключ по всему списку и заполняет таблицы NA в соответствующих случаях.

lst <- list(
  a=data.frame(key=c(1,2,3), val=c(10,20,30)), 
  b=data.frame(key=c(1,2,3), val=c(100,200,300)), 
  c=data.frame(key=c(1,2,3,4), val=c(1000,2000,3000,4000)), 
  d=data.frame(key=c(1,3), val=c(10000,30000)))

df <- data.frame(key = unique(unlist(sapply(1:length(lst), function(x) lst[[x]]$key))))
df[2:(length(lst)+1)] <- NA

for(i in 1:length(lst)){df[,(i+1)][sapply(lst[[i]]$key,match,df$key)] <- lst[[i]]$val}

colnames(df)[2:NCOL(df)] <- paste0("val.",names(lst))

Вывод

> df
  key val.a val.b val.c val.d
1   1    10   100  1000 10000
2   2    20   200  2000    NA
3   3    30   300  3000 30000
4   4    NA    NA  4000    NA

Первый попытаться в Base R

  df <- data.frame(key = c(1,2,3))
  df <- cbind(df,sapply(1:length(lst), function(x) lst[[x]]$val))

и автоматически назвать ваши столбцы

colnames(df)[2:NCOL(df)] <- paste0("val.",names(lst))
1 голос
/ 16 апреля 2020

Если lst является начальным списком, то:

library(dplyr);

#binding columns and then dropping the extra columns
df <- bind_cols(lst$a, lst$b, lst$c, lst$d)  %>% 
      select(-c(3,5,7)); 

#Use whatever name you want for the columns:
colnames(df)[c(2:5)] <- c("valLis1","valLis2","valLis3","valLis4");

df;
  key valLis1 valLis2 valLis3 valLis4
1   1      10     100    1000   10000
2   2      20     200    2000   20000
3   3      30     300    3000   30000
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...