在行组上应用data.frame消耗函数

时间:2016-09-12 13:16:02

标签: r

例如,假设我有一些data.frame df

df <- read.table(text = "
P    Q    R
c    1   10
a    1    0
a    2    0
b    2    0
b    1   10
c    2   10
b    1    0
a    2   10
",
stringsAsFactors = FALSE,
header=T)

...以及一些以foo为参数的函数data.frame

可以想象,根据其中一个列中的值dfdata.frame拆分为较小的P,并将foo应用于每个较小的data.frame foo

下面我展示了解决这个问题的最佳方法,但我怀疑已经存在更多简化的解决方案来执行这样的自然操作。如果是这样,我的问题是:他们是什么?

注意:我在下面显示了两个用例;两者中的第一个是我期望可以显着改善的那个。至于第二个,我认为我的解决方案可能已经达到了它的最佳状态;我包括这个用例,以防万一我猜错了。

我的解决方案取决于foo是否是我为其返回值调用的函数,或者是我仅为其副作用调用的函数。

对于前一种情况(foo调用其值),假设## returns a one-row data.frame corresponding to a random row of ## dataframe ## NB: this is *just an example* for the sake of this question foo <- function (dataframe) { dataframe[sample(nrow(dataframe), 1), ] } 是这样的:

set.seed(0)
sapply(unique(df$P), function (value) foo(df[df$P == value, ]),
       simplify = FALSE)
## $c
##   P Q  R
## 6 c 2 10
## 
## $a
##   P Q R
## 2 a 1 0
## 
## $b
##   P Q  R
## 5 b 1 10

...那么我的解决方案就是:

foo

对于后一种情况(foo要求其副作用),假设## prints to stdout a one-row data.frame corresponding to a random ## row of dataframe ## NB: this is *just an example* for the sake of this question foo <- function (dataframe) { cat(str(dataframe[sample(nrow(dataframe), 1), ])) } 是这样的:

set.seed(0)
for (value in unique(df$P)) foo(df[df$P == value, ])
## 'data.frame':    1 obs. of  3 variables:
##  $ P: chr "c"
##  $ Q: int 2
##  $ R: int 10
## 'data.frame':    1 obs. of  3 variables:
##  $ P: chr "a"
##  $ Q: int 1
##  $ R: int 0
## 'data.frame':    1 obs. of  3 variables:
##  $ P: chr "b"
##  Q: int 1
##  R: int 10

...那么我的解决方案就是:

class Variable{
   String name
   def value
}

1 个答案:

答案 0 :(得分:1)

您可以使用函数by实现两个用例。但是,要复制结果,我们会更改您的函数以返回或输出组的最后一行而不是随机选择的行。这是必要的,因为组内行的排序由by修改。在实际用例中,这种排序无关紧要。 only 很重要,因为您的结果取决于随机数生成器在分组行上进行选择。

在您的第一个用例中:

foo <- function (dataframe) {
  dataframe[nrow(dataframe), ]
}

out1 <- sapply(unique(df$P), function (value) foo(df[df$P == value, ]),
               simplify = FALSE)

结果out1list

str(out1)  ## this displays the structure of the out1 object
##List of 3
## $ c:'data.frame':    1 obs. of  3 variables:
##  ..$ P: chr "c"
##  ..$ Q: int 2
##  ..$ R: int 10
## $ a:'data.frame':    1 obs. of  3 variables:
##  ..$ P: chr "a"
##  ..$ Q: int 2
##  ..$ R: int 10
## $ b:'data.frame':    1 obs. of  3 variables:
##  ..$ P: chr "b"
##  ..$ Q: int 1
##  ..$ R: int 0

我们可以使用by获得相同的结果,它返回类by的对象,即list

by.out1 <- with(df, by(df, P, foo))
str(by.out1)
##List of 3
## $ a:'data.frame':    1 obs. of  3 variables:
##  ..$ P: chr "a"
##  ..$ Q: int 2
##  ..$ R: int 10
## $ b:'data.frame':    1 obs. of  3 variables:
##  ..$ P: chr "b"
##  ..$ Q: int 1
##  ..$ R: int 0
## $ c:'data.frame':    1 obs. of  3 variables:
##  ..$ P: chr "c"
##  ..$ Q: int 2
##  ..$ R: int 10
## - attr(*, "dim")= int 3
## - attr(*, "dimnames")=List of 1
##  ..$ P: chr [1:3] "a" "b" "c"
## - attr(*, "call")= language by.data.frame(data = df, INDICES = P, FUN = foo)
## - attr(*, "class")= chr "by"

在这里,我们使用bywithby构建的环境中执行df。这允许我们按名称指定df(例如P)的列而不带引号。

对于您的第二个用例(通过cat显示到控制台):

foo <- function (dataframe) {
  cat(str(dataframe[nrow(dataframe), ]))
}

for (value in unique(df$P)) foo(df[df$P == value, ])
##'data.frame': 1 obs. of  3 variables:
## $ P: chr "c"
## $ Q: int 2
## $ R: int 10
##'data.frame': 1 obs. of  3 variables:
## $ P: chr "a"
## $ Q: int 2
## $ R: int 10
##'data.frame': 1 obs. of  3 variables:
## $ P: chr "b"
## $ Q: int 1
## $ R: int 0

同样,我们可以使用by

获得相同的结果
with(df, by(df, P, foo))
##'data.frame': 1 obs. of  3 variables:
## $ P: chr "a"
## $ Q: int 2
## $ R: int 10
##'data.frame': 1 obs. of  3 variables:
## $ P: chr "b"
## $ Q: int 1
## $ R: int 0
##'data.frame': 1 obs. of  3 variables:
## $ P: chr "c"
## $ Q: int 2
## $ R: int 10

函数by位于base R包中。正如Dave2e所提到的,还有许多其他包具有类似的数据操作功能。其中一些提供了更多的语法糖,易于使用,而另一些提供更好的优化,或两者兼而有之。其中一些是:plyrdplyrdata.table。我留给你探索这些。