【问题标题】:Applying a function on each row of a data frame in R在R中数据框的每一行上应用一个函数
【发布时间】:2011-04-08 17:34:09
【问题描述】:

我想对 R 中数据框的每一行应用一些函数。

该函数可以返回单行数据帧或什么都不返回(我猜'return()'什么都不返回?)。

我想将此函数应用于给定数据帧的每一行,并获得结果数据帧(可能比原始数据帧更短,即行数更少)。

例如,如果原始数据框类似于:

id size name
1  100  dave
2  200  sarah
3  50   ben

我正在使用的函数获取数据帧中的一行(即单行数据帧),如果名称与“勇敢”押韵,则按原样返回,否则返回 null,那么结果应该是:

id size name
1  100  dave

这个例子实际上是指过滤一个数据框,我很想得到一个特定于这种任务的答案,也想得到一个更一般的情况,即使是辅助函数的结果(在单个row) 可以是具有单行的任意数据框。请注意,即使在过滤的情况下,我也想使用一些复杂的逻辑(不是像$size>100 这样简单的东西,而是由函数检查的更复杂的条件,比如boo(single_row_df)

附: 到目前为止,在这些情况下我所做的是使用apply(df, MARGIN=1) 然后使用do.call(rbind ...) 但我认为当我的数据框只有一行时它会给我带来一些麻烦(我得到Error in do.call(rbind, filterd) : second argument must be a list

更新

在斯蒂芬回复之后,我做了以下事情:

ranges.filter <- function(ranges,boo) {
    subset(x=ranges,subset=!any(boo[start:end]))
}

然后我用一些看起来像这样的范围数据框调用ranges.filter

start end
100   200
250   400
698   1520
1988  2147
...

还有一些布尔向量

(TRUE,FALSE,TRUE,TRUE,TRUE,...)

我想从布尔向量中过滤掉任何包含 TRUE 值的范围。例如,如果布尔向量在100 .. 200 位置上的布尔向量为FALSE,则第一个范围100 .. 200 将留在数据框中。

这似乎可以完成工作,但我收到一条警告说numerical expression has 53 elements: only the first used

【问题讨论】:

    标签: r filter dataframe


    【解决方案1】:

    听起来你想使用subset

    subset(orig.df,grepl("ave",name))
    

    第二个参数的计算结果是一个逻辑表达式,用于确定保留哪些行。你可以让这个表达式使用任意多列的值,例如grepl("ave",name) &amp; size&gt;50

    【讨论】:

      【解决方案2】:

      您可能必须使用lapply 而不是apply 来强制结果为列表。

      > rhymesWithBrave <- function(x) substring(x,nchar(x)-2) =="ave"
      > do.call(rbind,lapply(1:nrow(dfr),function(i,dfr)
      +                      if(rhymesWithBrave(dfr[i,"name"])) dfr[i,] else NULL,
      +                      dfr))
        id size name
      1  1  100 dave
      

      但在这种情况下,subset 会更合适:

      > subset(dfr,rhymesWithBrave(name))
        id size name
      1  1  100 dave
      

      如果您想在返回结果之前执行额外的转换,您可以回到上面的lapply 方法:

      > add100tosize <- function(x) within(x,size <- size+100)
      > do.call(rbind,lapply(1:nrow(dfr),function(i,dfr)
      +                      if(rhymesWithBrave(dfr[i,"name"])) add100tosize(dfr[i,])
      +                      else NULL,dfr))
        id size name
      1  1  200 dave
      

      或者,在这个简单的例子中,将函数应用于subset的输出。

      > add100tosize(subset(dfr,rhymesWithBrave(name)))
        id size name
      1  1  200 dave
      

      更新:

      要选择不在开始和结束之间的行,您可以构造不同的函数(注意:布尔/逻辑向量求和结果时,TRUE 值转换为 1,FALSE 值转换为 0)

      test <- function(x)
        rowSums(mapply(function(start,end,x) x >= start & x <= end,
                       start=c(100,250,698,1988),
                       end=c(200,400,1520,2147))) == 0
      
      subset(dfr,test(size))
      

      【讨论】:

        【解决方案3】:

        对于处理数据帧的更一般情况,例如,从 CRAN 获取 plyr 包并查看 ddply 函数。

        install.packages(plyr)
        library(plyr)
        help(ddply)
        

        做你想做的事,无需大量的摆弄。

        例如...

        > d
            x          y           z xx
        1   1 0.68434946 0.643786918  8
        2   2 0.64429292 0.231382912  5
        3   3 0.15106083 0.307459540  3
        4   4 0.65725669 0.553340712  5
        5   5 0.02981373 0.736611949  4
        6   6 0.83895251 0.845043443  4
        7   7 0.22788855 0.606439470  4
        8   8 0.88663285 0.048965094  9
        9   9 0.44768780 0.009275935  9
        10 10 0.23954606 0.356021488  4
        

        我们要计算由“xx”定义的组内 x 的均值和标准差:

        > ddply(d,"xx",function(r){data.frame(mean=mean(r$x),sd=sd(r$x))})
          xx mean        sd
        1  3  3.0        NA
        2  4  7.0 2.1602469
        3  5  3.0 1.4142136
        4  8  1.0        NA
        5  9  8.5 0.7071068
        

        它可以优雅地处理所有有时让您感到困惑的讨厌的边缘情况。

        【讨论】:

        • 你能解释一下如何使用它吗? AFAICT,它适用于列,而不是行。
        • 软件包本身或其他地方的帮助中有很多关于 plyr 的文档。 ddply 函数接受一个数据框、一个分组变量和一个函数;它通过分组变量拆分数据帧,并在每次拆分时调用函数。然后将结果返回到数据框中。
        • 帮助实际上很短。如何将数据框拆分为行?我必须添加一个具有唯一 ID 的虚拟列吗?
        猜你喜欢
        • 1970-01-01
        • 2018-10-29
        • 2019-04-05
        • 2016-02-04
        • 2022-01-07
        • 1970-01-01
        • 2011-07-16
        • 2013-05-24
        • 1970-01-01
        相关资源
        最近更新 更多