r语言 - 如何在dplyr中对分组元素应用函数,同时保留部分数据



问题总结

目前,我正试图应用一个以某种方式计算滞后数据的函数,这个函数必须应用于各种组集,我似乎无法用Dplyr来解决这个问题。

<标题>

预期结果作为一个例子,数据看起来像这样:

date group value
1 Jan 1     A     0
2 Feb 1     A     1
3 Mar 1     A     0
4 Jan 1     B     2
5 Feb 1     B     4
6 Mar 1     B     0

我们的想法是得到这样的输出,例如2个月的滚动平均值:

date group value roll_mean
1 Feb 1     A     1       0.5
2 Mar 1     A     0       0.5
3 Feb 1     B     4         3
4 Mar 1     B     0         2
<标题>

可再生的例子我准备了一个例子,在R中可用,与数据和一个函数,为了这个例子:

data <- data.frame(
date = as.yearmon(
as.Date(
c("01/01/2020", "01/02/2020", "01/03/2020", "01/01/2020", "01/02/2020", "01/03/2020"),
origin = "1970-01-01")
),
group = c("A", "A", "A", "B", "B", "B"),
value = c(0, 1, 0, 2, 4, 0)
)
computing_function <- function(data) {
output_data <- data %>% 
mutate(
roll_mean = rollmean(data$value, k = 2, fill = NA, align="right")
) %>% 
drop_na(roll_mean)
return (output_data)
}
<标题>

我知道如何使用循环来实现它,但是这将是耗时的,不可靠的,并且维护起来很痛苦。例如,组的输出可以工作。然而,我不能使它在Dplyr内工作,即使使用summarise()。我的逻辑中缺少了一些东西,我不能准确地指出是什么。

computing_function(data %>% filter(group == "B"))
#    date group value roll_mean
# 1 Feb 1     B     4         3
# 2 Mar 1     B     0         2
data %>%
group_by(group) %>% 
summarise(computing_function(.))
# Error

是否有一种方法可以做到这一点呢?

函数的逻辑应该保留在其中,而不是将其偏移到dplyr表达式。

包使用:

  • Dplyr
  • 动物园

summarise不是正确的函数,因为它每组返回一行。此外,你的函数得到一个数据帧作为输入,这将不会在summarisemutate内工作。你要么想要这样的东西,它接受一个向量作为输入:

computing_function1 <- function(values) {
rollmean(values, k = 2, fill = NA, align="right")
}
data %>%
group_by(group) %>% 
mutate(roll_mean = computing_function1(value)) %>% 
filter(!is.na(roll_mean))

或者如果你真的想保持相同的结构,你必须拆分数据集,在"组"上应用函数并重新组装数据集:

data %>%
split(.$group) %>% 
map_dfr( computing_function ) 

这种情况的答案可以在Dplyr的modify_by函数文档中找到。它是一个purrr风格的函数,允许在数据帧上使用函数(通过扩展可以使用标题)。

这个函数允许输入是一个点状图,输出是一个分组点状图。下面是用Dplyr代码和逻辑给出的答案:

data %>%
group_by(group) %>% 
group_modify(~computing_function(.x))
# # A tibble: 4 x 4
# # Groups:   group [2]
#   group date      value roll_mean
#   <chr> <yearmon> <dbl>     <dbl>
# 1 A     Feb 1         1       0.5
# 2 A     Mar 1         0       0.5
# 3 B     Feb 1         4       3  
# 4 B     Mar 1         0       2 

您可以在group_modify()表达式之后使用ungroup()来输出一个非分组的标题,以便在需要时传递给其他函数。

1)使用read.zoodata转换为一个宽窗体动物园对象,其中每个日期有一行,每个组有一列。然后使用rollmeanr(与rollmean相同,默认为align="right"),创建一个以原始值为实部,均值为虚部的复杂对象。使用增强。把它融回一个长形式的数据框架并提取出实部和虚部。这里只使用磁力管道和动物园。

data %>%
read.zoo(split = "group") %>%
{ fortify.zoo(. + rollmeanr(., 2) * 1i, melt = TRUE, names = names(data)) } %>%
transform(value = Re(value), rollmean = Im(value))

给:

date group value rollmean
1 Feb 0001     A     1      0.5
2 Mar 0001     A     0      0.5
3 Feb 0001     B     4      3.0
4 Mar 0001     B     0      2.0

2)上述内容的一个变体如下。它计算均值的宽范围对象,然后将其转换回长格式数据帧,并将值列合并回去。如果不需要结果中的value列,可以省略最后一行代码;如果使用一个zoo object of means就足够了,可以省略最后第二行代码。

data %>%
read.zoo(split = "group") %>%
rollmeanr(2) %>%
fortify.zoo(melt = TRUE, names = c(names(data)[1:2], "rollmean")) %>%
merge(data, ., by = 2:1)

最新更新