使用dplyr创建因子水平的聚合百分比

3

我该如何使用dplyr为每个州创建因子变量的水平比例?例如,我想要添加一个变量,指示每个州内女性所占的百分比至数据框中。

# gen data
state <- rep(c(rep("Idaho", 10), rep("Maine", 10)), 2)
student.id <- sample(1:1000,8,replace=T)
gender <- rep( c("Male","Female"), 100*c(0.25,0.75) )  
gender <- sample(gender, 40)
school.data <- data.frame(student.id, state, gender)

以下是一种我知道是错误的尝试,但可以让我访问信息:

 middle %>%
   group_by(state, gender %in%c("Female")) %>%
   summarise(count = n()) %>%
   mutate(test_count = count)

我在使用count和mutate函数时遇到了困难,这使得进一步的操作变得困难。它的行为不符合我的预期。


1
你想要一个每个州只有一行的新数据框还是你想要你的旧数据框,其中每一行都有该州女性的百分比? - Gregor Thomas
我需要在原始数据框中添加一行,该行将是该州女性的百分比。例如,缅因州女性的值将重复出现在所有缅因州女性中。 - bfoste01
3个回答

11

要向现有数据框添加新列:

school.data %>% 
    group_by(state) %>%
    mutate(pct.female = mean(gender == "Female"))

如果您只想每个州显示一行而不是向原始数据添加列,则使用summarize而不是mutate

school.data %>%
   group_by(state) %>%
   summarize(pct.female = mean(gender == "Female"))
# # A tibble: 2 x 2
#    state pct.female
#   <fctr>      <dbl>
# 1  Idaho       0.75
# 2  Maine       0.70

这会在R-studio中抛出一个错误,因为在mutate表达式的末尾需要一个逗号。此外,如果我的分类变量不是二元的,那么mean函数就无法正常工作,因为我的一些真实数据有多个级别(即>2)。 - bfoste01
1
代码运行良好 - 我建议您重新检查并确保语法正确。我可以添加一个修改以获取更多级别。如果您想要能够推广到更多级别,我很惊讶您没有要求男性百分比列。您是否希望除第一级外的所有级别都有百分比列? - Gregor Thomas
这不是代码行中的错误。我在之前的几行尝试了不同的东西,结果出现了问题,现在已经解决了。我有几个因子变量和多个水平。对于其中一些因子变量,我希望能够选择任何给定水平,并得到每个状态内因子水平百分比。如果是白人、西班牙裔、黑人等,我希望能够计算州内西班牙裔的百分比,并将该列添加到我的数据框中。我并不总是关心其他因子水平的百分比。 - bfoste01
好的,mean 对于百分比拉美裔也可以正常工作,例如 mean(race_ethnicity == "hispanic")。如果您想要复合组(例如,白人或拉美裔的百分比),您仍然可以使用 mean,只需将 == 替换为 %in%,例如 mean(race_ethnicity %in% c("hispanic", "white"))。无论您的数据有2个或更多级别,您的条件都是二进制的(拉美裔/非拉美裔,女性/非女性,拉美裔或白人/非拉美裔或白人...)。 - Gregor Thomas

11

Gregor的回答触及了问题的核心。这里是一个版本,它将为每个州的男女性别分别提供计数和比例:

library(dplyr)

gender.proportions <- group_by(school.data, state, gender) %>% 
  summarize(n = length(student.id)) %>% # count per gender
  ungroup %>% group_by(state) %>% 
  mutate(proportion = n / sum(n)) # proportion per gender

#   state gender     n proportion
#  <fctr> <fctr> <int>      <dbl>
#1  Idaho Female    16       0.80  
#2  Idaho   Male     4       0.20
#3  Maine Female    11       0.55
#4  Maine   Male     9       0.45

编辑:

根据楼主的评论/请求,下面的代码将为每个州的每个学生重复男性和女性比例:

gender.proportions <- group_by(school.data, state) %>% 
  mutate(prop.female = mean(gender == 'Female'), prop.male = mean(gender == 'Male'))

   student.id  state gender prop.female prop.male
        <int> <fctr> <fctr>       <dbl>     <dbl>
1         479  Idaho   Male         0.8       0.2
2         634  Idaho Female         0.8       0.2
3         175  Idaho Female         0.8       0.2
4         527  Idaho Female         0.8       0.2
5         368  Idaho Female         0.8       0.2
6         423  Idaho   Male         0.8       0.2
7         357  Idaho Female         0.8       0.2
8         994  Idaho Female         0.8       0.2
9         479  Idaho Female         0.8       0.2
10        634  Idaho Female         0.8       0.2
# ... with 30 more rows

这非常接近我所需要的。我正在进行多层建模,这很相关,因为基本上我需要的是一个变量,比如prop_female,并且在主数据集中对于所有爱达荷州重复0.80,在所有缅因州重复0.55。 - bfoste01
1
@bfoste01 编辑了我的回复,以确保完全符合要求。 - jdobres
1
我们的解决方案最终基本相同,是的。我最初以为你想要稍微不同的东西。 - jdobres

3

这里有一个使用 left_join 的解决方案。

state <- rep(c(rep("Idaho", 10), rep("Maine", 10)), 2)
student.id <- sample(1:1000,8,replace=T)
gender <- rep( c("Male","Female"), 100*c(0.25,0.75) )  
gender <- sample(gender, 40)
school.data <- data.frame(student.id, state, gender)

school.data %>%
    group_by(state) %>%
    mutate(gender_id = ifelse(gender == "Female", 1, 0)) %>%
    summarise(female_count = sum(gender_id)) %>%

    left_join(school.data %>%
                  group_by(state) %>%
                  summarise(state_count = n()),

              by = c("state" = "state")
    ) %>%
    mutate(percent_female = female_count / state_count)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接