Рассчитать процентное изменение во времени по групповой базе R - PullRequest
0 голосов
/ 05 сентября 2018

Ценю любую помощь в этом, я пытаюсь переучить некоторые основы.

Вот пример кода для работы с моей проблемой, он взят из базы данных пострадавших работников.

Area <- c("Connecticut", "Maine", "Massachusetts", "New Hampshire", "Texas", "Arizona", "California", "Washington")
Region <- c("Northeast", "Northeast", "Northeast", "Northeast", "South", "South", "West", "West") 
X2004 <- c(0,1,4,1,3,4,2,2)
X2005 <- c(1,0,6,2,0,1,0,2)
X2006 <- c(0,0,1,1,2,1,0,0) 
df1 <- data.frame(Area, Region, X2004, X2005, X2006) 

Я хотел бы показать процентное изменение от двухлетнего среднего за 2004-2005 гг. До единственного 2006 г. на базе R. Я смог решить эту проблему с помощью пакета Tidyverse, но похоже на использование костыля. Вот что у меня есть:

df2 <- reshape(df1, 
              idvar=c("Area"), 
              v.names="count",
              varying=c("X2004","X2005","X2006"), 
              direction="long",
              times=2004:2006, 
              timevar="year")
df3 <- df2 %>% group_by(Region, year) %>% 
summarise(total_count = sum(count)) 
df3$pre <- ifelse(df3$year<=2005, 1, 0)
df3 %>% 
group_by(Region) %>%  
summarise(mean_count_pre = mean(total_count[pre==1]),
        mean_count_post = mean(total_count[pre==0]), 
        pct_change = 100*(mean_count_post - mean_count_pre) / mean_count_pre) 

Любые идеи о том, как справиться с этим, не полагаясь на Tidyverse или Dplyr? По-настоящему ценю помощь в этом, я изучил R в Tidyverse, и я пытаюсь лучше понять основы.

Ответы [ 2 ]

0 голосов
/ 06 сентября 2018

Рассмотрим aggregate как замену group_by и summarise и использование двойных агрегатов для предварительных и последующих расчетов, объединенных в Регион . И within, и transform используются для назначения столбцов на месте, а setNames - для переименования столбцов, что невозможно сделать во время агрегации.

Tidyverse

df3 <- df2 %>% group_by(Region, year) %>% 
  summarise(total_count = sum(count)) 

df3$pre <- ifelse(df3$year<=2005, 1, 0)

aggdf <- df3 %>% 
  group_by(Region) %>%  
  summarise(mean_count_pre = mean(total_count[pre==1]),
            mean_count_post = mean(total_count[pre==0]), 
            pct_change = 100*(mean_count_post - mean_count_pre) / mean_count_pre) 

База R

df3_base <- setNames(aggregate(count~Region + year, df2, sum), 
                     c("Region", "year", "total_count"))

df3_base <- within(df3_base, {      
      pre <- ifelse(year <= 2005, 1, 0)
      count_pre <- ifelse(pre==1, total_count, NA)
      count_post <- ifelse(pre==0, total_count, NA)      
})

aggdf_base <- transform(setNames(merge(aggregate(count_pre ~ Region, df3_base, FUN = mean),
                                       aggregate(count_post ~ Region, df3_base, FUN = mean),
                                       by="Region"),
                                 c("Region", "mean_count_pre", "mean_count_post")),
                        pct_change = 100*(mean_count_post - mean_count_pre) / mean_count_pre)

Сравнение

identical(data.frame(aggdf), aggdf_base)
# [1] TRUE
0 голосов
/ 06 сентября 2018

Используя ваш df2 в качестве ввода, мы можем использовать только базовые функции R следующим образом:

> # creating `total_count`
> df3<- df2
> df3$total_count <- with(df2, ave(count, Region, year, FUN="sum"))
> 
> # creating `pre`
> df3$pre <- ifelse(df3$year<=2005, "pre", "post")
> 
> # creating "mean_count_pre" and "mean_count_post"
> output <- aggregate(total_count ~ Region+pre, data=df3, FUN="mean")
> colnames(output)[3] <- "mean_count"
> output_wide <- reshape(output, v.names="mean_count", idvar="Region", timevar = "pre", direction = "wide")
>
> # creating `pct_change`
> output_wide <- transform(output_wide, pct_change=(mean_count.post-mean_count.pre)/mean_count.pre)
> output_wide
     Region mean_count.post mean_count.pre pct_change
1 Northeast               2            7.5 -0.7333333
2     South               3            4.0 -0.2500000
3      West               0            3.0 -1.0000000
...