Подстановка данных по уровням гранулярности и применение функции к каждому фрейму данных в R - PullRequest
0 голосов
/ 05 октября 2019

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

----------------------------------------------------------------------

В настоящее время у меня слишком ручной процесс применения функции к подмножествам в моих данных, и я хотел бы выяснить, как сделать код более эффективным. Проще всего описать проблему с помощью примера:

Переменные в моих данных (myData): ВВП в 2017, 2018 и 2019 годах на четырех уровнях детализации: континент, страна, штат (или провинция)и город. (Примечание: цифры ВВП являются произвольными; используются только для упрощения расчетов)

myData:

   |------|---------------|---------|------------|-------------|------|
   | Year | Continent     | Country | State      | City        | GDP  |
   |------|---------------|---------|------------|-------------|------|
   | 2019 | North America | Canada  | Alberta    | Edmonton    | 13   |
   | 2018 | North America | Canada  | Alberta    | Calgary     | 9    |
   | 2018 | North America | Canada  | Alberta    | Edmonton    | 3    | 
   | 2018 | Asia          | India   | Bihar      | Patna       | 19   |
   | 2018 | Asia          | India   | Bihar      | Gaya        | 8    |
   | 2017 | Asia          | India   | Bihar      | Patna       | 22   | 
   | 2019 | Asia          | India   | Bihar      | Gaya        | 19   |
   | 2019 | Asia          | India   | Bihar      | Patna       | 16   |
   | 2019 | North America | USA     | California | San Diego   | 23   |
   | 2017 | North America | USA     | California | Los Angeles | 18   |
   | 2018 | North America | USA     | California | Los Angeles | 25   |
   | 2018 | North America | USA     | Florida    | Tampa       | 14   |
   | 2019 | North America | USA     | Florida    | Miami       | 19   |
   | 2018 | Asia          | China   | Guangdong  | Shenzhen    | 29   |
   | 2017 | Asia          | China   | Guangdong  | Shenzhen    | 26   |
   | 2019 | Asia          | China   | Guangdong  | Shenzhen    | 33   |
   | 2019 | Asia          | China   | Guangdong  | Guangzhou   | 20   |
   | 2018 | Asia          | China   | Guangdong  | Guangzhou   | 19   |
   | 2018 | North America | Canada  | Quebec     | Montreal    | 11   |
   | 2019 | North America | Canada  | Quebec     | Montreal    | 7    |
   | 2019 | Asia          | China   | Shandong   | Yantai      | 30   |
   | 2019 | Asia          | China   | Shandong   | Jinan       | 16   |
   | 2018 | Asia          | China   | Shandong   | Yantai      | 17   |
   | 2018 | Asia          | China   | Shandong   | Jinan       | 11   |
   | 2019 | Asia          | India   | U.P.       | Allahabad   | 21   |
   | 2018 | Asia          | India   | U.P.       | Agra        | 15   |
   | 2018 | Asia          | India   | U.P.       | Allahabad   | 13   |
   | 2019 | Asia          | India   | U.P.       | Agra        | 18   |
   |------|---------------|---------|------------|-------------|------|

Общая цель - рассчитать квантили ВВП (1 = 0-25%, 2 =25% -50% и т. Д.) С различной степенью детализации. Вот именно то, что я ищу:

  • Квантили для каждого года;(подмножество всего набора данных за 3 года)
  • Квантили для каждого континента;(подмножество данных по континентам)
  • Квантили для каждой страны;(подмножество данных по континентам и странам)
  • Квантили для каждого штата. Провинция;(подмножество данных по континентам, странам и штатам. Провинция)
  • Квантили для каждого города;(данные подмножества по Континенту, Стране, Штату. Провинции и городу)


В настоящее время у меня есть два этапа в этом процессе:

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


Подмножество путем суммирования / сложения ВВП на каждом уровне,(Примечание: этот шаг будет генерировать кадры данных с меньшим и меньшим количеством строк при переходе на уровень 5.) Вот что я сделал, и он довольно ручной и повторяющийся, поэтому я хотел бы найти лучший способ:

