我有一个列表,里面有很多我想合并的数据帧。这里的问题是,每个data.frame的行数和列数不同,但它们都共享关键变量(在下文中我将其称为“var1”和“var2”)。如果data.frames在列方面是相同的,我可以只rbind,对于plyr的rbind。填充可以完成这项工作,但这些数据不是这样的。
因为merge命令只适用于2 data.frames,所以我求助于互联网。我从这里得到了这个,它在R 2.7.2中完美地工作,这是我当时拥有的:
merge.rec <- function(.list, ...){
if(length(.list)==1) return(.list[[1]])
Recall(c(list(merge(.list[[1]], .list[[2]], ...)), .list[-(1:2)]), ...)
}
我将这样调用这个函数:
df <- merge.rec(my.list, by.x = c("var1", "var2"),
by.y = c("var1", "var2"), all = T, suffixes=c("", ""))
但在2.7.2之后的任何R版本中,包括2.11和2.12,这段代码会出现以下错误:
Error in match.names(clabs, names(xi)) :
names do not match previous names
(顺便说一句,我在其他地方看到了这个错误的其他引用,但没有解决方案)。
有办法解决这个问题吗?
我有一个没有公共id列的数据框架列表。
我丢失了许多dfs的数据。有Null值。
数据帧是使用表函数生成的。
还原,合并,rbind, rbind。填满,他们的同类不能帮助我达到我的目标。
我的目标是产生一个可理解的合并数据框架,与缺失的数据和公共id列无关。
因此,我做了如下函数。也许这个函数可以帮助到某些人。
##########################################################
#### Dependencies #####
##########################################################
# Depends on Base R only
##########################################################
#### Example DF #####
##########################################################
# Example df
ex_df <- cbind(c( seq(1, 10, 1), rep("NA", 0), seq(1,10, 1) ),
c( seq(1, 7, 1), rep("NA", 3), seq(1, 12, 1) ),
c( seq(1, 3, 1), rep("NA", 7), seq(1, 5, 1), rep("NA", 5) ))
# Making colnames and rownames
colnames(ex_df) <- 1:dim(ex_df)[2]
rownames(ex_df) <- 1:dim(ex_df)[1]
# Making an unequal list of dfs,
# without a common id column
list_of_df <- apply(ex_df=="NA", 2, ( table) )
它遵循函数
##########################################################
#### The function #####
##########################################################
# The function to rbind it
rbind_null_df_lists <- function ( list_of_dfs ) {
length_df <- do.call(rbind, (lapply( list_of_dfs, function(x) length(x))))
max_no <- max(length_df[,1])
max_df <- length_df[max(length_df),]
name_df <- names(length_df[length_df== max_no,][1])
names_list <- names(list_of_dfs[ name_df][[1]])
df_dfs <- list()
for (i in 1:max_no ) {
df_dfs[[i]] <- do.call(rbind, lapply(1:length(list_of_dfs), function(x) list_of_dfs[[x]][i]))
}
df_cbind <- do.call( cbind, df_dfs )
rownames( df_cbind ) <- rownames (length_df)
colnames( df_cbind ) <- names_list
df_cbind
}
运行示例
##########################################################
#### Running the example #####
##########################################################
rbind_null_df_lists ( list_of_df )
下面是一个通用包装器,可用于将二进制函数转换为多参数函数。这种解决方案的好处是它非常通用,可以应用于任何二进制函数。你只需要做一次,然后你可以把它应用到任何地方。
为了演示这个想法,我使用简单的递归来实现。当然,它可以用更优雅的方式实现,这得益于R对函数范式的良好支持。
fold_left <- function(f) {
return(function(...) {
args <- list(...)
return(function(...){
iter <- function(result,rest) {
if (length(rest) == 0) {
return(result)
} else {
return(iter(f(result, rest[[1]], ...), rest[-1]))
}
}
return(iter(args[[1]], args[-1]))
})
})}
然后,您可以简单地用它包装任何二进制函数,并在第一个括号中调用位置参数(通常是data.frames),在第二个括号中调用命名参数(例如by =或后缀=)。如果没有命名参数,则将第二个括号保留为空。
merge_all <- fold_left(merge)
merge_all(df1, df2, df3, df4, df5)(by.x = c("var1", "var2"), by.y = c("var1", "var2"))
left_join_all <- fold_left(left_join)
left_join_all(df1, df2, df3, df4, df5)(c("var1", "var2"))
left_join_all(df1, df2, df3, df4, df5)()