给定一个字符向量vars
和一个数据框列表d
,我想
确保d
中的每个数据框都包含vars
中指定的所有列。
假设一个数据框中缺少一些列,然后我创建
数据框中的这些列并用NA
s填充它们。
然而,当我使用assign
执行此操作时,我得到了一些奇怪的结果:
> vars <- c('y','z')
> b <- data.frame(a=1:3, b=3:1)
> b
a b
1 1 3
2 2 2
3 3 1
> within(b, for (v in vars) assign(v, NA))
a b z y v
1 1 3 NA NA z
2 2 2 NA NA z
3 3 1 NA NA z
您可以看到我设法使用此方法创建了列z
和y
,
但是还有一个额外的卷v
,我不知道它来自哪里。
答案 0 :(得分:2)
这是一种符合原始代码精神的简单方法。
for(v in vars) { b[[v]] <- NA }
您在版本中获得额外v
的原因是,在调用within
时创建的任何变量都会添加到该数据框中,而for循环会创建该变量。如果你在最后删除它会消失。但请注意,vars
变量包含v
。
within(b, {for (v in vars) assign(v, NA); rm(v) })
您也可以让vars
包含所有变量,然后获取您希望与setdiff
保持一致的变量。
vars <- c('a','b','y','z')
b <- data.frame(a=1:3, b=3:1)
for(v in setdiff(vars, names(b))) { b[[v]] <- NA }
答案 1 :(得分:1)
试试这个:
missingCols <- setdiff(vars, names(b))
naColumn <- function(x)rep(NA, nrow(b))
cbind(b, sapply(missingCols, naColumn, USE.NAMES=TRUE))
a b y z
1 1 3 NA NA
2 2 2 NA NA
3 3 1 NA NA
答案 2 :(得分:1)
您也可以尝试:
list2env(split(rep(NA,2*nrow(b)),vars),envir=.GlobalEnv)
cbind(b,mget(vars))
# a b y z
# 1 1 3 NA NA
# 2 2 2 NA NA
# 3 3 1 NA NA
或
cbind(b,mget(setdiff(vars,names(b))))
答案 3 :(得分:1)
此处使用data.table
:
require(data.table) ## 1.9.2+
setDT(b) ## convert data.frame to data.table
set(b, j=vars, value=NA_integer_)
# a b y z
# 1: 1 3 NA NA
# 2: 2 2 NA NA
# 3: 3 1 NA NA
请注意set*
(和data.table
运算符)中的所有:=
函数都按引用进行操作,这意味着此处没有(不必要的)副本。
如果您想使用data.frame
,则可以将其转换回data.frame
。在v1.9.3(当前正在开发的版本)中,有一个函数setDF
被实现为通过引用从data.frame
返回data.table
(相反)传统的as.data.frame(.)
功能,导致副本)。
全部放在一起(如果你想在最后data.frame
)
## 1.9.3
setDF(set(setDT(b), j=vars, value=NA_integer_))
# a b y z
# 1 1 3 NA NA
# 2 2 2 NA NA
# 3 3 1 NA NA
再一次,没有(深)副本。