Level_1.Year <- aggregate(
    GDP ~ 
      Year + 
      Continent + 
      Country + 
      State.Province + 
      City, 
    FUN = sum, 
    data = myData)

Level_2.Continent <- aggregate(
    GDP ~ 
      Continent + 
      Country + 
      State.Province + 
      City, 
    FUN = sum, 
    data = myData)

Level_3.Country <- aggregate(
    GDP ~ 
      Country + 
      State.Province + 
      City, 
    FUN = sum, 
    data = myData)

Level_4.State.Province <- aggregate(
    GDP ~ 
      State.Province + 
      City, 
    FUN = sum, 
    data = myData)

Level_5.City <- aggregate(
    GDP ~ 
      City, 
    FUN = sum, 
    data = myData)

----------------------------------------------------------------------

Итак, теперь, когда у нас есть подмножества, мы вычисляем квантили для каждого подмножества. Поскольку все они имеют разную длину и не имеют одинаковых переменных, я прибегнул к ручным / повторным вычислениям (снова ...) для каждого подмножества:

Level_1.Year_quantiles <- Level_1.Year %>% 
        group_by(Year) %>% 
        mutate(Quantile = cut(GDP,
            breaks = quantile(GDP, 
        c(0, 0.25, 0.5, 0.75, 1)), 
            labels = 1:4, 
            include.lowest = TRUE))

Level_2.Continent_quantiles <- Level_2.Continent %>% 
        group_by(Continent) %>% 
        mutate(Quantile = cut(GDP,
            breaks = quantile(GDP, 
        c(0, 0.25, 0.5, 0.75, 1)), 
            labels = 1:4, 
            include.lowest = TRUE))

Level_3.Country_quantiles <- Level_3.Country %>% 
        group_by(Country) %>% 
        mutate(Quantile = cut(GDP,
            breaks = quantile(GDP, 
        c(0, 0.25, 0.5, 0.75, 1)), 
            labels = 1:4, 
            include.lowest = TRUE))
        . 
        .
        .

# All the way through Level_5.City; I think you get the point. 

----------------------------------------------------------------------

Есть ли способ (1) подмножествакаждый уровень более эффективным образом, затем (2) сохранить каждое подмножество в списке фреймов данных, а затем (3) добавить квантили к каждому фрейму данных в списке?

Если есть лучший способ сделать весь этот процесс, пожалуйста, дайте мне знать! Кроме того, если у вас есть какие-либо комментарии или рекомендации, я хотел бы услышать их.

Ответы [ 2 ]

1 голос
/ 05 октября 2019

Во-первых, некоторые пояснения: то, что вы называете подмножествами, является сгруппированным резюмеОбратитесь к «агрегат» для получения дополнительной информации. Во-вторых, ответ на каждый из ваших трех вопросов - да. В-третьих, ваше резюме уровня 1 эквивалентно вашему фрейму данных.

Поскольку вы используете aggregate(), я сначала проиллюстрирую, как получить список сгруппированных резюме, используя aggregate():

library(tidyverse)

formula_list <- 
  list(
    GDP ~ Year + Continent + Country + State.Province + City,
    GDP ~ Continent + Country + State.Province + City, 
    GDP ~ Country + State.Province + City, 
    GDP ~ State.Province + City,
    GDP ~ City
    )

summaries <- formula_list %>% 
  map( ~ aggregate(.x, FUN = sum, data = myData))

Также возможно заменить aggregate() наполностью dplyr основанный подход. Положительным моментом является замена общеизвестно неэффективной aggregate(). Недостатком является то, что нам придется иметь дело с вопросами, которые являются более сложной темой (для получения дополнительной информации обратитесь к vignette("programming")).

var_combs <- list(
  vars(Year, Continent, Country, State.Province, City),
  vars(Continent, Country, State.Province, City),
  vars(Country, State.Province, City),
  vars(State.Province, City),
  vars(City)) 

