Как выбрать верхние значения на их основе, покрывающие определенный процент? - PullRequest
1 голос
/ 27 марта 2020

Я хочу выбрать лучшие страны в зависимости от того, какую часть общего производства они покрывают. Я хочу, чтобы страны, которые я отфильтровал, покрывали, по крайней мере, 50% от общего производства.

У меня есть эти данные:

production = structure(list(iso3_code = c("USA", "CHN", "BRA", "ARG", "UKR", 
"IDN", "IND", "MEX", "ROU", "CAN", "IDN", "MYS", "THA", "NGA", 
"COL", "ECU", "CMR", "GHA", "PNG", "HND", "USA", "BRA", "ARG", 
"CHN", "IND", "PRY", "CAN", "UKR", "RUS", "BOL", "BRA", "IND", 
"CHN", "THA", "PAK", "MEX", "COL", "GTM", "AUS", "USA"), country = c("USA", 
"China", "Brazil", "Argentina", "Ukraine", "Indonesia", "India", 
"Mexico", "Romania", "Canada", "Indonesia", "Malaysia", "Thailand", 
"Nigeria", "Colombia", "Ecuador", "Cameroon", "Ghana", "Papua New Guinea", 
"Honduras", "USA", "Brazil", "Argentina", "China", "India", "Paraguay", 
"Canada", "Ukraine", "Russia", "Bolivia", "Brazil", "India", 
"China", "Thailand", "Pakistan", "Mexico", "Colombia", "Guatemala", 
"Australia", "USA"), item = c("Maize", "Maize", "Maize", "Maize", 
"Maize", "Maize", "Maize", "Maize", "Maize", "Maize", "Oil palm fruit", 
"Oil palm fruit", "Oil palm fruit", "Oil palm fruit", "Oil palm fruit", 
"Oil palm fruit", "Oil palm fruit", "Oil palm fruit", "Oil palm fruit", 
"Oil palm fruit", "Soybeans", "Soybeans", "Soybeans", "Soybeans", 
"Soybeans", "Soybeans", "Soybeans", "Soybeans", "Soybeans", "Soybeans", 
"Sugar cane", "Sugar cane", "Sugar cane", "Sugar cane", "Sugar cane", 
"Sugar cane", "Sugar cane", "Sugar cane", "Sugar cane", "Sugar cane"
), value = c(392450840, 257173900, 82288298, 43462323, 35801050, 
30253938, 27820000, 27169977, 18663939, 13884800, 115267491, 
98419400, 15400000, 7850000, 5878504, 2785756, 2641118, 2604387, 
2496325, 2493910, 123664230, 117887672, 37787927, 14189217, 13786000, 
11045971, 7266600, 4460770, 4026850, 2942131, 746828157, 376900000, 
108097100, 104360867, 67173975, 56841523, 36276860, 35568207, 
33506830, 31335984)), class = c("tbl_df", "tbl", "data.frame"
), row.names = c(NA, -40L), spec = structure(list(cols = list(
    iso3_code = structure(list(), class = c("collector_character", 
    "collector")), country = structure(list(), class = c("collector_character", 
    "collector")), item = structure(list(), class = c("collector_character", 
    "collector")), value = structure(list(), class = c("collector_double", 
    "collector")), share = structure(list(), class = c("collector_double", 
    "collector")), cumulative_share = structure(list(), class = c("collector_double", 
    "collector"))), default = structure(list(), class = c("collector_guess", 
"collector")), skip = 1), class = "col_spec"))

То, что я сделал, - это то, что я вычисляю внутри группы «пункт» - доля для каждой страны и совокупная доля. Затем я фильтрую в каждой группе, которая имеет не более 0,5 в совокупной доле.

production %>% 
  group_by(item) %>% 
  mutate(share = value / sum(value),
         cumulative_share = cumsum(share)) %>% 
  filter(cumulative_share <= 0.5)

, что дает мне:

# A tibble: 4 x 6
# Groups:   item [4]
  iso3_code country   item               value share cumulative_share
  <chr>     <chr>     <chr>              <dbl> <dbl>            <dbl>
1 USA       USA       Maize          392450840 0.422            0.422
2 IDN       Indonesia Oil palm fruit 115267491 0.451            0.451
3 USA       USA       Soybeans       123664230 0.367            0.367
4 BRA       Brazil    Sugar cane     746828157 0.468            0.468

Но я хочу, чтобы в каждой группе "элемент" выбрать верхнюю страны, которые охватывают не менее 50% от общего «значения» в этой группе. Так что для кукурузы я хочу выбрать США и Китай (поскольку они охватывают 0,422 + 0,277 = 0,699> 0,5).

Есть идеи, как решить эту проблему?

Ответы [ 3 ]

3 голосов
/ 27 марта 2020

Используйте lag, чтобы выбрать все, включая первый случай, когда ваше условие ложно. Использование default = TRUE гарантирует, что все будет смещено, а TRUE будет добавлен, так что будет включено и первое наблюдение.

library(tidyverse)

production %>% 
  group_by(item) %>% 
  arrange(desc(value)) %>% 
  mutate(share = value / sum(value),
         cumulative_share = cumsum(share)) %>% 
  filter(lag(cumulative_share <= 0.5, default = TRUE)) %>% 
  ungroup()

#   iso3_code country   item               value share cumulative_share
#   <chr>     <chr>     <chr>              <dbl> <dbl>            <dbl>
# 1 BRA       Brazil    Sugar cane     746828157 0.468            0.468
# 2 USA       USA       Maize          392450840 0.422            0.422
# 3 IND       India     Sugar cane     376900000 0.236            0.704
# 4 CHN       China     Maize          257173900 0.277            0.699
# 5 USA       USA       Soybeans       123664230 0.367            0.367
# 6 BRA       Brazil    Soybeans       117887672 0.350            0.717
# 7 IDN       Indonesia Oil palm fruit 115267491 0.451            0.451
# 8 MYS       Malaysia  Oil palm fruit  98419400 0.385            0.835
1 голос
/ 27 марта 2020

cumsum() логический вектор для поиска первого cumulative_share, большего или равного 0,5.

library(dplyr)

production %>% 
  group_by(item) %>% 
  mutate(share = value / sum(value),
         cumulative_share = cumsum(share)) %>%
  filter(cumsum(cumulative_share >= 0.5) <= 1) %>%
  ungroup()

# # A tibble: 8 x 6
#   iso3_code country   item               value share cumulative_share
#   <chr>     <chr>     <chr>              <dbl> <dbl>            <dbl>
# 1 USA       USA       Maize          392450840 0.422            0.422
# 2 CHN       China     Maize          257173900 0.277            0.699
# 3 IDN       Indonesia Oil palm fruit 115267491 0.451            0.451
# 4 MYS       Malaysia  Oil palm fruit  98419400 0.385            0.835
# 5 USA       USA       Soybeans       123664230 0.367            0.367
# 6 BRA       Brazil    Soybeans       117887672 0.350            0.717
# 7 BRA       Brazil    Sugar cane     746828157 0.468            0.468
# 8 IND       India     Sugar cane     376900000 0.236            0.704
0 голосов
/ 27 марта 2020

Вам нужно что-то подобное?

library(dplyr)

production %>% 
   group_by(item) %>% 
   mutate(share = value / sum(value),
          cumulative_share = cumsum(share)) %>%
   ungroup %>%
   slice(seq_len(which.max(cumulative_share >= 0.5)))

# A tibble: 2 x 6
#  iso3_code country item      value share cumulative_share
#  <chr>     <chr>   <chr>     <dbl> <dbl>            <dbl>
#1 USA       USA     Maize 392450840 0.422            0.422
#2 CHN       China   Maize 257173900 0.277            0.699

Выбирает строки до тех пор, пока cumulative_share не пересечет 0.5.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...