尝试按组获取频率计数和 R 中数据框中每一列的百分比

Trying to get frequnecy counts and percent by group of each column in data frame in R

我有这样的数据:

   pat# sex race    group   bmi
    1   F   Black   1   4
    2   M   Asian   2   8
    3   M   Asian   3   19
    4   M   Asian   1   35
    5   F   Black   2   12
    6   F   Black   3   33
    7   M   White   1   2
    8   F   Black   2   35
    9   M   Asian   3   6
    10  F   Black   1   13
    11  F   Black   2   18
    12  F   Asian   3   1
    13  M   White   1   36
    14  F   Asian   2   25
    15  M   White   3   6
    16  M   White   1   20
    17  F   Black   2   3
    18  M   Asian   3   23
    19  F   Black   1   26
    20  F   Asian   2   13
    21  M   White   3   21
    22  M   White   1   16
    23  F   Black   2   29
    24  F   Black   3   19
    25  M   Asian   1   17
    26  M   Asian   2   22
    27  F   Black   3   26

我想得到每个变量的频率和每个变量的分组百分比,如下所示:

        n           1   2   3
sex M   frequency   %   %   %
    F   frequency   %   %   %

下一个变量:

                n          1    2   3
race    White   frequency   %   %   %
        Asian   frequency   %   %   %
        Black   frequency   %   %   %

变量很多,所以我不想一一列出。我尝试使用 xtabs()dplyr 包来使用 R 的矢量功能 (df[2:30]),但我没有让它工作。哪个包或函数并不重要,但希望使其足够灵活,以便将来使用不同列名和具有不同维度的数据。非常感谢任何建议!!

一种方法是使用 janitor 包,但它也会将总数更改为百分比:

library(janitor)

df %>%
  tabyl(sex, group) %>%
  adorn_totals("col") %>%
  adorn_percentages() %>%
  adorn_pct_formatting(digits = 2)

 sex      1      2      3   Total
   F 21.43% 50.00% 28.57% 100.00%
   M 46.15% 15.38% 38.46% 100.00%

#But we could also choose counts
df %>%
  tabyl(sex, group) %>%
  adorn_totals("col")

 sex 1 2 3 Total
   F 3 7 4    14
   M 6 2 5    13

一个tidyverse方式是-

library(tidyverse)

df %>%
  count(sex, group) %>%
  group_by(sex) %>%
  mutate(n = prop.table(n) * 100) %>%
  pivot_wider(names_from = group, values_from = n, values_fill = 0)

#  sex     `1`   `2`   `3`
#  <chr> <dbl> <dbl> <dbl>
#1 F      21.4  50    28.6
#2 M      46.2  15.4  38.5

如果你想对多个变量执行此操作,你可以使用 map -

cols <- c('sex', 'race')

map(cols, ~df %>%
      count(.data[[.x]], group) %>%
      group_by(.data[[.x]]) %>%
      mutate(n = prop.table(n) * 100) %>%
      pivot_wider(names_from = group, values_from = n, values_fill = 0) %>%
      ungroup)

#[[1]]
# A tibble: 2 x 4
#  sex     `1`   `2`   `3`
#  <chr> <dbl> <dbl> <dbl>
#1 F      21.4  50    28.6
#2 M      46.2  15.4  38.5

#[[2]]
# A tibble: 3 x 4
#  race    `1`   `2`   `3`
#  <chr> <dbl> <dbl> <dbl>
#1 Asian  20    40    40  
#2 Black  27.3  45.5  27.3
#3 White  66.7   0    33.3

如果你需要频率,你可以这样做:

lapply(df[2:3], table, df$group)
$race
       
        1 2 3
  Asian 2 4 4
  Black 3 5 3
  White 4 0 2

$group
   
    1 2 3
  1 9 0 0
  2 0 9 0
  3 0 0 9

如果您需要百分比,则必须定义您需要的百分比,即按行、按列、总计等

如果需要按行:

lapply(df[2:3], function(x)prop.table(table(x, df$group),1)*100)
$sex
   
x          1        2        3
  F 21.42857 50.00000 28.57143
  M 46.15385 15.38462 38.46154

$race
       
x              1        2        3
  Asian 20.00000 40.00000 40.00000
  Black 27.27273 45.45455 27.27273
  White 66.66667  0.00000 33.33333

我能够使用 table() 函数和 tigerstats 包来做到这一点。我遇到的主要问题是 R 会以不同于 CSV 数据集的方式对待 SAS 数据集。白天和黑夜!