使用“滚动”分组进行分组后的摘要

时间:2019-02-11 17:28:03

标签: r

我想获得一个列,其中包含每个年龄段的滚动收入平均值,但要包括一岁以下的年龄段。例如,对于年龄为42和类型1的人,该类型必须使用年龄分别为41,42和43(如果有)的所有收入数据,依此类推。我想要一种系统的方法。

最小数据应如下所示:

Client Schema

我曾考虑过使用Zoo的rollapply,但这只是用于收入变量观测的顺序,而不是用于分组变量之一的值,而分组变量正是我要“滚动”的变量。

income <- c(1000, 2000, 3000, 4000, 6000, 7000, 8000, 9000, 10000, 11000) age <- c(41, 42, 42, 44, 45, 46, 47, 47, 49, 50) type <- c(1,1,2,2,1,2,1,2,1,1) df <- as.data.frame(cbind(income, age, type)) 排序,但以滚动方式将年龄分组(年龄1,年龄,年龄+1)。目的是使年龄的平均收入每三年重叠一次。当然,在年龄分布的尾部的两个年龄段的收入都将减少或根本没有增加。

谢谢!

P.S。我认为,预期结果将是这样(手动计算):

dplyr (group_by(type,age)) %>% summarize (avg=mean(income))

请注意,如果(年龄)和类型的每个(滚动)年龄的平均收入只有该年龄的所有三年中所有类型的收入都具有NA。 即使给定年龄的实际数据是NA,但如果观测值低于或低于该值,则将计算平均值(忽略NA)。

2 个答案:

答案 0 :(得分:1)

这是一种蛮力的tidyverse方法。

library(tidyverse)
df <- data.frame(income =  c(1000, 2000, 3000, 4000, 6000, 7000, 8000, 9000, 10000, 11000), 
                 age = c(41, 42, 42, 44, 45, 46, 47, 47, 49, 50),
                 type =  c(1,1,2,2,1,2,1,2,1,1))

指定每个滚动平均值中包含的年份,这里的意思是“包括上一年,下一年和下一年。”

yr_range = c(-1:1)   # same as c(-1, 0, 1)

使用yr_rangetidyr::uncount中的每个条目复制每一行,然后创建一个虚拟age_adj来调整每一行的年龄以将其移动到存储桶中以进行汇总:

df2 <- df %>%
  uncount(length(yr_range)) %>%
  mutate(age_adj = rep(yr_range, length.out = n()),
         age_bucket  = age + age_adj) %>%
# At this point it looks like:
#   income age type age_adj age_bucket
#1    1000  41    1      -1         40
#2    1000  41    1       0         41  
#3    1000  41    1       1         42
#4    2000  42    2      -1         41   
#5    2000  42    2       0         42
#6    2000  42    2       1         43
  group_by(type, age_bucket) %>%
  summarize(income_mean = mean(income)) %>%
  # optional, to prune edge years beyond orig data
  filter(age_bucket >= min(df$age),
         age_bucket <= max(df$age))

> df2
# A tibble: 18 x 3
# Groups:   type [2]
    type age_bucket income_mean
   <dbl>      <dbl>       <dbl>
 1     1         41        1500
 2     1         42        1500
 3     1         43        2000
 4     1         44        6000
 5     1         45        6000
 6     1         46        7000
 7     1         47        8000
 8     1         48        9000
 9     1         49       10500
10     1         50       10500
11     2         41        3000
12     2         42        3000
13     2         43        3500
14     2         44        4000
15     2         45        5500
16     2         46        8000
17     2         47        8000
18     2         48        9000

答案 1 :(得分:1)

创建类型/年龄网格<ItemsControl x:Class="Miotec.PressureMapping.UserControls.BaroLayerContainer" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:Miotec.PressureMapping.UserControls" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <ItemsControl.Resources> <Style TargetType="local:BaroLayerContainer"> <Setter Property="ItemsPanel"> <Setter.Value> <ItemsPanelTemplate> <Canvas Width="{Binding Parametros.Colunas}" Height="{Binding Parametros.Linhas}" IsItemsHost="True"/> </ItemsPanelTemplate> </Setter.Value> </Setter> </Style> </ItemsControl.Resources> <Viewbox Stretch="Uniform" x:Name="container"> <ItemsPresenter Width="{Binding ActualWidth, ElementName=container}" Height="{Binding ActualHeight, ElementName=container}"/> </Viewbox> </ItemsControl> 并将其与g合并,得到df。然后使用m通过ave运行rollapply

type

给予:

library(zoo)

g <- expand.grid(type = unique(df$type), age = seq(min(df$age), max(df$age)))
m <- merge(g, df, all.x = TRUE)
roll <- function(x) rollapply(x, 3, mean, na.rm = TRUE, partial = TRUE)
transform(m, avg = ave(income, type, FUN = roll))