Получите процентные значения по нескольким столбцам на основе факторов, заданных функцией group by в R

#r #dplyr #group-by #tidyverse

Вопрос:

У меня есть df, который смотрит только на 1 идентификатор с соответствующими активами:

 ID | Asset | CONF_1 | CONF_2 | CONF_3 |  1 A PERFECT HIGH LOW  1 B PERFECT LOW LOW 1 C LOW HIGH VERY LOW 1 D NA MEDIUM MEDIUM 1 E MEDIUM MEDIUM PERFECT 1 F MEDIUM VERY LOW NA 1 G VERY LOW VERY LOW VERY LOW 1 H NA PERFECT HIGH  

Цель состоит в том, чтобы реорганизовать df, чтобы я мог разбить % каждого уровня уверенности (ИДЕАЛЬНЫЙ, ВЫСОКИЙ, СРЕДНИЙ И Т. Д.) С учетом каждого идентификатора и 3 полей Conf.

Желаемый результат

 ID | CONFIDENCE | CONF_1 % | CONF_2 % | CONF_3 % 1 PERFECT 25 % 12.5 % 12.5 % 1 HIGH 0 25 % 12.5 % 1 MEDIUM 25 % 25 % 12.5 % 1 LOW 12.5 % 12.5 % 25 % 1 VERY LOW 12.5 % 25 % 25 % 1 NA 25 % 0 12.5 %  

Комментарии:

1. Я полагаю, что так @akrun — знаменатель равен 8, и я просто подсчитал, сколько раз каждый уровень конфронтации происходил из 8

2. Пожалуйста, проверьте решение, которое я опубликовал

Ответ №1:

Сгруппированные по столбцам «ID», summarise across «CONF», получите счетчик частот table в factor столбце с levels указанным в порядке и найдите proportions

 library(dplyr) df1 %gt;%   group_by(ID) %gt;%   summarise(lvls = c("PERFECT", "HIGH", "MEDIUM", "LOW", "VERY LOW", NA),   across(starts_with("CONF"),   ~ 100 * proportions(table(factor(., levels = na.omit(lvls)),   useNA = "always"))), .groups = 'drop') %gt;%  rename(CONFIDENCE = lvls)  

-выход

 # A tibble: 6 × 5  ID CONFIDENCE CONF_1 CONF_2 CONF_3   lt;intgt; lt;chrgt; lt;tablegt; lt;tablegt; lt;tablegt; 1 1 PERFECT 25.0 12.5 12.5  2 1 HIGH 0.0 25.0 12.5  3 1 MEDIUM 25.0 25.0 12.5  4 1 LOW 12.5 12.5 25.0  5 1 VERY LOW 12.5 25.0 25.0  6 1 lt;NAgt; 25.0 0.0 12.5   

Или другой вариант-изменить форму в «длинный» формат с pivot_longer помощью , выполните count и измените форму обратно в «широкий» формат с помощью pivot_wider

 library(tidyr) df1 %gt;%   select(-Asset) %gt;%   pivot_longer(cols = starts_with("CONF"), values_to = 'CONFIDENCE') %gt;%   count(ID, name, CONFIDENCE) %gt;%  group_by(ID, name) %gt;%  mutate(n = 100 *n/sum(n) ) %gt;%  ungroup %gt;%  pivot_wider(names_from = name, values_from = n, values_fill = 0)  

-выход

 # A tibble: 6 × 5  ID CONFIDENCE CONF_1 CONF_2 CONF_3  lt;intgt; lt;chrgt; lt;dblgt; lt;dblgt; lt;dblgt; 1 1 LOW 12.5 12.5 25  2 1 MEDIUM 25 25 12.5 3 1 PERFECT 25 12.5 12.5 4 1 VERY LOW 12.5 25 25  5 1 lt;NAgt; 25 0 12.5 6 1 HIGH 0 25 12.5  

данные

 df1 lt;- structure(list(ID = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), Asset = c("A",  "B", "C", "D", "E", "F", "G", "H"), CONF_1 = c("PERFECT", "PERFECT",  "LOW", NA, "MEDIUM", "MEDIUM", "VERY LOW", NA), CONF_2 = c("HIGH",  "LOW", "HIGH", "MEDIUM", "MEDIUM", "VERY LOW", "VERY LOW", "PERFECT" ), CONF_3 = c("LOW", "LOW", "VERY LOW", "MEDIUM", "PERFECT",  NA, "VERY LOW", "HIGH")), class = "data.frame", row.names = c(NA,  -8L))  

Комментарии:

1. Блестяще — я начал использовать pivot_wider, но это фантастика. Спасибо.

2. есть ли способ заказать по идентификатору, а затем по уровням ДОВЕРИЯ? Таким образом, каждый идентификатор имеет одинаковый порядок уровней достоверности, и он сбрасывается для каждого идентификатора.

3. @Dinho Вы можете указать arrange(ID, factor(CONFIDENCE, levels = c("PERFECT", "HIGH", "MEDIUM", "LOW", "VERY LOW"))) промежуток между

Ответ №2:

Решение, основанное на reshape2 :

 library(dplyr) library(reshape2)  df %gt;%   melt(id.vars="ID", measure.vars=paste0("CONF_",1:3), variable.name="X") %gt;%   dcast(ID   X ~ value, fun.aggregate = length) %gt;%   melt(id.vars=c("ID","X"), measure.vars=3:ncol(.) ) %gt;%   dcast(ID variable ~ X) %gt;%   group_by(ID) %gt;%   mutate(across(starts_with("CONF_"), ~ .x*100 /sum(.x))) %gt;%   rename(CONFIDENCE=variable) %gt;%   arrange(ID,CONFIDENCE)