合并(rbind)dataframe并创build具有原始dataframe名称的列

我有几个数据框,我想按行组合。 在生成的单一数据框架中,我想创build一个新的variables来标识观察来自哪个数据集。

# original data frames df1 <- data.frame(x = c(1, 3), y = c(2, 4)) df2 <- data.frame(x = c(5, 7), y = c(6, 8)) # desired, combined data frame df3 <- data.frame(x = c(1, 3, 5, 7), y = c(2, 4, 6, 8), source = c("df1", "df1", "df2", "df2") # xy source # 1 2 df1 # 3 4 df1 # 5 6 df2 # 7 8 df2 

我怎样才能做到这一点? 提前致谢!

这不是你要求的,但是非常接近。 把你的对象放在一个命名列表中,并使用do.call(rbind...)

 > do.call(rbind, list(df1 = df1, df2 = df2)) xy df1.1 1 2 df1.2 3 4 df2.1 5 6 df2.2 7 8 

请注意,行名现在反映了源data.frame

更新:使用cbindrbind

另一个select是做一个基本的function,如下所示:

 AppendMe <- function(dfNames) { do.call(rbind, lapply(dfNames, function(x) { cbind(get(x), source = x) })) } 

然后这个函数接受一个你想“堆栈”的data.frame名称的字符向量,如下所示:

 > AppendMe(c("df1", "df2")) xy source 1 1 2 df1 2 3 4 df1 3 5 6 df2 4 7 8 df2 

更新2:使用“gdata”包中的组合

 > library(gdata) > combine(df1, df2) xy source 1 1 2 df1 2 3 4 df1 3 5 6 df2 4 7 8 df2 

更新3:使用“data.table”中的rbindlist

现在可以使用的另一种方法是使用“data.table”中的rbindlist。 这样做的方法可以是:

 > rbindlist(mget(ls(pattern = "df\\d+")), idcol = TRUE) .id xy 1: df1 1 2 2: df1 3 4 3: df2 5 6 4: df2 7 8 

更新4:使用来自“purrr”的map_df

rbindlist类似,您也可以使用“purrr”中的map_df和Ic作为应用于每个列表元素的函数。

 > mget(ls(pattern = "df\\d+")) %>% map_df(I, .id = "src") Source: local data frame [4 x 3] src xy (chr) (int) (int) 1 df1 1 2 2 df1 3 4 3 df2 5 6 4 df2 7 8 

我不确定这样的function是否已经存在,但这似乎有诀窍:

 bindAndSource <- function(df1, df2) { df1$source <- as.character(match.call())[[2]] df2$source <- as.character(match.call())[[3]] rbind(df1, df2) } 

结果:

 bindAndSource(df1, df2) 1 1 2 df1 2 3 4 df1 3 5 6 df2 4 7 8 df2 

警告:这不适用于*aply的电话

另外两个答案的混合:

 df1 <- data.frame(x = 1:3,y = 1:3) df2 <- data.frame(x = 4:6,y = 4:6) > foo <- function(...){ args <- list(...) result <- do.call(rbind,args) result$source <- rep(as.character(match.call()[-1]),times = sapply(args,nrow)) result } > foo(df1,df2,df1) xy source 1 1 1 df1 2 2 2 df1 3 3 3 df1 4 4 4 df2 5 5 5 df2 6 6 6 df2 7 1 1 df1 8 2 2 df1 9 3 3 df1 

如果你想避免match.call业务,你总是可以限制自己命名函数参数(即df1 = df1, df2 = df2 )和使用names(args)来访问名称。

另一种使用dplyr方法dplyr

 df1 <- data.frame(x = c(1,3), y = c(2,4)) df2 <- data.frame(x = c(5,7), y = c(6,8)) df3 <- dplyr::bind_rows(list(df1=df1, df2=df2), .id = 'source') df3 Source: local data frame [4 x 3] source xy (chr) (dbl) (dbl) 1 df1 1 2 2 df1 3 4 3 df2 5 6 4 df2 7 8 

另一个解决方法是在plyr包中使用ldply。

 df1 <- data.frame(x = c(1,3), y = c(2,4)) df2 <- data.frame(x = c(5,7), y = c(6,8)) list = list(df1 = df1, df2 = df2) df3 <- ldply(list) df3 .id xy df1 1 2 df1 3 4 df2 5 6 df2 7 8 

尽pipe这里已经有了一些很好的答案,但我只是想添加一个我一直在使用的答案。 它是基本的R所以如果你想在一个包中使用它,它可能会受到更less的限制,而且比其他一些基本的R解决scheme要快一些。

 dfs <- list(df1 = data.frame("x"=c(1,2), "y"=2), df2 = data.frame("x"=c(2,4), "y"=4), df3 = data.frame("x"=2, "y"=c(4,5,7))) > microbenchmark(cbind(do.call(rbind,dfs), rep(names(dfs), vapply(dfs, nrow, numeric(1)))), times = 1001) Unit: microseconds min lq mean median uq max neval 393.541 409.083 454.9913 433.422 453.657 6157.649 1001 

第一部分, do.call(rbind, dfs)将dataframe的行绑定到单个数据框中。 vapply(dfs, nrow, numeric(1))查找每个dataframe有多less行被传递给rep中的rep(names(dfs), vapply(dfs, nrow, numeric(1))) ,重复名称dataframe的每一行dataframe一次。 cbind把它们放在一起。

这与以前发布的解决scheme类似,但速度提高了约2倍。

 > microbenchmark(do.call(rbind, lapply(names(dfs), function(x) cbind(dfs[[x]], source = x))), times = 1001) Unit: microseconds min lq mean median uq max neval 844.558 870.071 1034.182 896.464 1210.533 8867.858 1001 

我不是百分之百肯定的,但我相信加快速度是由于一次调用cbind而不是每个dataframe一次。