在dplyr
中,我想对我之前选择的组应用一个条件函数。但是,始终为完整数据计算函数。一个最小的例子:
func_a = function(data_a) {
value = mean(data_a$V2)
return(value)
}
data = as.data.frame(cbind(c("a","a","a","b","b","b"), c(1,2,3,4,5,6)))
data$V2=as.numeric(data$V2)
data V1 V2 a 1 a 2 a 3 b 4 b 5 b 6
o = data %>% group_by(V1) %>% dplyr::mutate(test = func_a(.))
o$test
[1] 3.5 3.5 3.5 3.5 3.5 3.5
我希望/希望:
[1] 2 2 2 5 5 5
平均函数是一个原始的例子,dplyr::mutate(test = mean(V2))
可以清楚地完成工作。但是,还有其他功能无法像这样使用。
这个问题的主要内容是如何将数据帧的一部分转移到一个函数而不是整个函数。
答案 0 :(得分:1)
正如@DavidArenburg评论的那样,你的函数的工作方式不是.
的工作方式。 %>%
明确表示通过data %>%
group_by(V1) %>%
mutate(eg = mean(V2) / mean(.$V2))
传递的完整变量(在本例中为data.frame)。如果我想在完整数据上做一些事情,那么我偶尔也会使用这个hack,例如。
V1 V2 eg
<fctr> <dbl> <dbl>
1 a 1 0.5714286
2 a 2 0.5714286
3 a 3 0.5714286
4 b 4 1.4285714
5 b 5 1.4285714
6 b 6 1.4285714
给出
mutate
因此,让func_forColumn = function(data_a) {
value = mean(data_a)
return(value)
}
data %>%
group_by(V1) %>%
mutate(test = func_forColumn(V2))
应用分组的最佳解决方案是传递列名,例如,
V1 V2 test
<fctr> <dbl> <dbl>
1 a 1 2
2 a 2 2
3 a 3 2
4 b 4 5
5 b 5 5
6 b 6 5
给出
split
如果你真的需要能够传入完整的data.frame(例如,你正在处理为旧范例编写的函数,并且由于某些原因无法更新它们),你可以使用{{1} } / lapply
就像我假设您习惯的那样,然后只是bind_rows
结果,如下所示:
data %>%
split(.$V1) %>%
lapply(function(x){
x %>%
mutate(test = func_a(.))
}) %>%
bind_rows()
给出了
V1 V2 test
1 a 1 2
2 a 2 2
3 a 3 2
4 b 4 5
5 b 5 5
6 b 6 5
或者,您可以使用do
,这允许更复杂的分组/摘要输出。这旨在允许data.frames中的多列返回,但可以根据您的场景进行调整:
data %>%
group_by(V1) %>%
do(as.data.frame(func_a(.)))
给出
V1 `func_a(.)`
<fctr> <dbl>
1 a 2
2 b 5
请注意,它每组只返回一行。因此,如果您希望每个原始条目有一行,则需要对原始数据使用连接(例如left_join
)。
以下是使用do
的一个更典型的示例,它可能与您的函数首先期望完整data.frame的原因更密切相关。
mySummary <- function(x){
as.data.frame(rbind(summary(x)))
}
data %>%
group_by(V1) %>%
do(mySummary(.$V2))
给出
V1 Min. `1st Qu.` Median Mean `3rd Qu.` Max.
<fctr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 a 1 1.5 2 2 2.5 3
2 b 4 4.5 5 5 5.5 6