从data.frame提取时用NA填充缺少的列
我有一个函数,它将带有特定列的数据帧作为输入从data.frame提取时用NA填充缺少的列,r,dataframe,R,Dataframe,我有一个函数,它将带有特定列的数据帧作为输入 columns =['a', 'b',...,'z'] 现在我有了一个数据帧DF,其中只有很少的列DF_columns=['f','u','z'] 如果列不在DF中,并且与['f'、'u'、'z']列上的DF一致,如何创建一个包含所有值为NA的列的数据帧 例如: d = data.frame('g'=c(1,2,3), 's' = c(4,2,3)) columns = letters[1:21] columns [1] "a" "b" "c"
columns =['a', 'b',...,'z']
现在我有了一个数据帧DF
,其中只有很少的列DF_columns=['f','u','z']
如果列不在DF
中,并且与['f'、'u'、'z']列上的DF
一致,如何创建一个包含所有值为NA的列的数据帧
例如:
d = data.frame('g'=c(1,2,3), 's' = c(4,2,3))
columns = letters[1:21]
columns
[1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t"
[21] "u"
> d
g s
1 1 4
2 2 2
3 3 3
>
设置:
以下是一些方法及其时间安排
createDF1 <- function(colVec, data)
{
m <- matrix(, nrow = nrow(data), ncol = length(colVec),
dimnames = list(NULL, colVec))
m[, names(data)] <- as.matrix(data)
data.frame(apply(m, 2, as.numeric))
}
createDF2 <- function(colVec, data)
{
rr <- setNames(rep(list(rep(NA_integer_, nrow(data))), length(colVec)), .
nm = colVec)
rr[match(names(data), colVec)] <- data
as.data.frame(rr)
}
createDF3 <- function(colVec, data)
{
rr <- setNames(replicate(length(colVec),
list(rep(NA_integer_, nrow(data)))),
nm = colVec)
rr[match(names(d), colVec)] <- data
as.data.frame(rr)
}
在这三种方法中,它看起来像是rep(list(list)(rep(NA_integer,nrow(data)))、length(columns))
,并替换其中的值 使用数据,这非常简单(语法方面)且高效(速度方面)。表包:
require(data.table) ## 1.9.2+
setDT(d)[, setdiff(columns, names(d)) := NA] ## (1)
setcolorder(d, columns) ## (2)
setDF(d) ## (3)
setDT
将d
转换为data.table
,然后使用:=
操作符通过引用创建新列。有很多方法可以使用:=
,但这里突出显示的是用例LHS:=RHS
。这里,LHS
是列名向量,RHS
是值<代码>NA
仅在RHS上提供一次,可自动回收用于所有其他列。请注意,NA
默认情况下是R中的逻辑类型
如果需要,您可以使用setcolorder
按与列相同的顺序对d
的列重新排序
同样,如果需要,可以使用函数setDF
将data.table
转换回data.frame,该函数再次通过引用修改对象。但它现在只在美国上市
x.or.na您没有使用[
括号在R中创建向量。我只是在写伪代码。我希望这不会导致误解。请尽量让这个问题更具可复制性,毕竟这不是您第一次发布问题……我在您的ifelse
中添加了一个示例,长度(字母)%in%colnames(DF)
中的%in不等于length(DF)
,因此,如果回收后得到预期的结果,这只是运气。请参阅关于用字母替换字母[4:26]
例如。cbind
还强制所有数据为同一类型,这不是一件好事。@flodel,哎呀,我没有注意到。非常感谢您指出这一点。还是有什么问题(对不起…),尝试添加DF$k您的解决方案假设了DF
中列的顺序;我建议在创建后添加DF$k,因此k
是最后一列,但您可以尝试DFcreateDF2
速度很快,因为列表中的每个元素都指向相同的值。只为第一列进行分配时间。其余的都是浅层复制的。执行:.Internal(检查(rep(list)(rep(NA,10)),5))
并检查地址。他们每个人都是相同的。这不是很快,只是将耗时的操作(内存分配)推迟到下一步。如果你不使用它(直接写入文件),这是很有利的.但我怀疑这是经常发生的情况。我在它上面做了一个Rprof
,除了print
和它的方法之外没有什么。它的速度很快,至少部分是因为我用NA\u integer\uu
创建了新结构,而不是NA
(逻辑).嗯,也许..也许不是.:-)我不知道你想用Rprof
说什么。NAs的分配只发生一次(即,一个大小为300万整数的向量被分配一次)。不是21次。因此,我对几乎没有显示的Rprof
并不感到惊讶。而且,您认为将NA
更改为NA_整数
,会使代码更快吗?它们都需要4字节的存储空间。检查时间:system.time(rep(NA_整数,3e6))
与system.time(rep(list)(rep(NA_integer,3e6)),300L))
。在我的系统上需要0.007对0.007。除非它们只是浅拷贝,否则这怎么可能发生…:)(就像Rv3.1+那样)。
set.seed(1)
DF_all <- setNames(data.frame(matrix(rnorm(5*26), nrow=5, ncol=26)), letters)
DF <- DF_all[, c('f','u','z')]
DF2 <- setNames(data.frame(matrix(nrow=5, ncol=26)), letters)
DF2[, c('f','u','z')] <- DF[, c('f','u','z')]
> DF2
a b c d e f g h i j k l m n o p q r s t u v w x y z
1 NA NA NA NA NA -0.05612874 NA NA NA NA NA NA NA NA NA NA NA NA NA NA -0.62036668 NA NA NA NA 0.71266631
2 NA NA NA NA NA -0.15579551 NA NA NA NA NA NA NA NA NA NA NA NA NA NA 0.04211587 NA NA NA NA -0.07356440
3 NA NA NA NA NA -1.47075238 NA NA NA NA NA NA NA NA NA NA NA NA NA NA -0.91092165 NA NA NA NA -0.03763417
4 NA NA NA NA NA -0.47815006 NA NA NA NA NA NA NA NA NA NA NA NA NA NA 0.15802877 NA NA NA NA -0.68166048
5 NA NA NA NA NA 0.41794156 NA NA NA NA NA NA NA NA NA NA NA NA NA NA -0.65458464 NA NA NA NA -0.32427027
createDF1 <- function(colVec, data)
{
m <- matrix(, nrow = nrow(data), ncol = length(colVec),
dimnames = list(NULL, colVec))
m[, names(data)] <- as.matrix(data)
data.frame(apply(m, 2, as.numeric))
}
createDF2 <- function(colVec, data)
{
rr <- setNames(rep(list(rep(NA_integer_, nrow(data))), length(colVec)), .
nm = colVec)
rr[match(names(data), colVec)] <- data
as.data.frame(rr)
}
createDF3 <- function(colVec, data)
{
rr <- setNames(replicate(length(colVec),
list(rep(NA_integer_, nrow(data)))),
nm = colVec)
rr[match(names(d), colVec)] <- data
as.data.frame(rr)
}
columns <- letters[1:21]
d <- data.frame(g = 1:3e6L, s = 1:3e6L, j = 1:3e6L)
system.time({ createDF1(columns, d) })
# user system elapsed
# 5.022 1.023 6.054
system.time({ createDF2(columns, d) })
# user system elapsed
# 0.007 0.004 0.011
system.time({ createDF3(columns, d) })
# user system elapsed
# 0.105 0.077 0.183
require(data.table) ## 1.9.2+
setDT(d)[, setdiff(columns, names(d)) := NA] ## (1)
setcolorder(d, columns) ## (2)
setDF(d) ## (3)
x.or.na <- function(x, df) if (x %in% names(df)) df[[x]] else NA
as.data.frame(Map(x.or.na, columns, list(d)))