Calculate percentage of an item in a group per year in R

Asked

Viewed 150 times

1

I have a DF 14-column: item, grupo and years 2010 to 2021. I need to know the percentage of each item within the grupo to which he belongs. I tried to use a group_by with the summarise, but since I need the calculation for each of the years, it didn’t work.

I tried to use a mutate_at, but it didn’t work either.

Man dput:

structure(list(Item = c("Carvão mineral", "Minerais não-metálicos", 
"Petróleo, gás natural e serviços de apoio", "Minério de ferro", 
"Minerais metálicos não-ferrosos", "Carne de bovinos e outros prod. de carne", 
"Carne de suíno", "Carne de aves", "Pescado industrializado", 
"Leite resfriado, esterilizado e pasteurizado", "Outros produtos do laticínio", 
"Açúcar", "Conservas de frutas, legumes, outros vegetais e sucos de frutas", 
"Óleos e gorduras vegetais e animais", "Café beneficiado", 
"Arroz beneficiado e produtos derivados do arroz", "Produtos derivados do trigo, mandioca ou milho", 
"Rações balanceadas para animais", "Outros produtos alimentares", 
"Bebidas", "Produtos do fumo", "Fios e fibras têxteis beneficiadas", 
"Tecidos", "Art. têxteis de uso doméstico e outros têxteis", 
"Artigos do vestuário e acessórios", "Calçados e artefatos de couro", 
"Produtos de madeira, exclusive móveis", "Celulose", "Papel, papelão, embalagens e artefatos de papel", 
"Serviços de impressão e reprodução"), Atividade = c("Extrativas ex-petróleo e gás", 
"Extrativas ex-petróleo e gás", "Combustíveis e lubrificantes básicos", 
"Extrativas ex-petróleo e gás", "Extrativas ex-petróleo e gás", 
"3.10 Fabricação de produtos alimentícios", "3.10 Fabricação de produtos alimentícios", 
"3.10 Fabricação de produtos alimentícios", "3.10 Fabricação de produtos alimentícios", 
"3.10 Fabricação de produtos alimentícios", "3.10 Fabricação de produtos alimentícios", 
"3.10 Fabricação de produtos alimentícios", "3.10 Fabricação de produtos alimentícios", 
"3.10 Fabricação de produtos alimentícios", "3.10 Fabricação de produtos alimentícios", 
"3.10 Fabricação de produtos alimentícios", "3.10 Fabricação de produtos alimentícios", 
"3.10 Fabricação de produtos alimentícios", "3.10 Fabricação de produtos alimentícios", 
"3.11 Fabricação de bebidas", "3.12 Fabricação de produtos do fumo", 
"3.13 Fabricação de produtos têxteis", "3.13 Fabricação de produtos têxteis", 
"3.13 Fabricação de produtos têxteis", "3.14 Confecção de artigos do vestuário e acessórios", 
"3.15 Preparação de couros e fabricação de artefatos de couro, artigos para viagem e calçados", 
"3.16 Fabricação de produtos de madeira", "3.17 Fabricação de celulose, papel e produtos de papel", 
"3.17 Fabricação de celulose, papel e produtos de papel", "3.18 Impressão e reprodução de gravações"
), `2010` = c(0, 3800, 0, 5705, 1540, 15471, 1203, 4387, 909, 
2045, 5336, 4713, 5285, 3850, 2291, 3668, 5273, 3974, 23901, 
14037, 1459, 1110, 2513, 6913, 27945, 10840, 4671, 1059, 9586, 
5218), `2011` = c(0, 4514, 0, 7229, 2054, 14430, 1048, 3753, 
861, 2644, 7965, 5350, 5701, 3700, 2356, 3645, 5988, 4355, 26759, 
12830, 1754, 2102, 4234, 8279, 33938, 12963, 5309, 1145, 11274, 
6862), `2012` = c(0, 3846, 0, 6400, 2316, 21339, 1195, 5872, 
1098, 2727, 8653, 5985, 6920, 5022, 2870, 4973, 7719, 5868, 29907, 
15592, 1965, 2095, 4347, 10057, 39308, 14406, 6012, 967, 14133, 
8790), `2013` = c(0, 4414, 0, 7347, 2580, 27309, 1502, 7518, 
1681, 3905, 10728, 6090, 7918, 5326, 3961, 6340, 10684, 6448, 
36141, 17583, 2430, 2473, 4684, 12889, 41084, 16638, 6535, 969, 
15818, 9260), `2014` = c(0, 4367, 0, 6346, 2209, 31058, 1720, 
7881, 1850, 5661, 14518, 6624, 10580, 5920, 4441, 6648, 11421, 
7070, 47139, 21731, 2607, 2295, 4921, 13610, 50464, 17915, 6599, 
972, 14611, 10414), `2015` = c(0, 4776, 0, 4921, 2606, 35003, 
1890, 8601, 1780, 5157, 15002, 6797, 10865, 6057, 5158, 7244, 
12818, 7217, 50349, 22886, 2924, 2354, 4893, 14240, 50223, 19992, 
6800, 913, 15571, 11804), `2016` = c(0, 3822, 0, 4858, 2102, 
37319, 2022, 9592, 1871, 5742, 15526, 9216, 10579, 5864, 5419, 
8239, 13446, 8808, 53770, 23388, 3052, 1965, 4533, 14555, 51787, 
20728, 6116, 1124, 16783, 12900), `2017` = c(0, 4231, 0, 7002, 
2506, 41952, 2295, 10938, 2117, 6115, 16304, 8685, 10980, 6003, 
6808, 9077, 14351, 8411, 58195, 26806, 3469, 2080, 4966, 17092, 
53900, 20718, 7553, 1324, 18283, 12907), `2018` = c(0, 4231, 
0, 7002, 2506, 41952, 2295, 10938, 2117, 6115, 16304, 8685, 10980, 
6003, 6808, 9077, 14351, 8411, 58195, 26806, 3469, 2080, 4966, 
17092, 53900, 20718, 7553, 1324, 18283, 12907), `2019` = c(0, 
4231, 0, 7002, 2506, 41952, 2295, 10938, 2117, 6115, 16304, 8685, 
10980, 6003, 6808, 9077, 14351, 8411, 58195, 26806, 3469, 2080, 
4966, 17092, 53900, 20718, 7553, 1324, 18283, 12907), `2020` = c(0, 
4231, 0, 7002, 2506, 41952, 2295, 10938, 2117, 6115, 16304, 8685, 
10980, 6003, 6808, 9077, 14351, 8411, 58195, 26806, 3469, 2080, 
4966, 17092, 53900, 20718, 7553, 1324, 18283, 12907), `2021` = c(0, 
4231, 0, 7002, 2506, 41952, 2295, 10938, 2117, 6115, 16304, 8685, 
10980, 6003, 6808, 9077, 14351, 8411, 58195, 26806, 3469, 2080, 
4966, 17092, 53900, 20718, 7553, 1324, 18283, 12907)), row.names = c(NA, 
-30L), class = c("tbl_df", "tbl", "data.frame"), na.action = structure(c(`1` = 1L), class = "omit"))

