这个 dplyr group_by 代码的 Base R 等价物是什么?

问题描述

The R4DS book 具有以下代码块:

library(tidyverse)
by_age2 <- gss_cat %>%
  filter(!is.na(age)) %>%
  count(age,marital) %>%
  group_by(age) %>%
  mutate(prop = n / sum(n))

在基本 R 中是否有与此代码等效的简单代码filter 可以替换为 gss_cat[!is.na(gss_cat$age),],但之后我遇到了麻烦。这显然是 bytapplyaggregate 的工作,但我一直找不到正确的方法by(gss_2,with(gss_2,list(age,marital)),length) 是朝着正确方向迈出的一步,但结果很糟糕。

解决方法

我们可以在 proportions 删除 table (subset) 和 NA 列之后在 complete.cases 输出上使用 select

数据来自 forcats 包。所以,加载包并获取数据

library(forcats)
data(gss_cat)

使用上面提到的table/proportions

by_age2_base <- proportions(table(subset(gss_cat,complete.cases(age),select = c(age,marital))),1)

-输出

head(by_age2_base,3)
    marital
age    No answer Never married   Separated    Divorced     Widowed     Married
  18 0.000000000   0.978021978 0.000000000 0.000000000 0.000000000 0.021978022
  19 0.000000000   0.939759036 0.000000000 0.012048193 0.004016064 0.044176707
  20 0.000000000   0.904382470 0.003984064 0.007968127 0.000000000 0.083665339

-与 OP 的输出进行比较

head(by_age2,3)
# A tibble: 3 x 4
# Groups:   age [2]
    age marital           n   prop
  <int> <fct>         <int>  <dbl>
1    18 Never married    89 0.978 
2    18 Married           2 0.0220
3    19 Never married   234 0.940 

如果我们需要'long'格式的输出,用tabledata.frame转换成as.data.frame

by_age2_base_long <- subset(as.data.frame(by_age2_base),Freq > 0)

或者另一个选项是aggregate/ave(使用R 4.1.0

subset(gss_cat,marital)) |> 
    {\(dat) aggregate(cbind(n = age) ~ age + marital,data = dat,FUN = length)}() |> 
   transform(prop = ave(n,age,FUN = \(x) x/sum(x)))