R Studio: Как выполнить отдельные процедуры преобразования данных для разных значений переменной в список отдельных фреймов данных?

У меня есть фрейм данных, который выглядит так:

+-----------+------------+--------+------------+
| Geography | Dates      | Sales  | Avg_Volume |
+-----------+------------+--------+------------+
| A         | 2020-01-01 |        |            |
+-----------+------------+--------+------------+
| A         | 2020-01-02 |        |            |
+-----------+------------+--------+------------+
| A         | 2020-01-03 |        |            |
+-----------+------------+--------+------------+
| A         | 2020-01-04 |        |            |
+-----------+------------+--------+------------+
| A         | 2020-01-05 |        |            |
+-----------+------------+--------+------------+
| B         | 2020-01-01 |        |            |
+-----------+------------+--------+------------+
| B         | 2020-01-02 |        |            |
+-----------+------------+--------+------------+
| B         | 2020-01-03 |        |            |
+-----------+------------+--------+------------+
| B         | 2020-01-04 |        |            |
+-----------+------------+--------+------------+
| B         | 2020-01-05 |        |            |
+-----------+------------+--------+------------+
| C         | 2020-01-01 |        |            |
+-----------+------------+--------+------------+
| C         | 2020-01-02 |        |            |
+-----------+------------+--------+------------+
| C         | 2020-01-03 |        |            |
+-----------+------------+--------+------------+
| C         | 2020-01-04 |        |            |
+-----------+------------+--------+------------+
| C         | 2020-01-05 |        |            |
+-----------+------------+--------+------------+
| D         | 2020-01-01 |        |            |
+-----------+------------+--------+------------+
| D         | 2020-01-02 |        |            |
+-----------+------------+--------+------------+
| D         | 2020-01-03 |        |            |
+-----------+------------+--------+------------+
| D         | 2020-01-04 |        |            |
+-----------+------------+--------+------------+
| D         | 2020-01-05 |        |            |
+-----------+------------+--------+------------+

Я хотел бы иметь 3 фрейма данных, посвященных городам B, C, D, которые выглядят следующим образом (мне нужно, чтобы A_Sales всегда присутствовали:

+------------+----------+---------+--------------+
| Dates      | A_Sales  | B_Sales | B_Avg_Volume |
+------------+----------+---------+--------------+
| 2020-01-01 |          |         |              |
+------------+----------+---------+--------------+
| 2020-01-02 |          |         |              |
+------------+----------+---------+--------------+
| 2020-01-03 |          |         |              |
+------------+----------+---------+--------------+
| 2020-01-04 |          |         |              |
+------------+----------+---------+--------------+
| 2020-01-05 |          |         |              |
+------------+----------+---------+--------------+
+------------+----------+---------+--------------+
| Dates      | A_Sales  | C_Sales | C_Avg_Volume |
+------------+----------+---------+--------------+
| 2020-01-01 |          |         |              |
+------------+----------+---------+--------------+
| 2020-01-02 |          |         |              |
+------------+----------+---------+--------------+
| 2020-01-03 |          |         |              |
+------------+----------+---------+--------------+
| 2020-01-04 |          |         |              |
+------------+----------+---------+--------------+
| 2020-01-05 |          |         |              |
+------------+----------+---------+--------------+
+------------+----------+---------+--------------+
| Dates      | A_Sales  | D_Sales | D_Avg_Volume |
+------------+----------+---------+--------------+
| 2020-01-01 |          |         |              |
+------------+----------+---------+--------------+
| 2020-01-02 |          |         |              |
+------------+----------+---------+--------------+
| 2020-01-03 |          |         |              |
+------------+----------+---------+--------------+
| 2020-01-04 |          |         |              |
+------------+----------+---------+--------------+
| 2020-01-05 |          |         |              |
+------------+----------+---------+--------------+

На данный момент это то, что у меня есть:

data_A <- data %>% 
  filter(Geography == "A") %>% 
  rename("A_Sales" = Sales) %>% 
  select(Dates, A_Sales)


data_B <- data %>% 
  filter(Geography == 'B') %>% 
  rename("B_Sales" = Sales)%>%
  rename("B_Avg_Volume" = Avg_Volume)%>%
  select(Dates, B_Sales, B_Avg_Volume)

data_a_n_b <- data_A %>% 
  left_join(data_B, by = 'Dates') 

Это очень избыточно и неэффективно, потому что мне приходилось бы каждый раз менять Geography == '...') на "B,C,D..." и запускать заново. Мои реальные данные содержат ~ 50 городов, поэтому для меня нереально проводить этот процесс для каждого города индивидуально.

Что представляет собой элегантный способ пакетной обработки этого процесса?

