Итеративное деление на значение, заданное несколькими измерениями dplyr R

#r #dplyr

Вопрос:

У меня есть фрейм данных, который включает данные о населении за несколько лет и географические данные. Выглядит примерно так:

 
df <- tibble(YEAR = c("2015", "2015", "2016", "2016", "2017", "2017", "2018", "2018"), 
           LOCATION = c("a", "b", "a", "b", "a", "b", "a", "b"), 
           POPULATION = c(2, 3, 4, 3, 6, 6, 7, 9))

df
# A tibble: 8 x 3
YEAR  LOCATION POPULATION
<chr> <chr>         <dbl>
1 2015  a                 2
2 2015  b                 3
3 2016  a                 4
4 2016  b                 3
5 2017  a                 6
6 2017  b                 6
7 2018  a                 7
8 2018  b                 9
 

Теперь я хочу рассчитать численность населения для каждого местоположения относительно первого года (таким образом, численность населения за 2015 год = 1).

По сути, я хочу разделить население за каждый год на население за первый год (или другой данный год).

Это было бы довольно просто, если бы данные были просто сгруппированы по годам. Я бы просто назвал конкретный первый год (2015 в этом репрексе). Я бы mutate и сделал свою новую переменную RELATIVE_POPULATION = POPULATION/(POPULATION[YEAR == "2015"]) такой:

 df_year <- df %>%
group_by(YEAR) %>%
summarise(POPULATION = sum(POPULATION)) %>%
mutate(RELATIVE_POPULATION = POPULATION/(POPULATION[YEAR == "2015"]))

df_year

# A tibble: 4 x 3
YEAR  POPULATION RELATIVE_POPULATION
<chr>      <dbl>               <dbl>
1 2015           5                 1  
2 2016           7                 1.4
3 2017          12                 2.4
4 2018          16                 3.2
 

Но я хочу сделать это для каждого местоположения, чтобы получить результат, который выглядел бы следующим образом (таким образом, все популяции местоположения a делятся на население местоположения a в 2015 году, а все популяции местоположения b делятся на население местоположения b в 2015 году).

 YEAR  LOCATION POPULATION    RELATIVE_POPULATION
<chr> <chr>         <dbl>   <dbl> 
1 2015  a                 2   1
2 2015  b                 3   1
3 2016  a                 4   2
4 2016  b                 3   1
5 2017  a                 6   3
6 2017  b                 6   2
7 2018  a                 7   3.5
8 2018  b                 9   3
 

Я думаю, что могу использовать подмножество case_when для расчета за каждый год, но я не знаю, как указать значение для операции на основе двух других измерений. Я пытался

 df_relative <- df %>% 
  mutate(
    RELATIVE_POPULATION = case_when(
      LOCATION == "a" ~ POPULATION/(POPULATION[YEAR == "2015", LOCATION == "a"]),
      LOCATION == "b" ~ POPULATION/(POPULATION[YEAR == "2015", LOCATION == "b"])
    ))
 

но это возвращает ошибку Error in POPULATION[YEAR == "2015", LOCATION == "a"] : incorrect number of dimensions

Итак, можно ли здесь указать два измерения, и если да, то как?

Один полезный человек (@MikeMahoney218 в Twitter) хитро предложил мне создать второй tibble, который имеет значения 2015 года для каждого местоположения, а затем я объединю их вместе, как показано ниже:

 original_pop <- df %>% 
  group_by(LOCATION) %>%
  filter(YEAR == 2015) %>% 
  select(LOCATION, INITIAL_POP = POPULATION)

df %>% 
  left_join(original_pop) %>%
  mutate(RELATIVE_POP = POPULATION / INITIAL_POP)

df
# A tibble: 8 x 5
  YEAR  LOCATION POPULATION INITIAL_POP RELATIVE_POP
  <chr> <chr>         <dbl>       <dbl>        <dbl>
1 2015  a                 2           2          1  
2 2015  b                 3           3          1  
3 2016  a                 4           2          2  
4 2016  b                 3           3          1  
5 2017  a                 6           2          3  
6 2017  b                 6           3          2  
7 2018  a                 7           2          3.5
8 2018  b                 9           3          3  
 

Это работает (да), но есть ли способ сделать это без создания второго фрейма данных? Я видел, что это может усложняться по мере умножения кода.

Ответ №1:

Создайте группу по «МЕСТОПОЛОЖЕНИЮ», подмножеству «НАСЕЛЕНИЕ», где YEAR находится 2015 год, и разделите НАСЕЛЕНИЕ

 library(dplyr)
df <- df %>% 
    group_by(LOCATION) %>%
    mutate(RELATIVE_POPULATION = POPULATION/POPULATION[YEAR == 2015] ) %>%
    ungroup
 

-выход

 df
# A tibble: 8 x 4
  YEAR  LOCATION POPULATION RELATIVE_POPULATION
  <chr> <chr>         <dbl>               <dbl>
1 2015  a                 2                 1  
2 2015  b                 3                 1  
3 2016  a                 4                 2  
4 2016  b                 3                 1  
5 2017  a                 6                 3  
6 2017  b                 6                 2  
7 2018  a                 7                 3.5
8 2018  b                 9                 3  
 

ПРИМЕЧАНИЕ: Когда мы используем == , убедитесь, что для каждого «МЕСТОПОЛОЖЕНИЯ» есть только одно совпадение, иначе мы должны получить первый элемент, т. Е. match(2015, YEAR)

Комментарии:

1. Ну а теперь я чувствую себя очень глупо. Я не думаю, что раньше осознавал, что могу ungroup так без потерь! Спасибо