summaries <- var_combs %>% 
  map(~ myData %>% 
          group_by(!!!.x) %>% 
          summarize(GDP = sum(GDP)))

Далее следует применение вашего кода для расчета квартилей к каждому элементу списка. Поскольку вы также изменяете переменную группировки, нам нужно выполнить итерации по двум спискам, поэтому мы будем использовать purrr::map2():

grp_var <- list(
  vars(Year),
  vars(Continent),
  vars(Country),
  vars(State.Province),
  vars(City)
)

map2(summaries[1:3], 
     grp_var[1:3], 
     ~ .x %>%  
       group_by(!!!.y) %>% 
       mutate(Quantile = cut(GDP,
                             breaks = quantile(GDP, c(0, 0.25, 0.5, 0.75, 1)), 
                             labels = 1:4, 
                             include.lowest = TRUE))
)

. Вы заметите, что мне пришлось подгруппировать списки только для первых трех элементов. ,Код, который вы написали для расчета квартилей, не работает, если у одной из групп есть только одно наблюдение (что имеет смысл: вы не можете рассчитать квартили для выборки из одного). Это всегда будет иметь место для последней из пяти, так как она содержит только один элемент на группу по определению. Также сомнительно, если ваш результат особенно значим, если у вас есть только два или три наблюдения на группу.

Данные:

myData <- structure(list(
    Year = c(2019, 2019, 2018, 2019, 2019, 2018, 2019, 
            2018, 2018, 2018, 2018, 2018, 2018, 2017, 2017, 2019, 2018, 2019, 
            2019, 2018, 2019, 2017, 2019, 2018, 2018, 2018, 2019, 2019), 
    Continent = c("North America", "Asia", "Asia", "North America", 
                 "Asia", "North America", "Asia", "North America", "Asia", 
                 "North America", "Asia", "Asia", "Asia", "North America", 
                 "Asia", "North America", "Asia", "North America", "Asia", 
                 "North America", "Asia", "Asia", "Asia", "North America", 
                 "Asia", "Asia", "Asia", "Asia"), 
    Country = c("Canada", "India", "India", "USA", "China", "USA", "China", 
               "Canada", "China", "Canada", "India", "India", "China", 
               "USA", "China", "USA", "India", "Canada", "China", "USA", 
               "China", "India", "India", "Canada", "China", "China", 
               "India", "India"), 
    State.Province = c("Alberta", "Uttar Pradesh", "Bihar", "California", 
                      "Shandong", "Florida", "Shandong", "Quebec", "Guangdong", 
                      "Alberta", "Uttar Pradesh", "Bihar", "Shandong", 
                      "California", "Guangdong", "Florida", "Uttar Pradesh", 
                      "Quebec", "Guangdong", "California", "Guangdong", "Bihar", 
                      "Bihar", "Alberta", "Shandong", "Guangdong", "Uttar Pradesh", 
                      "Bihar"), 
    City = c("Edmonton", "Allahabad", "Patna", "Los Angeles", "Yantai", "Miami", 
             "Jinan", "Montreal", "Shenzhen", "Calgary", "Agra", "Gaya", "Yantai", 
             "Los Angeles", "Shenzhen", "Miami", "Allahabad", "Montreal", 
             "Shenzhen", "Los Angeles", "Guangzhou", "Patna", "Gaya", "Edmonton", 
             "Jinan", "Guangzhou", "Agra", "Patna"), 
    GDP = c(13, 21, 19, 23, 30, 14, 16, 11, 29, 9, 15, 8, 17, 18, 26, 19, 13, 7, 
            33, 25, 20, 22, 19, 3, 11, 19, 18, 16)), 
  class = c("spec_tbl_df", "tbl_df", "tbl", "data.frame"), 
  row.names = c(NA, -28L), 
  spec = structure(list(cols = list(Year = structure(list(), class = c("collector_double", "collector")), 
                                    Continent = structure(list(), class = c("collector_character", "collector")), 
                                    Country = structure(list(), class = c("collector_character", "collector")), 
                                    State.Province = structure(list(), class = c("collector_character", "collector")), 
                                    City = structure(list(), class = c("collector_character", "collector")), 
                                    GDP = structure(list(), class = c("collector_double", "collector"))), 
                        default = structure(list(), class = c("collector_guess", "collector")), 
                        skip = 2), 
                   class = "col_spec"))
