как получить вывод таблицы proc (SAS) в R

#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. Создайте столбец из 1 — n
  2. Разверните данные, чтобы заполнить недостающие комбинации — complete
  3. Измените формат на «широкий» — pivot_wider
  4. Создайте столбец «Итого», получив сумму по строкам — rowSums
  5. Добавьте процент, зациклив 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) результата.