r语言 - 以编程方式创建新变量,这些变量是其他变量的嵌套系列的总和



我有数据,可以告诉我某些群体中具有不同教育程度的人的百分比:

df <- data_frame(group = c("A", "B"),
no.highschool = c(20, 10),
high.school = c(70,40),
college = c(10, 40),
graduate = c(0,10))
df
# A tibble: 2 x 5
group no.highschool high.school college graduate
<chr>         <dbl>       <dbl>   <dbl>    <dbl>
1 A               20.         70.     10.       0.
2 B               10.         40.     40.      10.

例如,在A组中,70%的人受过高中教育。

我想生成 4 个变量,这些变量给我每个组中低于 4 个教育级别中每个级别(例如,lessthan_no.高中、lessthan_high.学校等(的人的比例。

所需的DF将是:

desired.df <- data.frame(group = c("A", "B"),
no.highschool = c(20, 10),
high.school = c(70,40),
college = c(10, 40),
graduate = c(0,10),
lessthan_no.highschool = c(0,0),
lessthan_high.school = c(20, 10),
lessthan_college = c(90, 50),
lessthan_graduate = c(100, 90))

在我的实际数据中,我有很多群体和更多的教育水平。当然,我可以一次执行一个变量,但是如何使用tidyverse工具以编程方式(优雅地(执行此操作?

我会从在map()内做一些类似mutate_at()的事情开始,但我被绊倒的地方是每个新变量的求和变量列表都是不同的。您可以将新变量及其相应的变量列表作为两个列表传递给一个pmap(),但如何简洁地生成第二个列表并不明显。想知道是否有某种嵌套解决方案...

下面是一个基本的 R 解决方案。虽然这个问题要求tidyverse,但考虑到问题评论中的对话框,我决定发布它。
它使用applycumsum来完成艰苦的工作。然后,在cbind最终结果之前,有一些外观问题。

tmp <- apply(df[-1], 1, function(x){
s <- cumsum(x)
100*c(0, s[-length(s)])/sum(x)
})
rownames(tmp) <- paste("lessthan", names(df)[-1], sep = "_")
desired.df <- cbind(df, t(tmp))
desired.df
#  group no.highschool high.school college graduate lessthan_no.highschool
#1     A            20          70      10        0                      0
#2     B            10          40      40       10                      0
#  lessthan_high.school lessthan_college lessthan_graduate
#1                   20               90               100
#2                   10               50                90
如何使用

整洁的宇宙工具以编程方式(优雅地(做到这一点?

当然,第一步是整理数据。列名中的编码信息(如 edu 级别(不整洁。将education转换为因子时,请确保级别顺序正确 - 我使用了它们在原始数据列名称中出现的顺序。

library(tidyr)
tidy_result = df %>% gather(key = "education", value = "n", -group) %>%
mutate(education = factor(education, levels = names(df)[-1])) %>%
group_by(group) %>%
mutate(lessthan_x = lag(cumsum(n), default = 0) / sum(n) * 100) %>%
arrange(group, education)
tidy_result
# # A tibble: 8 x 4
# # Groups:   group [2]
#   group education         n lessthan_x
#   <chr> <fct>         <dbl>      <dbl>
# 1 A     no.highschool    20          0
# 2 A     high.school      70         20
# 3 A     college          10         90
# 4 A     graduate          0        100
# 5 B     no.highschool    10          0
# 6 B     high.school      40         10
# 7 B     college          40         50
# 8 B     graduate         10         90

这给了我们一个漂亮、整洁的结果。如果您想spread/cast这些数据转换为不整洁的desired.df格式,我建议您使用data.table::dcast,因为(据我所知(整洁的宇宙并没有提供传播多列的好方法。请参阅使用 tidyr 展开多列或如何将多个变量的重复度量展开为宽格式?对于data.table解决方案或不优雅的tidyr/dplyr版本。在传播之前,您可以创建一个密钥less_than_x_key = paste("lessthan", education, sep = "_")

最新更新