0 голосов
/ 05 октября 2019

Рассмотрим решение семейства применений, а именно lapply, by (обертка до tapply) и Map (обертка до mapply), обрабатывающие всю обработку в списках:

agg_factors <- c("City", "State", "Country", "Continent", "Year")

# NAMED LIST OF DATA FRAMES WHERE FORMULA DYNAMICALLY BUILT AND PASS INTO aggregate()
agg_df_list <- setNames(lapply(seq_along(agg_factors), function(i) {
                              agg_formula <- as.formula(paste("GDP ~", paste(agg_factors[1:i], collapse=" + ")))
                              aggregate(agg_formula, myData, FUN=sum)
                       }), agg_factors)

# FUNCTION TO CALL by() TO RUN FUNCTION ON EACH SUBSET TO BIND TOGETHER AT END
proc_quantiles <- function(df, nm) {

  dfs <- by(df, df[[nm]], function(sub) 
               transform(sub,
                         Quantile = tryCatch(cut(GDP,
                                                 breaks = quantile(GDP, c(0, 0.25, 0.5, 0.75, 1)), 
                                                 labels = 1:4, 
                                                 include.lowest = TRUE), 
                                             error = function(e) NA)
                         )
         ) 

  do.call(rbind, unname(dfs))      
 }

# ELEMENTWISE LOOP THROUGH DFs AND CORRESPONDING NAMES
quantile_df_list <- Map(proc_quantiles, agg_df_list, names(agg_df_list))

Выход

head(quantile_df_list$City)
#        City GDP Quantile
# 1      Agra  33       NA
# 2 Allahabad  34       NA
# 3   Calgary   9       NA
# 4  Edmonton  16       NA
# 5      Gaya  27       NA
# 6 Guangzhou  39       NA

head(quantile_df_list$State)
#          City      State GDP Quantile
# 1     Calgary    Alberta   9        1
# 2    Edmonton    Alberta  16        4
# 3        Gaya      Bihar  27        1
# 4       Patna      Bihar  57        4
# 5 Los Angeles California  43        4
# 6   San Diego California  23        1

head(quantile_df_list$Country)
#        City     State Country GDP Quantile
# 1   Calgary   Alberta  Canada   9        1
# 2  Edmonton   Alberta  Canada  16        2
# 3  Montreal    Quebec  Canada  18        4
# 4 Guangzhou Guangdong   China  39        2
# 5  Shenzhen Guangdong   China  88        4
# 6     Jinan  Shandong   China  27        1

head(quantile_df_list$Continent)
#        City     State Country Continent GDP Quantile
# 1 Guangzhou Guangdong   China      Asia  39        3
# 2  Shenzhen Guangdong   China      Asia  88        4
# 3     Jinan  Shandong   China      Asia  27        1
# 4    Yantai  Shandong   China      Asia  47        3
# 5      Gaya     Bihar   India      Asia  27        1
# 6     Patna     Bihar   India      Asia  57        4

head(quantile_df_list$Year)
#          City      State Country     Continent Year GDP Quantile
# 1    Shenzhen  Guangdong   China          Asia 2017  26        4
# 2       Patna      Bihar   India          Asia 2017  22        2
# 3 Los Angeles California     USA North America 2017  18        1
# 4   Guangzhou  Guangdong   China          Asia 2018  19        3
# 5    Shenzhen  Guangdong   China          Asia 2018  29        4
# 6       Jinan   Shandong   China          Asia 2018  11        1
...