For the items of the first group (Extractive ex-petroleum and gas), respectively, mineral, non-metallic minerals, iron ore and non-ferrous metallic minerals, I would need to find the following values for 2010: 0.0, 0.344, 0.517 and 0.139.

The general idea is to find these percentages for every year.

Code that I used:

library(tidyverse)

variaveis <- c("Carvão mineral", "Minerais não-metálicos", "Minério de ferro", "Minerais metálicos não-ferrosos")

dados %>%
    group_by(item, atividade) %>%
    mutate_at(vars(variaveis), funs(. / sum(.)))
  • Alexandre, Good night! The value of mineral coal in 2010 is zero, it really represents 0.141?

  • Sorry for the error, I have corrected the values.

4 answers

3


A possible solution would be to pivot the data frame:

library(tidyverse)

dados2 <- pivot_longer(
  data = dados,
  cols = starts_with('20'),
  names_to = 'Ano',
  values_to = 'Valores'
)

Then we group and calculate the percentage:

teste <-  dados2 %>% group_by(Ano, Atividade) %>%
  mutate('%' = Valores/sum(Valores) * 100)

As we generate some NA, we have to remove:

teste[is.na(teste)] = 0
  • 1

    Thank you very much, it worked perfectly!

  • 1

    For nothing Alexandre! Hug!

