问题描述
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),]
,但之后我遇到了麻烦。这显然是 by
、tapply
或 aggregate
的工作,但我一直找不到正确的方法。 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'格式的输出,用table
将data.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)))