使 rbindlist 跳过、忽略或更改列的 class 属性
Make rbindlist skip, ignore or change class attribute of the column
我想合并一大组数据帧(大约 30 个),每个数据帧大约有 200 个变量。这些数据集非常相似但不完全相同。
请在下面找到两个示例数据框:
library(data.table)
library(haven)
df1 <- fread(
"A B C iso year
0 B 1 NLD 2009
1 A 2 NLD 2009
0 Y 3 AUS 2011
1 Q 4 AUS 2011
0 NA 7 NLD 2008
1 0 1 NLD 2008
0 1 3 AUS 2012",
header = TRUE
)
df2 <- fread(
"A B D E iso year
0 1 1 NA ECU 2009
1 0 2 0 ECU 2009
0 0 3 0 BRA 2011
1 0 4 0 BRA 2011
0 1 7 NA ECU 2008
1 0 1 0 ECU 2008
0 0 3 2 BRA 2012
1 0 4 NA BRA 2012",
header = TRUE
)
重现错误:
class(df2$B) <- "anything"
当我执行以下操作时
df_merged <- rbindlist(list(df1, df2), fill=TRUE, use.names=TRUE)
数据集报错:
Error in rbindlist(list(df1, df2), fill = TRUE, use.names = TRUE) :
Class attribute on column 2 of item 2 does not match with column 2 of item 1.
我能做些什么:
- 使
rbindlist
跳过不匹配的列并添加一些后缀。
- 将其中一列的 class 更改为另一列。
选项 1 的预期结果:
df_merged <- fread(
"A B B.x C D E iso year
0 A NA 1 NA NA NLD 2009
1 Y NA 2 NA NA NLD 2009
0 Q NA 3 NA NA AUS 2011
1 NA NA 4 NA NA AUS 2011
0 0 NA 7 NA NA NLD 2008
1 1 NA 1 NA NA NLD 2008
0 1 NA 3 NA NA AUS 2012
0 NA 1 NA 1 NA ECU 2009
1 NA 0 NA 2 0 ECU 2009
0 NA 0 NA 3 0 BRA 2011
1 NA 0 NA 4 0 BRA 2011
0 NA 1 NA 7 NA ECU 2008
1 NA 0 NA 1 0 ECU 2008
0 NA 0 NA 3 2 BRA 2012
1 NA 0 NA 4 NA BRA 2012",
header = TRUE
)
选项 2 的预期结果:
df_merged <- fread(
"A B C D E iso year
0 3 1 NA NA NLD 2009
1 4 2 NA NA NLD 2009
0 5 3 NA NA AUS 2011
1 5 4 NA NA AUS 2011
0 0 7 NA NA NLD 2008
1 1 1 NA NA NLD 2008
0 1 3 NA NA AUS 2012
0 1 NA 1 NA ECU 2009
1 0 NA 2 0 ECU 2009
0 0 NA 3 0 BRA 2011
1 0 NA 4 0 BRA 2011
0 1 NA 7 NA ECU 2008
1 0 NA 1 0 ECU 2008
0 0 NA 3 2 BRA 2012
1 0 NA 4 NA BRA 2012",",
header = TRUE
)
我提出了这个不雅 解决方案来绕过这个问题。基本上,我所做的是将列表第一项的列的属性分配给与列表中所有其他项目同名的列。请记住,此解决方案存在问题,并且根据项目的不同,这可能是一种非常错误的做法,因为它有可能弄乱您的数据。但是,如果您需要的是使用 rbindlist
来组合您的数据帧,那么这就是诀窍
dfs <- list(df1, df2)
varnames <- names(dfs[[1]]) # variable names
vattr <- purrr::map_chr(varnames, ~class(dfs[[1]][[.x]])) # variable attributes
for (i in seq_along(dfs)) {
# assign the same attributes of list 1 to the rest of the lists
for (j in seq_along(varnames)) {
if (varnames[[j]] %in% names(dfs[[i]])) {
class(dfs[[i]][[varnames[[j]]]]) <- vattr[[j]]
}
}
}
df_merged <- data.table::rbindlist(dfs, fill=TRUE, use.names=TRUE)
最佳,
尝试 ldply(list, data.frame)
作为变通方法。为我工作,rbindlist() 不喜欢日期列。
@R.Andres Castaneda 的回答更不优雅的解决方案是:
当使用 fread
设置 colClasses = "character"
将所有内容强制转换为字符时,请执行 rbindlist
,然后选择您喜欢的方法,以便随后将所有内容强制转换回合理的状态。
它并不优雅,但我经常发现这是读取不一致数据时最简单的方法。
我想合并一大组数据帧(大约 30 个),每个数据帧大约有 200 个变量。这些数据集非常相似但不完全相同。
请在下面找到两个示例数据框:
library(data.table)
library(haven)
df1 <- fread(
"A B C iso year
0 B 1 NLD 2009
1 A 2 NLD 2009
0 Y 3 AUS 2011
1 Q 4 AUS 2011
0 NA 7 NLD 2008
1 0 1 NLD 2008
0 1 3 AUS 2012",
header = TRUE
)
df2 <- fread(
"A B D E iso year
0 1 1 NA ECU 2009
1 0 2 0 ECU 2009
0 0 3 0 BRA 2011
1 0 4 0 BRA 2011
0 1 7 NA ECU 2008
1 0 1 0 ECU 2008
0 0 3 2 BRA 2012
1 0 4 NA BRA 2012",
header = TRUE
)
重现错误:
class(df2$B) <- "anything"
当我执行以下操作时
df_merged <- rbindlist(list(df1, df2), fill=TRUE, use.names=TRUE)
数据集报错:
Error in rbindlist(list(df1, df2), fill = TRUE, use.names = TRUE) :
Class attribute on column 2 of item 2 does not match with column 2 of item 1.
我能做些什么:
- 使
rbindlist
跳过不匹配的列并添加一些后缀。 - 将其中一列的 class 更改为另一列。
选项 1 的预期结果:
df_merged <- fread(
"A B B.x C D E iso year
0 A NA 1 NA NA NLD 2009
1 Y NA 2 NA NA NLD 2009
0 Q NA 3 NA NA AUS 2011
1 NA NA 4 NA NA AUS 2011
0 0 NA 7 NA NA NLD 2008
1 1 NA 1 NA NA NLD 2008
0 1 NA 3 NA NA AUS 2012
0 NA 1 NA 1 NA ECU 2009
1 NA 0 NA 2 0 ECU 2009
0 NA 0 NA 3 0 BRA 2011
1 NA 0 NA 4 0 BRA 2011
0 NA 1 NA 7 NA ECU 2008
1 NA 0 NA 1 0 ECU 2008
0 NA 0 NA 3 2 BRA 2012
1 NA 0 NA 4 NA BRA 2012",
header = TRUE
)
选项 2 的预期结果:
df_merged <- fread(
"A B C D E iso year
0 3 1 NA NA NLD 2009
1 4 2 NA NA NLD 2009
0 5 3 NA NA AUS 2011
1 5 4 NA NA AUS 2011
0 0 7 NA NA NLD 2008
1 1 1 NA NA NLD 2008
0 1 3 NA NA AUS 2012
0 1 NA 1 NA ECU 2009
1 0 NA 2 0 ECU 2009
0 0 NA 3 0 BRA 2011
1 0 NA 4 0 BRA 2011
0 1 NA 7 NA ECU 2008
1 0 NA 1 0 ECU 2008
0 0 NA 3 2 BRA 2012
1 0 NA 4 NA BRA 2012",",
header = TRUE
)
我提出了这个不雅 解决方案来绕过这个问题。基本上,我所做的是将列表第一项的列的属性分配给与列表中所有其他项目同名的列。请记住,此解决方案存在问题,并且根据项目的不同,这可能是一种非常错误的做法,因为它有可能弄乱您的数据。但是,如果您需要的是使用 rbindlist
来组合您的数据帧,那么这就是诀窍
dfs <- list(df1, df2)
varnames <- names(dfs[[1]]) # variable names
vattr <- purrr::map_chr(varnames, ~class(dfs[[1]][[.x]])) # variable attributes
for (i in seq_along(dfs)) {
# assign the same attributes of list 1 to the rest of the lists
for (j in seq_along(varnames)) {
if (varnames[[j]] %in% names(dfs[[i]])) {
class(dfs[[i]][[varnames[[j]]]]) <- vattr[[j]]
}
}
}
df_merged <- data.table::rbindlist(dfs, fill=TRUE, use.names=TRUE)
最佳,
尝试 ldply(list, data.frame)
作为变通方法。为我工作,rbindlist() 不喜欢日期列。
@R.Andres Castaneda 的回答更不优雅的解决方案是:
当使用 fread
设置 colClasses = "character"
将所有内容强制转换为字符时,请执行 rbindlist
,然后选择您喜欢的方法,以便随后将所有内容强制转换回合理的状态。
它并不优雅,但我经常发现这是读取不一致数据时最简单的方法。