Я предполагаю, что конечный результат будет списком фреймов данных для городов B, C, D ... и так далее, причем имя каждого отдельного фрейма данных будет названием города. Таким образом, я могу легко получить доступ к каждому индивидуальному фрейму данных. Например, вызов data_result$C (или что-то подобное) даст мне фрейм данных для City C. Также приветствуется любой другой формат вывода, если доступ к отдельному фрейму данных прост.

Большое спасибо за Вашу помощь!


person DPatrick    schedule 05.02.2021    source источник


Ответы (2)


Используя purrr, этого можно добиться так:

  1. Разделите свой df по географии
  2. Прокрутите список (кроме области A) и присоедините dfs к списку для области A
  3. Сделайте переименование
set.seed(42)

dat <- data.frame(
  Geography = rep(LETTERS[1:4], each = 4),
  Dates = rep(seq(as.Date("2020-01-01"), as.Date("2020-01-04"), by = "1 day"), 4),
  Sales = runif(4 * 4),
  Avg_Volume = runif(4 * 4)
)

library(purrr)
library(dplyr)
library(stringr)

dat_list <- dat %>% 
  split(.$Geography) %>% 
  map(select, -Geography)

imap(dat_list[setdiff(names(dat_list), "A")], function(x, y) {
  left_join(dat_list[["A"]], x, by = "Dates", suffix = c(paste0("_", y), "_A")) %>% 
    rename_with(~ str_replace(.x, "(Sales|Avg_Volume)_(.*)", "\\2_\\1"), -Dates) %>% 
    select(-A_Avg_Volume)
})
#> $B
#>        Dates   B_Sales B_Avg_Volume   A_Sales
#> 1 2020-01-01 0.9148060    0.9782264 0.6417455
#> 2 2020-01-02 0.9370754    0.1174874 0.5190959
#> 3 2020-01-03 0.2861395    0.4749971 0.7365883
#> 4 2020-01-04 0.8304476    0.5603327 0.1346666
#> 
#> $C
#>        Dates   C_Sales C_Avg_Volume   A_Sales
#> 1 2020-01-01 0.9148060    0.9782264 0.6569923
#> 2 2020-01-02 0.9370754    0.1174874 0.7050648
#> 3 2020-01-03 0.2861395    0.4749971 0.4577418
#> 4 2020-01-04 0.8304476    0.5603327 0.7191123
#> 
#> $D
#>        Dates   D_Sales D_Avg_Volume   A_Sales
#> 1 2020-01-01 0.9148060    0.9782264 0.9346722
#> 2 2020-01-02 0.9370754    0.1174874 0.2554288
#> 3 2020-01-03 0.2861395    0.4749971 0.4622928
#> 4 2020-01-04 0.8304476    0.5603327 0.9400145

Создано 2021-02-05 пакетом REPEX (v1.0.0)

person stefan    schedule 05.02.2021
comment
Я столкнулся с этой ошибкой: Ошибка на карте (., Select, -Geography): объект «География» не найден - person DPatrick; 05.02.2021
comment
Когда вы запускаете код на моих данных примера или когда вы тестируете его на своих данных? - person stefan; 05.02.2021
comment
Я понял. Моя библиотека dplyr с сегодняшнего утра не работает. Мне пришлось принудительно вызвать dplyr :: для простых функций, таких как выбор, фильтр и т. Д. - person DPatrick; 05.02.2021
comment
Хм. Странный. Может быть, какое-то имя конфликтует с другим пакетом или ... - person stefan; 05.02.2021

Я взял фрейм данных установки Стефана и добавил еще один способ сделать это. Шаги следующие:

  1. Получите список из списка названий городов (исключая A). То, как я это написал, предполагает, что A первым, но вы также можете использовать discard (), чтобы удалить A из списка городов.
  2. Используйте карту с фильтром, чтобы получить список фреймов данных, в которых есть A и каждый город в городах. set_names, чтобы каждый элемент списка был доступен по названию города
  3. Возьмите каждый фрейм данных в списке и pivot_wider, затем выберите все по Avg_Volume для A.
#Set up a sample data frame
library(dplyr)

set.seed(42)

dat <- tibble(
  Geography = rep(LETTERS[1:4], each = 4),
  Dates = rep(seq(as.Date("2020-01-01"), as.Date("2020-01-04"), by = "1 day"), 4),
  Sales = runif(4 * 4),
  Avg_Volume = runif(4 * 4)
)

#Code to wrangle into list of filtered, wide format data frames
library(dpylyr)
library(tidyr)
library(purrr)

cities <- unique(dat$Geography)[-1]
dat_list <- map(cities, ~ filter(dat, Geography == "A" | Geography == .x)) %>% set_names(cities)
dat_list_wider <- map(dat_list, 
                      ~pivot_wider(.x, id_cols = "Dates", 
                                   names_from = "Geography", 
                                   values_from = c("Sales","Avg_Volume")) %>% 
                      select(-Avg_Volume_A))

person John Franchak    schedule 05.02.2021