2015-09-08 2 views
1

Основываясь на следующих кадрах данных:Слияние как консолидация dataframes в R

df1<-data.frame(ast = c('MMM', 'ABT','AES'), aloc = c(0.4140585, 0.3599352,0.2260063)) 
df2<-data.frame(ast = c('MMM','ABT','AFL', 'AES','A'), aloc =c(0.2493530, 0.2478328, 0.1720778, 0.1702486, 0.1604878)) 
df3<-data.frame(ast = c('ABT','MMM','ADBE','AFL','AMD'), aloc =c(0.2578605, 0.2540922, 0.2183000, 0.1364096, 0.1333377)) 

Я хотел бы сделать что-то вроде слияния (хотя я не мог сделать это со слиянием), чтобы получить следующий результат:

#  Df1  Df2  Df3 
A  NA  NA 0.1604878 
ABT 0.3599352 0.2478328 0.2578605 
ADBE  NA  NA 0.2183000 
AES 0.2260063 0.1702486  NA 
AFL  NA  0.1720778 0.1364096 
AMD  NA   NA 0.1333377 
MMM 0.4140585 0.2493530 0.2540922 

ответ

5

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

library(dplyr) 

full_join(df1, df2, by = "ast") %>% 
    full_join(., df3, by = "ast") %>% 
    setNames(c(names(.)[1], paste0("df", 1:3))) %>% 
    arrange(ast) 

Что дает:

# ast  df1  df2  df3 
#1 A  NA 0.1604878  NA 
#2 ABT 0.3599352 0.2478328 0.2578605 
#3 ADBE  NA  NA 0.2183000 
#4 AES 0.2260063 0.1702486  NA 
#5 AFL  NA 0.1720778 0.1364096 
#6 AMD  NA  NA 0.1333377 
#7 MMM 0.4140585 0.2493530 0.2540922 

Или согласно @RichardScriven на упоминалось:

Reduce(function(...) full_join(..., by = "ast"), list(df1, df2, df3)) %>% arrange(ast) 

Если у вас есть много df в вашей глобальной окружающей среды в виде ФР п вы могли бы также сделать:

dflist <- ls(pattern = "df[1-9]") 
Reduce(function(...) full_join(..., by = "ast"), lapply(dflist, get)) %>% 
    setNames(c(names(.)[1], dflist)) %>% 
    arrange(ast) 
+0

Я думаю, что это самый элегантный; но я предпочитаю сначала переименовывать столбцы, поэтому слияния являются автоматическими: 'full_join (rename (df1, df1 = aloc), rename (df2, df2 = aloc))%>% full_join (переименование (df3, df3 = aloc)) ' – user295691

+1

Другим вариантом (лучше для большего количества кадров данных) является' Уменьшить (function (...) full_join (..., by = "ast"), list (df1, df2, df3))%>% аранжировать (ast) ' –

+1

Я бы поднял голову, если бы мог –

3

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

df1<-data.frame(ast = c('MMM', 'ABT','AES'), aloc = c(0.4140585, 0.3599352,0.2260063)) 
df2<-data.frame(ast = c('MMM','ABT','AFL', 'AES','A'), aloc =c(0.2493530, 0.2478328, 0.1720778, 0.1702486, 0.1604878)) 
df3<-data.frame(ast = c('ABT','MMM','ADBE','AFL','AMD'), aloc =c(0.2578605, 0.2540922, 0.2183000, 0.1364096, 0.1333377)) 

df1$df1 <- df1$aloc 
df2$df2 <- df2$aloc 
df3$df3 <- df3$aloc 

df1$aloc <- NULL 
df2$aloc <- NULL 
df3$aloc <- NULL 

data <- merge(df1, df2, by = "ast", all = TRUE) 
data <- merge(data, df3, by = "ast", all = TRUE) 

data 
2

sqldf package можно использовать для таких вещей, как это. Это позволяет вам рассматривать кадры данных в виде таблиц SQL, а также выполнять запросы SQL на них:

library(sqldf) 
sqldf('select a.ast, df1.aloc as df1, df2.aloc as df2, df3.aloc as df3 
     from (select ast from df1 union select ast from df2 union select ast from df3) as a 
      left join df1 on a.ast = df1.ast 
      left join df2 on a.ast = df2.ast 
      left join df3 on a.ast = df3.ast') 
## ast  df1  df2  df3 
## 1 A  NA 0.1604878  NA 
## 2 ABT 0.3599352 0.2478328 0.2578605 
## 3 ADBE  NA  NA 0.2183000 
## 4 AES 0.2260063 0.1702486  NA 
## 5 AFL  NA 0.1720778 0.1364096 
## 6 AMD  NA  NA 0.1333377 
## 7 MMM 0.4140585 0.2493530 0.2540922 

sqldf() функция возвращает фрейм данных, и вы можете работать с ним, как, например:

rownames(df) <- df[,1] 
df <- df[,-1] 
df 
##   df1  df2  df3 
## A   NA 0.1604878  NA 
## ABT 0.3599352 0.2478328 0.2578605 
## ADBE  NA  NA 0.2183000 
## AES 0.2260063 0.1702486  NA 
## AFL   NA 0.1720778 0.1364096 
## AMD   NA  NA 0.1333377 
## MMM 0.4140585 0.2493530 0.2540922 
1

Итак, вот два решения. Они имеют преимущество перед другими решениями (wx решение tidyr), что вы можете работать с произвольным количеством data.frames, просто изменив первую строку (lst <- ...).

library(reshape2) 
lst <- list(df1,df2,df3) 
df <- do.call(rbind,lst) 
df <- cbind(df.name=rep(1:length(lst),sapply(lst,nrow)),df) 
result <- dcast(df,ast~df.name) 
result[order(as.character(result$ast)),] 
# ast   1   2   3 
# 4 A  NA 0.1604878  NA 
# 1 ABT 0.3599352 0.2478328 0.2578605 
# 6 ADBE  NA  NA 0.2183000 
# 2 AES 0.2260063 0.1702486  NA 
# 5 AFL  NA 0.1720778 0.1364096 
# 7 AMD  NA  NA 0.1333377 
# 3 MMM 0.4140585 0.2493530 0.2540922 


library(data.table) 
lst <- list(df1,df2,df3) 
df <- do.call(rbind,lst) 
setDT(df)[,df.name:=rep(1:length(lst), sapply(lst,nrow))] 
result <- dcast.data.table(df,ast~df.name, value.var="aloc") 
result[,ast:=factor(ast, levels=sort(levels(ast)))] 
setkey(result,ast) 
result 
#  ast   1   2   3 
# 1: A  NA 0.1604878  NA 
# 2: ABT 0.3599352 0.2478328 0.2578605 
# 3: ADBE  NA  NA 0.2183000 
# 4: AES 0.2260063 0.1702486  NA 
# 5: AFL  NA 0.1720778 0.1364096 
# 6: AMD  NA  NA 0.1333377 
# 7: MMM 0.4140585 0.2493530 0.2540922 

Оба из них связывают data.frames вместе построчно, с колонной, df.name, чтобы указать, какие data.frame эта строка принадлежит, то бросает из длинного формата в широком формате. Решение data.table, вероятно, будет намного быстрее с большими наборами данных.

0

Во-первых, мы можем сделать длинный dataframe с помощью rbind:

rbinddf <- rbind(df1, df2, df3) 

Тогда нам нужен столбец ID от оригиналов:

rbinddf$id <- unlist(lapply(1:3, function(n, i){rep(paste0("df", i), nrow(n[[i]]))}, n = list(df1, df2, df3))) 

Тогда это просто Reshape - мы можем использовать tidyr

library(tidyr) 
spread(rbinddf, id, aloc) 
Смежные вопросы