#r
#r
Вопрос:
Есть ли какая-либо функция R, которая могла бы дать мне непосредственно тот же вывод таблицы proc ??
var1lt;-c(rep("A",4),rep("B",4)) var2lt;-c(rep("C",4),rep("D",4)) var3lt;-c(rep("E",2),rep("F",4),rep("G",2)) datasetlt;-data.frame(var1,var2,var3)
proc tabulate data=dataset; class var1 var2 var3; table var1*var2 ,var3 all (n rowpctn); run;
Результат, который я хочу получить, выглядит примерно так:
Комментарии:
1. хорошо, я изменил сообщение, предоставив более подробную информацию
Ответ №1:
Вот способ с R
—
- Создайте столбец из 1 —
n
- Разверните данные, чтобы заполнить недостающие комбинации —
complete
- Измените формат на «широкий» —
pivot_wider
- Создайте столбец «Итого», получив сумму по строкам —
rowSums
- Добавьте процент, зациклив
across
столбцы «var3»
library(dplyr) library(tidyr) library(stringr) dataset %gt;% mutate(n = 1, var3 = str_c('var3_', var3)) %gt;% complete(var1, var2, var3, fill = list(n = 0)) %gt;% pivot_wider(names_from = var3, values_from = n, values_fn = sum) %gt;% mutate(Total = rowSums(across(where(is.numeric)))) %gt;% group_by(var1) %gt;% mutate(across(starts_with('var3'), ~ case_when(. == 0 ~ '0(0%)', TRUE ~ sprintf('%d(%d%%)', ., 100 * mean(. != 0))))) %gt;% ungroup
-выход
# A tibble: 4 × 6 var1 var2 var3_E var3_F var3_G Total lt;chrgt; lt;chrgt; lt;chrgt; lt;chrgt; lt;chrgt; lt;dblgt; 1 A C 2(50%) 2(50%) 0(0%) 4 2 A D 0(0%) 0(0%) 0(0%) 0 3 B C 0(0%) 0(0%) 0(0%) 0 4 B D 0(0%) 2(50%) 2(50%) 4
Обновить
Основываясь на комментариях @IceCreamToucan, была ошибка, которая исправлена в приведенном ниже коде
dataset %gt;% mutate(n = 1, var3 = str_c('var3_', var3)) %gt;% complete(var1, var2, var3, fill = list(n = 0)) %gt;% pivot_wider(names_from = var3, values_from = n, values_fn = sum) %gt;% mutate(Total = rowSums(across(where(is.numeric))), 100 * across(starts_with('var3'), ~ . != 0, .names = "{.col}_perc")/rowSums(across(starts_with('var3'), ~ .!= 0)), across(matches('var3_[A-Z]
Комментарии:
1. Я не думаю, что последний шаг-это правильный расчет процентов. Должно быть по строке, а не по столбцу (используется SAS rowpctn). Так уж получилось, что в этом примере проценты строк и столбцов совпадают, поэтому результаты совпадают. Но это не всегда так. Например, начните с
dataset %gt;% bind_rows(tibble(var1 = 'A', var2 = 'D', var3 = 'E'))
вместоdataset
, и проценты в первой строке составят 150%.2. @IceCreamToucan можете ли вы проверить обновленный код
3. Теперь он правильно вычисляет проценты на основе строки
Ответ №2:
Вот более общая версия, в которой я определяю функцию.
var1lt;-c(rep("A",4),rep("B",4)) var2lt;-c(rep("C",4),rep("D",4)) var3lt;-c(rep("E",2),rep("F",4),rep("G",2)) dflt;-data.frame(var1,var2,var3) df_tabulate(df, id_cols = c(var1, var2), names_from = var3) #gt; # A tibble: 4 × 6 #gt; var1 var2 var3_E var3_F var3_G Total #gt; lt;chrgt; lt;chrgt; lt;chrgt; lt;chrgt; lt;chrgt; lt;dblgt; #gt; 1 A C 2(50.0%) 2(50.0%) 0(0.0%) 4 #gt; 2 A D 0(0%) 0(0%) 0(0%) 0 #gt; 3 B C 0(0%) 0(0%) 0(0%) 0 #gt; 4 B D 0(0.0%) 2(50.0%) 2(50.0%) 4
Вы можете определить функцию с помощью janitor
library(janitor, warn.conflicts = FALSE) library(dplyr, warn.conflicts = FALSE) library(rlang) library(tidyr) df_tabulate lt;- function(df, id_cols, names_from){ id_cols lt;- enquo(id_cols) if (quo_is_call(id_cols, 'c')) id_cols lt;- call_args(id_cols) else id_cols lt;- ensym(id_cols) names_from_chr lt;- as_label(enquo(names_from)) counts lt;- df %gt;% mutate(g = eval(call2(paste, !!!id_cols, sep = ',')), col = paste0(names_from_chr, '_', {{ names_from }})) %gt;% tabyl(g, col) %gt;% adorn_totals('col') percs lt;- adorn_percentages(counts) %gt;% adorn_pct_formatting() rbind(counts, percs) %gt;% group_by(g) %gt;% summarise(across(-Total, ~ paste0(first(.), '(', last(.), ')')), Total = as.numeric(first(Total))) %gt;% separate(g, into = as.character(id_cols)) %gt;% complete(!!!id_cols) %gt;% mutate(across(starts_with(names_from_chr), ~ coalesce(., '0(0%)')), across(Total, ~ coalesce(., 0))) }
Ответ №3:
Здесь он представляет собой единый конвейер с дискретными простыми шагами. Конечно, долго, но если бы вам нужно было много таких таблиц, вы могли бы сохранить их как функцию.
library(tidyverse) library(janitor) dataset %gt;% mutate(across(var1:var2, as.factor)) %gt;% count(var1, var2, var3, .drop = FALSE) %gt;% unite(vars, var1, var2) %gt;% pivot_wider(names_from = var3, values_from = n) %gt;% select(-`NA`) %gt;% replace(is.na(.), 0) %gt;% adorn_totals("col") %gt;% adorn_percentages(,,,,-c(vars, Total)) %gt;% adorn_pct_formatting(digits = 0,,,,-c(vars, Total)) %gt;% adorn_ns(position = "front",,,-c(vars, Total)) %gt;% separate(vars, into = c("var1", "var2")) #gt; # A tibble: 4 x 6 #gt; var1 var2 E F G Total #gt; lt;chrgt; lt;chrgt; lt;chrgt; lt;chrgt; lt;chrgt; lt;dblgt; #gt; 1 A C 2 (50%) 2 (50%) 0 (0%) 4 #gt; 2 A D 0 (-) 0 (-) 0 (-) 0 #gt; 3 B C 0 (-) 0 (-) 0 (-) 0 #gt; 4 B D 0 (0%) 2 (50%) 2 (50%) 4
Это заменяет сомнительное 0/0 = 0%
просто -
для более чистого(IMO) результата.
), ~ case_when(. == 0 ~ '0(0%)', TRUE ~ sprintf('%d(%.f%%)', ., get(str_c(cur_column(), '_perc')))))) %gt;% select(-ends_with('perc'))
Комментарии:
1. Я не думаю, что последний шаг-это правильный расчет процентов. Должно быть по строке, а не по столбцу (используется SAS rowpctn). Так уж получилось, что в этом примере проценты строк и столбцов совпадают, поэтому результаты совпадают. Но это не всегда так. Например, начните с
dataset %gt;% bind_rows(tibble(var1 = 'A', var2 = 'D', var3 = 'E'))
вместоdataset
, и проценты в первой строке составят 150%.2. @IceCreamToucan можете ли вы проверить обновленный код
3. Теперь он правильно вычисляет проценты на основе строки
Ответ №2:
Вот более общая версия, в которой я определяю функцию.
Вы можете определить функцию с помощью janitor
Ответ №3:
Здесь он представляет собой единый конвейер с дискретными простыми шагами. Конечно, долго, но если бы вам нужно было много таких таблиц, вы могли бы сохранить их как функцию.
Это заменяет сомнительное 0/0 = 0%
просто -
для более чистого(IMO) результата.