我有数据,可以告诉我某些群体中具有不同教育程度的人的百分比:
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
,但考虑到问题评论中的对话框,我决定发布它。
它使用apply
和cumsum
来完成艰苦的工作。然后,在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 = "_")
。