dplyr как рассчитать процент от нескольких столбцов и вывести столбцы с пользовательскими именами

#r #dplyr

Вопрос:

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

Рассмотрим следующий код:

 a<-structure(list(year = 2000:2005, Col1 = 1:6, Col2 = c(1L, 4L, 
9L, 16L, 25L, 36L)), row.names = c(NA, -6L), class = "data.frame")
> a
  year Col1 Col2
1 2000    1    1
2 2001    2    4
3 2002    3    9
4 2003    4   16
5 2004    5   25
6 2005    6   36
a<-a %>% rowwise() %>%
mutate(total = sum(across(starts_with("Col")), na.rm = T)) %>% data.frame()
a %>%
    mutate_at(vars(starts_with("Col")) , funs(P = ./a$total * 100))
 

Результат выглядит следующим образом:

введите описание изображения здесь

Как обработать имя двух последних столбцов(например, per_Col1 и per_Col2 вместо Col1_P и Col2_P, основной вопрос) ? Есть ли лучший способ(с помощью пакета dplyr) сделать это?( вместо того, чтобы вычислять сумму столбцов, а затем делить каждый из них на нее)

Ответ №1:

Вы можете использовать его вместе с аргументом .names:

 a %>%
  rowwise() %>%
  mutate(total = sum(across(starts_with("Col")), na.rm = TRUE)) %>% 
  mutate(across(starts_with("Col") , ~./total * 100, .names = 'per_{col}')) %>%
  ungroup()
 

что дает:

 # A tibble: 6 x 6
   year  Col1  Col2 total per_Col1 per_Col2
  <int> <int> <int> <int>    <dbl>    <dbl>
1  2000     1     1     2     50       50  
2  2001     2     4     6     33.3     66.7
3  2002     3     9    12     25       75  
4  2003     4    16    20     20       80  
5  2004     5    25    30     16.7     83.3
6  2005     6    36    42     14.3     85.7
 

Ответ №2:

Вот несколько иной подход, использующий scales :

 library(scales)
library(dplyr)
a %>%
    rowwise() %>% 
    mutate(Total = sum(c_across(Col1:Col2), na.rm = TRUE), 
           across(Col1:Col2, ~percent(./sum(Total), accuracy = 0.1), .names ="percent_{.col}")
           )
 

выход

    year  Col1  Col2 Total percent_Col1 percent_Col2
  <int> <int> <int> <int> <chr>        <chr>       
1  2000     1     1     2 50.0%        50.0%       
2  2001     2     4     6 33.3%        66.7%       
3  2002     3     9    12 25.0%        75.0%       
4  2003     4    16    20 20.0%        80.0%       
5  2004     5    25    30 16.7%        83.3%       
6  2005     6    36    42 14.3%        85.7% 
 

Ответ №3:

Мы можем использовать rowSums это для векторизации

 library(dplyr)
a %>%
    mutate(total = rowSums(across(starts_with('Col'))), 
     across(starts_with('Col'), ~ ./total * 100, .names = 'per_{.col}'))
  year Col1 Col2 total per_Col1 per_Col2
1 2000    1    1     2 50.00000 50.00000
2 2001    2    4     6 33.33333 66.66667
3 2002    3    9    12 25.00000 75.00000
4 2003    4   16    20 20.00000 80.00000
5 2004    5   25    30 16.66667 83.33333
6 2005    6   36    42 14.28571 85.71429