在R中的数据帧的每一行上应用函数

时间:2010-09-06 11:02:17

标签: r filter dataframe

我想在R中的数据帧的每一行上应用一些函数。

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

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

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

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

我正在使用的函数在数据帧中获取一行(即单行数据帧),如果名称与“brave”押韵,则返回原样,否则返回null,则结果应为:< / p>

id size name
1  100  dave

这个例子实际上是指对数据帧进行过滤,我希望得到一个特定于这种任务的答案,但也希望得到一个更一般的情况,即使是辅助函数的结果(在单个操作上的那个)行)可以是具有单行的任意数据帧。请注意,即使在过滤的情况下,我也想使用一些复杂的逻辑(不是像$size>100这样的简单逻辑,而是一个由函数检查的更复杂的条件,让我们说boo(single_row_df)。 / p>

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

更新

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

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

3 个答案:

答案 0 :(得分:4)

对于处理数据帧的更一般情况,例如从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的平均值和sd:

> 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

它优雅地处理了有时会让你感到困惑的所有令人讨厌的边缘情况。

答案 1 :(得分:1)

您可能必须使用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))

答案 2 :(得分:0)

听起来你想使用subset

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

第二个参数求值为一个逻辑表达式,用于确定保留哪些行。您可以使此表达式使用任意数量的列,例如grepl("ave",name) & size>50