【问题标题】:R / using vectorization to check if columns in exist in a dfR /使用矢量化检查df中是否存在列
【发布时间】:2016-02-16 15:19:39
【问题描述】:

我已经定义了以下函数来检查数据框是否包含多个列,如果不包含则包含它们。

CheckFullCohorts <- function(df) {
  # Checks if year/cohort df contains all necessary columns 
  # Args:
  #  df: year/cohort df

  # Return:
  #  df: df, corrected if necessary 

  foo <- function(mydf, mystring) {
    if(!(mystring %in% names(mydf))) {
      mydf[mystring] <- 0
    }
    mydf
  }

  df <- foo(df, "age.16.20")
  df <- foo(df, "age.21.24")
  df <- foo(df, "age.25.49")
  df <- foo(df, "age.50.57")
  df <- foo(df, "age.58.65")
  df <- foo(df, "age.66.70")

  df
}

我会这样使用这个函数:

test <- data.frame(age.16.20 = rep("x", 5), lorem = rep("y", 5))

test <- CheckFullCohorts(test)

问题:如何通过使用列名向量进行检查,使函数的硬编码部分 (df &lt;- foo(...) 更加灵活?

我试过了:

CheckFullCohorts <- function(df, col.list) {
  # Checks if year/cohort df contains all necessary columns 
  # Args:
  #  df: year/cohort df
  #  col.list: named list of columns

  # Return:
  #  df: df, corrected if necessary 

  foo <- function(mydf, mystring) {
    if(!(mystring %in% names(mydf))) {
      mydf[mystring] <- 0
    }
    mydf
  }

  df <- sapply(df, foo, mystring = col.list) 

  df
}

...但我得到了错误的结果:

test <- data.frame(age.16.20 = rep("x", 5), lorem = rep("y", 5))
test <- CheckFullCohorts(test, c("age.16.20", "age.20.25"))

Warning messages:
1: In if (!(mystring %in% names(mydf))) { :
  the condition has length > 1 and only the first element will be used
2: In `[<-.factor`(`*tmp*`, mystring, value = 0) :
  invalid factor level, NA generated
3: In if (!(mystring %in% names(mydf))) { :
  the condition has length > 1 and only the first element will be used
4: In `[<-.factor`(`*tmp*`, mystring, value = 0) :
  invalid factor level, NA generated
> test
          age.16.20 lorem
          "x"       "y"  
          "x"       "y"  
          "x"       "y"  
          "x"       "y"  
          "x"       "y"  
age.16.20 NA        NA   
age.20.25 NA        NA  

【问题讨论】:

  • 如何将字符串向量S 传递给CheckFullCohort,然后用for(s in S){df &lt;- foo(df, s)} 替换相关行?
  • 当然可以。这是否意味着循环比矢量化解决方案更有效的情况之一?如果是的话,我仍然很想知道我的sapply 做错了什么。
  • 循环是否有效取决于每次交互时是否复制数据框,不知道这里会不会是这样。但是关于循环效率不高的讨论往往被夸大了:这一步是你代码中的瓶颈吗?如果没有,那不是您应该花费精力优化的地方。至于sapply,很好的问题——我倾向于使用plyr 来处理这些事情,界面对我来说更有意义。 PS,@Roland 下面的回答也可以,不需要函数!
  • 你的sapply 尝试的问题是你应该循环col.list 而不是df

标签: r vectorization sapply


【解决方案1】:

您可以轻松地将其矢量化:

test <- data.frame(age.16.20 = rep("x", 5), lorem = rep("y", 5))
musthaves <- c("age.16.20", "age.21.24", "age.25.49",
               "age.50.57", "age.58.65", "age.66.70")

test[musthaves[!(musthaves %in% names(test))]] <- 0
#  age.16.20 lorem age.21.24 age.25.49 age.50.57 age.58.65 age.66.70
#1         x     y         0         0         0         0         0
#2         x     y         0         0         0         0         0
#3         x     y         0         0         0         0         0
#4         x     y         0         0         0         0         0
#5         x     y         0         0         0         0         0

但是,通常NA 值比0 更合适。

【讨论】:

  • 哇,这真的很优雅。总的来说,我同意 NA 评论 - 在这种特定情况下,0 是我正在寻找的。​​span>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-28
  • 2019-03-26
  • 1970-01-01
  • 1970-01-01
  • 2020-03-28
  • 2019-03-25
  • 2016-09-09
相关资源
最近更新 更多