Rollmean基于条件

时间:2017-02-20 16:19:15

标签: r zoo

根据下面的数据框,我想基于三个条件使用rollmean创建一个新列 - 列b中的值彼此匹配,列a中要平均的最小值是2,我只想要平均当前行以下的所有值。如果要平均的值的数量是2或更少,我想返回一个空白值。

我假设我必须使用apply函数来执行此操作,但我不知道从哪里开始。

a=c(1,2,3,4,1,2,3,4,1,2,3,4)
b=c("X","X","X","X","Y","Y","Y","Y","Z","Z","Z","Z")
df=as.data.frame(cbind(a,b))

我希望决赛桌看起来像:

Name    Value   Output
X        1         2.5
X        2         3
X        3  
X        4  
Y        1         2.5
Y        2         3
Y        3  
Y        4  
Z        1         2.5
Z        2         3
Z        3  
Z        4  

2 个答案:

答案 0 :(得分:3)

一个简单的tidverse解决方案。在每个组中,如果剩余的项目超过两个,请从当前索引(row_number())到最终索引(n())取平均值。

library(tidyverse)
df %>% 
  group_by(b) %>% 
  mutate(Output = map_dbl(row_number(), ~ifelse(n() - . < 3, NA, mean(a[.:n()]))))

数据

您创建数据的方式会将b强制转换为字符向量(因为cbind会生成矩阵)。

简单地使用:

a <- c(1,2,3,4,1,2,3,4,1,2,3,4)
b <- c("X","X","X","X","Y","Y","Y","Y","Z","Z","Z","Z")
df <- data.frame(a, b)

或者

df <- data.frame(a = 1:4, b = rep(c('X', 'Y', 'Z'), each = 4))

答案 1 :(得分:0)

请注意,问题中df的形成存在错误,因此我们在下面进行了修改。我们可以像这样使用ave。没有包使用。

df <- data.frame(a, b)
fun <- function(x) if (length(x) <= 2) NA else rev(cumsum(rev(x)) / c(NA, NA, 3:length(x)))
transform(df, Output = ave(a, b, FUN = fun))

,并提供:

   a b Output
1  1 X    2.5
2  2 X    3.0
3  3 X     NA
4  4 X     NA
5  1 Y    2.5
6  2 Y    3.0
7  3 Y     NA
8  4 Y     NA
9  1 Z    2.5
10 2 Z    3.0
11 3 Z     NA
12 4 Z     NA
相关问题