3

Here is a relatively simple solution.

library(dplyr)

variaveis <- c("Carvão mineral", "Minerais não-metálicos", "Minério de ferro", "Minerais metálicos não-ferrosos")

dados %>%
  filter(Item %in% variaveis) %>%
  group_by(Atividade) %>%
  summarise_at(vars(`2010`:`2021`), ~./sum(.)) %>%
  bind_cols(Item = dados %>% filter(Item %in% variaveis) %>% pull(Item), .)
## A tibble: 4 x 14
#  Item             Atividade         `2010` `2011` `2012` `2013` `2014` `2015` `2016` `2017` `2018` `2019` `2020` `2021`
#  <chr>            <chr>              <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
#1 Carvão mineral   Extrativas ex-pe…  0      0      0      0      0      0      0      0      0      0      0      0    
#2 Minerais não-me… Extrativas ex-pe…  0.344  0.327  0.306  0.308  0.338  0.388  0.354  0.308  0.308  0.308  0.308  0.308
#3 Minério de ferro Extrativas ex-pe…  0.517  0.524  0.509  0.512  0.491  0.400  0.451  0.510  0.510  0.510  0.510  0.510
#4 Minerais metáli… Extrativas ex-pe…  0.139  0.149  0.184  0.180  0.171  0.212  0.195  0.182  0.182  0.182  0.182  0.182

3

The question is tagged dplyr, but for the record, here’s how to calculate the percentages per group for all numeric columns using data.table:

library(data.table)

setDT(dados)

percentage <- function(x) nafill(x/sum(x), fill = 0)  # função para calcular porcentagem e trocar NA/NaN por 0

cols <- names(dados)[sapply(dados, is.numeric)]  # nomes das colunas numéricas

dados.pct <- copy(dados)  # caso queira preservar os dados originais

dados.pct[, paste(cols) := lapply(.SD, percentage), by = Atividade, .SDcols = cols]


> dados.pct[Atividade == "Extrativas ex-petróleo e gás", 1:4]
                              Item                    Atividade      2010      2011
1:                  Carvão mineral Extrativas ex-petróleo e gás 0.0000000 0.0000000
2:          Minerais não-metálicos Extrativas ex-petróleo e gás 0.3440471 0.3271726
3:                Minério de ferro Extrativas ex-petróleo e gás 0.5165233 0.5239545
4: Minerais metálicos não-ferrosos Extrativas ex-petróleo e gás 0.1394296 0.1488729

Alternatively, if you want to create new columns in the original data.frame, just assign new names:

dados[, paste0(cols,"pctAtv") := lapply(.SD, percentage), by = Atividade, .SDcols = cols]


> dados[Atividade == "Extrativas ex-petróleo e gás", c(1:4,15:16)]
                              Item                    Atividade 2010 2011 2010pctAtv 2011pctAtv
1:                  Carvão mineral Extrativas ex-petróleo e gás    0    0  0.0000000  0.0000000
2:          Minerais não-metálicos Extrativas ex-petróleo e gás 3800 4514  0.3440471  0.3271726
3:                Minério de ferro Extrativas ex-petróleo e gás 5705 7229  0.5165233  0.5239545
4: Minerais metálicos não-ferrosos Extrativas ex-petróleo e gás 1540 2054  0.1394296  0.1488729

2

You need to enter the column names for the mutate_at. In addition, you must group only by Activity (or the total for the percentage calculation will be given for each item of each activity).

library(dplyr)

variaveis <- names(dados)[sapply(dados, is.numeric)] # todas as colunas numéricas
## ou
variaveis <- grep("^20", names(dados), value = TRUE) # todas as colunas que começam com "20"

dados %>%
    group_by(Atividade) %>%
    mutate_at(variaveis, .funs = list(~ coalesce(./sum(.), 0)))  # coalesce para substituir NaNs/NAs

Browser other questions tagged

You are not signed in. Login or sign up in order to post.