我正在尝试合并
df1
"ID" "df1"
var1 100
var2 300
var3 400
var5 300
df2
"ID" "df2"
var1 100
var2 200
var4 300
var5 400
制作
"ID" "df1" "df2"
var1 100 100
var2 200 300
var3 400 NA
var4 400 300
var5 300 400
,并将其应用于lapply
的csv文件列表。目的是为每个变量(ID)创建一个具有单个ID列的csv文件,并将每个从csv列表中读取的内容作为一个单独的列,如下所示。
final
ID df1 df2 df3 df4 df5
var1
var2
var3
var4
var5
merge
可以完美地工作,当我一一指定文件时,但尝试循环播放文件{。{1}}中的最后一项会覆盖write.csv。
我的代码当前如下所示:
list.files
我想在目录中创建一个csv(如果尚不存在),然后命名第一列ID,该ID与其他csv文件中的ID列匹配。然后,在电子表格中重命名我的列名,以提高可读性。
最后,我想将我的一个数据框与新创建的
sheetname<-str_split_fixed(foo_bar,"_")[1]
if(file.exists(paste0(dir,sheet_name)) == FALSE) {
write.csv(file=(paste0(dir,sheet_name,".csv")),x=1,row.names=FALSE)
}
new_file<-read.csv(paste0(dir,sheet_name,".csv"),header=TRUE)
colnames(datafile)[2] = paste0(str_split_fixed(foo_bar_foo_1,"_",n=4)[4])
colnames(new_file)[1] = "ID"
final<- merge(x=new_file,y=csv_single,all=TRUE)
write.csv(final, file = paste0(enddir,sheet_name,".csv"),row.names = FALSE)
}
合并,在每次迭代时,它将在旧的数据框上重写我的数据框,重写该文件,并添加唯一的行和列每个新数据框。
我在哪里错了?
答案 0 :(得分:0)
假设您的数据很小,让我们按步骤进行划分:
1:读取文件名列表:
files_to_read <- list.files(...)
2:加载数据,并检查您的数据并检查其是否正常运行。 但是,因为这是要对独立文件重复的单独步骤,所以我们将编写一个函数:
read_my_file <- function(fn) {
df <- read.csv(fn)
# check check check.. er...
if (ncol(df) != 2)
return(NULL) ## don't return an invalid data frame
if (names(df)[1] != ID')
return(NULL)
# The amount of checking depends on how paranoid you are and how much (or little) you trust the input files.
# If everything is fine, return the data
return(df)
}
3:在R中,显式循环可能很慢,通常建议您使用*apply
系列方法,就像您在lapply
中正确找到的那样。
all_my_data_frames <- lapply(files_to_read, read_my_file)
# remove NULL elements:
didnotwork <- sapply(all_my_data_frames, is.null)
all_my_data_frames <- all_my_data_frames[!didnotwork]
all_my_data_frames
现在是一个 list 对象。使用str(all_my_data_frames)
进行检查。每个元素都应该有一个元素
files_to_read
中的文件名。然后,我们检查列表中的任何元素是否为NULL
(出了点问题),然后将那些被正确读取的元素作为子集。
4:Reduce
是您的朋友在这里。我无法尝试此解决方案,因此可以帮助您入门。请注意,我使用的是匿名函数,因为有时候我们不能只为使用一次函数而烦恼命名函数...
Reduce(function(a,b) merge(a,b,by='ID', all=TRUE), x)
尽管您可以手动执行循环操作。但是,当迭代相互依赖时(通过依赖于先前的迭代或访问/更新外部文件或变量),*apply
系列方法通常无法很好地工作。因此,最好使用循环:
res <- data.frame(ID=character(0)) ## initiate
for (i in seq_along(all_my_data_frames)) {
if (is.null(all_my_data_frames[[i]])) ## notice double brackets!
next
res <- merge(res, all_my_data_frames[[i]], by='ID', all=TRUE)
}
这样做的好处是您可以即时检查是否应跳过某个元素。