代码之家  ›  专栏  ›  技术社区  ›  John_Doe

函数从数据帧中删除某些行

  •  0
  • John_Doe  · 技术社区  · 8 年前

    我试图编写一个函数,从数据帧中删除某些行。 为简单起见,我们假设移除的条件是行中至少有一个NA。

        df = data.frame(c("A","B","C"),c(1,NA,3))
    fn = function (d) {
    
      for (x in 1:nrow(d)) { for (y in 1:ncol(d)) {
    if(is.na(d[x,y])) d = d[-x,] 
     }}}
    
    fn(df)
    

    PS:我知道有更好的方法可以删除至少有一个NA的行,即df=df[-这(!complete.cases(df)],但我想找出我编写的代码不起作用的原因。

    2 回复  |  直到 8 年前
        1
  •  0
  •   Gavin Simpson    8 年前

    您需要显式返回 d 从您的功能

    df <- data.frame(X1 = c("A","B","C"), X2 = c(1,NA,3))
    fn <- function (d) {
      for (x in 1:nrow(d)) {
        for (y in 1:ncol(d)) {
          if(is.na(d[x,y])) d = d[-x,] 
        }
      }
    d # return d
    }
    
    fn(df)
    
    > fn(df)
      X1 X2
    1  A  1
    3  C  3
    

    R隐式返回最后一个操作的结果,但这是计算的结果 if (...) 对于第三行,返回 NULL

    > foo <- fn(df) # using your fn()
    > foo
    NULL
    

    您可以显式调用 return(d) 在函数的末尾,但as R也在调用 return() 在最后一句话中,这就像打电话 return(return(d)) . 因此,您可以使用 d 在函数的最后一行,R做了正确的事情。

    不使用的主要例外情况 return() (即,您应该何时使用它)处于您可能希望从函数中提前返回的情况。

    最后,与其在对象的行和列上循环,不如考虑按行工作。R是矢量化的,所以您可以 is.na() (例如)在整行上 if() 声明将是 if (any(is.na(d[i, ])) 哪里 i 是循环索引,例如:

    fn2 <- function (d) {
      for (i in 1:nrow(d)) {
        if (any(is.na(d[i,]))) {
          d <- d[-i, ]
        }
      }
    d # return d
    }
    
    > fn2(df)
      X1 X2
    1  A  1
    3  C  3
    

    甚至还有更有效的方法可以做到这一点,但如果您以矢量化的方式思考,您将开始编写更简单、更快的R代码。

        2
  •  0
  •   pietrodito    8 年前

    函数式编程风格

    我认为OP缺少的是不能修改作为参数直接传递的变量。这就是函数式编程风格。

    参观 https://en.wikipedia.org/wiki/Functional_programming

    事实上,函数体中的变量是作为参数传递的变量的副本。因此,您正在制作副本。

    这就是为什么必须返回副本并将其重新分配给变量的原因。

    df <- data.frame(X1 = c("A","B","C"), X2 = c(1,NA,3))
    fn <- function (d) {
            for (x in 1:nrow(d)) {
              for (y in 1:ncol(d)) {
                if(is.na(d[x,y])) d = d[-x,]}}
             d} # return d
    
    df <- fn(df)
    

    df 现在如OP所愿