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

R 以编程方式创建新变量,这些变量是其他变量嵌套系列的总和,r,dplyr,tidyverse,purrr,R,Dplyr,Tidyverse,Purrr,我有数据显示某些群体中具有不同教育程度的人的百分比: 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.h

我有数据显示某些群体中具有不同教育程度的人的百分比:

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.
df
如何使用tidyverse工具以编程方式(优雅地)实现这一点

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

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
library(tidyr)
整理结果=df%>%gather(key=“education”、value=“n”、-group)%>%
突变(教育=因子(教育,等级=名称(df)[-1]))%>%
分组依据(分组)%>%
突变(lessthan_x=lag(累积和(n),默认值=0)/sum(n)*100)%>%
安排(团体、教育)
整洁的结果
##A tibble:8 x 4
##组:组[2]
#乐山市团体教育
#                   
#1 A第二中学20 0
#A高中70 20
#3 A学院10 90
#4一名毕业生0 100
#5 B第二中学10 0
#6 B高中40 10
#7 B学院40 50
#8 B毕业生10 90

这给了我们一个好的、整洁的结果。如果您想
传播
/
将这些数据转换成您不整洁的
所需的.df
格式,我建议您使用
data.table::dcast
,因为(据我所知)tidyverse不能提供传播多列的好方法。有关
数据。表
解决方案或不雅观的
tidyr
/
dplyr
版本,请参阅或。在传播之前,您可以创建一个小于的密钥粘贴(“lessthan”,education,sep=“”)
,这里是一个基本的解决方案。虽然这个问题需要一个
tidyverse
one,但考虑到问题评论中的对话,我决定发布它。
它使用
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

tmp没有低于no.highschool的级别,因此lessthan_no.highschool将始终为0。在
desired.df
中,变量
小于.hs
。难道不是吗?高中
?不知道你的意思吗?@lost Gregor抢先告诉我,在你想要的结果中,你重复输入的变量,因此它们的名称应该是相同的。其中一个不是。我以为这是个打字错误。哦,我错过了关于tidyverse的部分,所以我正忙着编写一个基本的R方式。有兴趣吗?那是个打字错误,对不起。修正了。它是故意用不整洁的格式。它采用这种格式是因为它将被连接到各个层次的数据中,这些数据的格式是整齐的,并且将用于建模等等。对,太好了。但是如果你想“优雅地”使用
tidyverse
工具,你需要先整理一下。我链接的问题应该可以帮助你把它恢复到你需要的不整洁的格式。我不认为我需要在这里重复这些答案。如果有更改或更新,则应更新针对该问题的那些问题。虽然变量的顺序与OP中的不同,但这是可行的:desired.df%select(-n)%%>%mutate(education=paste0(“lessthan_u”,education))%%>%spread(education,lessthan_x)%%>%right_join(df)
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