例如,假设我有一些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
。
可以想象,根据其中一个列中的值df
将data.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
}
答案 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)
结果out1
是list
:
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"
在这里,我们使用by
和with
在by
构建的环境中执行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所提到的,还有许多其他包具有类似的数据操作功能。其中一些提供了更多的语法糖,易于使用,而另一些提供更好的优化,或两者兼而有之。其中一些是:plyr
,dplyr
和data.table
。我留给你探索这些。