从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
    是最后一列,但您可以尝试
    DF
    createDF2
    速度很快,因为列表中的每个元素都指向相同的值。只为第一列进行分配时间。其余的都是浅层复制的。执行:
    .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)))