【问题标题】:Is there a way to filter for 50% response rate in R?有没有办法在 R 中过滤 50% 的响应率?
【发布时间】:2021-11-05 00:47:00
【问题描述】:

我用 6 个问题 [Q1:Q6,有 2 个表达式]、4 个不同的组织单位 [Org_unit,1:4] 和另一个试图找出问题的调查来表示我正在处理的一项调查。 , 对应公司的人是否为经理[经理,1:2],其中[1]代表经理,[2]代表员工。

小标题如下所示: 注意:[-9] 是无响应,因此我将它们分配给 NA。

library(dplyr)

Org_unit <- c(1,1,1,1,2,2,2,3,3,4)
Manager <- c(1,1,2,2,1,1,1,1,2,2)
Q1 <-  c(1,2,1,2,1,2,1,2,1,2)
Q2 <- c(1,-9,-9,-9,-9,-9,-9,-9,-9,-9) #Note one response
Q3 <- c(1,1,2,-9,-9,2,1,1, -9, 1)
Q4 <- c(1,1,-9,1,2,2,-9,1,-9,2)
Q5 <- c(1,-9,-9,-9,-9,-9,-9,-9,-9,-9)
Q6 <- c(1,-9,-9,-9,-9,-9,-9,-9,-9,-9)

df <- tibble(Org_unit, Manager, Q1, Q2, Q3, Q4, Q5, Q6)
df[df == -9] <- NA
df

# A tibble: 10 x 8
   Org_unit Manager    Q1    Q2    Q3    Q4    Q5    Q6
      <dbl>   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1        1       1     1     1     1     1     1     1
 2        1       1     2    NA     1     1    NA    NA
 3        1       2     1    NA     2    NA    NA    NA
 4        1       2     2    NA    NA     1    NA    NA
 5        2       1     1    NA    NA     2    NA    NA
 6        2       1     2    NA     2     2    NA    NA
 7        2       1     1    NA     1    NA    NA    NA
 8        3       1     2    NA     1     1    NA    NA
 9        3       2     1    NA    NA    NA    NA    NA
10        4       2     2    NA     1     2    NA    NA

目的是找出有多少员工(条件 #1,经理必须是 [2])回答了 [1] 的问题。基本上是员工的数量,他们在各自的 org_unit 中用 [1] 回答了特定问题。

示例:org_unit 1 共有 4 个成员。在这 4 人中,只有 2 人符合员工标准(经理 == 2)。 org_unit 1 中的 2 名员工中有 1 人用 [1] 回答了 Q1,换句话说,org_unit 1 中 50% 的员工用 [1] 回答了 Q1。

prop <-df %>%
  group_by(Org_unit) %>%
  filter(Manager == 2) %>%
  summarise(N = n(), 
        across(c(Q1, Q2, Q3, Q4, Q5, Q6), ~mean(. == 1))) 

prop
# A tibble: 3 x 8
  Org_unit     N    Q1    Q2    Q3    Q4    Q5    Q6
     <dbl> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1        1     2   0.5    NA    NA    NA    NA    NA
2        3     1   1      NA    NA    NA    NA    NA
3        4     1   0      NA     1     0    NA    NA

如我们所见,Q1 在 Org_unit 1 中有一个 prop 为 0,5 和总共 N = 2 个成员。所以这似乎可行。

问题是,回答不到所有问题 50% 的个人不应被算作各自小组的成员。让我们再看看 tibble。

# A tibble: 10 x 8
   Org_unit Manager    Q1    Q2    Q3    Q4    Q5    Q6
      <dbl>   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1        1       1     1     1     1     1     1     1
 2        1       1     2    NA     1     1    NA    NA
 3        1       2     1    NA     2    NA    NA    NA
 4        1       2     2    NA    NA     1    NA    NA
 5        2       1     1    NA    NA     2    NA    NA
 6        2       1     2    NA     2     2    NA    NA
 7        2       1     1    NA     1    NA    NA    NA
 8        3       1     2    NA     1     1    NA    NA
 9        3       2     1    NA    NA    NA    NA    NA
10        4       2     2    NA     1     2    NA    NA

个人 3,尽管它符合员工标准(经理 == 2)并且至少有一个问题回答为(Q1 == 1),但 Q2 和 Q4:Q6 是不适用的,因此超过 50%所有的问题都没有回答。

我需要调整道具代码以减少所有未响应的 N 的数量(在这种情况下,org_unit 1 应该减少 2,因为个人 3 和 4,尽管它们符合某些标准,但有 4/ 6 个无响应。同样重要的是,org_unit 1 仍会继续显示在数据框中,而是将 N 列为 NA,并且应根据特定组中适当的成员数量调整比例。

有没有办法解决这个问题?提前致谢!

编辑:阈值应为

结果应该是这样的:

prop
# A tibble: 3 x 8
  Org_unit     N    Q1    Q2    Q3    Q4    Q5    Q6
     <dbl> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1        1    NA    NA    NA    NA    NA    NA    NA
2        2    NA    NA    NA    NA    NA    NA    NA    
3        3    NA    NA    NA    NA    NA    NA    NA
4        4     1     0    NA     1     0    NA    NA

【问题讨论】:

  • 你能更清楚结果应该是什么样子吗?阈值是&lt; .5 还是&lt;= .5?理想情况下,发布您想要的表格作为结果

标签: r proportions


【解决方案1】:

我的理解是,您要计算N 不是dplyr::n(),而是作为Manager == 2 并且回答了(!is.na)至少50% 的问题Q1:Q6 的受访者数量.

我们可以使用dplyr::rowwise 执行此操作,然后按行计算NAsum 是否小于或等于3。然后我们可以恢复原来的计算和group_by(Org_unit),将N每组计算为sum(N),然后在across的函数内使用N作为sum(.x == 1, na.rm = TRUE) / N,而不是使用mean

所提供的数据对于这个特定示例来说并不是很好,因为大多数受访者的回复中有 50% 或更多 NAs。通常N 将是0,因此我们需要一个if else 流来解释我们划分N == 0 的情况。

library(dplyr)

prop <- df %>%
  filter(Manager == 2) %>%
  rowwise() %>% 
  mutate(N = sum(is.na(c_across(Q1:Q6))) <= 3) %>% 
  group_by(Org_unit) %>%
  summarise(N = sum(N),
            across(c(Q1:Q6), ~ if(N > 0) {
              sum(.x == 1, na.rm = TRUE) / N
              } else NA_real_))

prop

#> # A tibble: 3 x 8
#>   Org_unit     N    Q1    Q2    Q3    Q4    Q5    Q6
#>      <dbl> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1        1     0    NA    NA    NA    NA    NA    NA
#> 2        3     0    NA    NA    NA    NA    NA    NA
#> 3        4     1     0     0     1     0     0     0

reprex package (v2.0.1) 于 2021-09-08 创建

正如@mnist 所建议的,这里有一个更具可扩展性的版本:

df %>%
  filter(Manager == 2) %>%
  rowwise() %>% 
  mutate(N = mean(is.na(c_across(starts_with("Q")))) <= 0.5) %>% 
  group_by(Org_unit) %>%
  summarise(N = sum(N),
            across(starts_with("Q"), ~ if(N > 0) {
              sum(.x == 1, na.rm = TRUE) / N
            } else NA_real_))

【讨论】:

  • 问题是您已经对列进行了硬编码,并且 across 中across 选择了多少列?
  • @mnist:这仅涉及带有c_acrossmutate 调用,因此我们可以说&lt;= length(c_across(Q1:Q6))/2 而不是&lt;= 3。当然,Q1:Q6 在示例中在这里是硬编码的,但是&lt;tidyselect&gt; 允许我们选择任意数量的列,所以这应该不是问题。
  • 我将其转换为我的主数据集,但出现错误,“..3 必须是向量,而不是'公式'对象”。我想我必须从头开始构建整个东西,这真的让我感到困惑
  • @Sascha:我认为对across 的调用存在问题。你有没有以任何方式改变它?它是否以~ 开头并且是否包含.x?您可以尝试通过在波浪号 ~ 之前添加 .fn = 来命名函数参数。在没有看到数据或完整错误的情况下,这就是我能想到的。也许您可以添加来自rlang::last_error() 的信息。
【解决方案2】:

这是你要找的吗?

首先在 group_by 中添加语句 .drop = FALSE 以不从原始表中删除 Org_units。然后我们发送rowMeans 来检查是否有 50% 或更多的问题得到了回答。

df %>%
  group_by(Org_unit, .drop = FALSE) %>%
  filter(rowMeans(is.na(across(matches("Q\\d+")))) <= 0.5) %>%
  filter(Manager == 2) %>%
  summarise(N = n(), across(matches("Q\\d+"), ~mean(. == 1))) 

导致:

  Org_unit     N    Q1    Q2    Q3    Q4    Q5    Q6
     <dbl> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1        1     0   NaN   NaN   NaN   NaN   NaN   NaN
2        2     0   NaN   NaN   NaN   NaN   NaN   NaN
3        3     0   NaN   NaN   NaN   NaN   NaN   NaN
4        4     1     0    NA     1     0    NA    NA

【讨论】:

  • 不完全是 OP 想要的结果,但我的主要问题是您已经对列进行了硬编码,&lt;=3 可以很好地扩展到未知数量的问题列,对吧?
  • 虽然这适用于示例数据帧,但一旦我将此代码传输到真实数据帧,它会跳过一些 org_units 并且它们不会出现。我仍在试图找出原因
  • @mnist 增加了可扩展性
  • @Sascha 尝试在第一个过滤器之前执行group_by。我可以想象这就是跳过一些 Org_units 的原因。我会相应地编辑我的答案
  • 谢谢,这停止了跳过 Org_units!但不幸的是,N Column 没有计算正确的成员数量。我手动将其与原始数据框进行了比较,不知何故 N 已关闭,因此比例也不正确
【解决方案3】:

Idea 与 @Tim 类似,但 rowwise 使用 pmap_int

df %>%
  filter(Manager == 2) %>%
  mutate(
    count = pmap_int(
      select(., matches("^Q[0-9]+$")),
      ~sum(is.na(c(...))) * 2 <= length(c(...))
    ) 
  ) %>%
  group_by(Org_unit) %>%
  summarise(
    N = sum(count),
    N = ifelse(N > 0, N, NA_integer_),
    across(matches("^Q[0-9]+$"), ~sum(.x == 1) / N)
  )

【讨论】:

  • 喜欢可伸缩性,因为您没有指定列名或列数!
  • 可以通过添加min_answer_perc = 0.5然后更改为sum(is.na(c(...))) / length(c(...)) &lt;= 1-min_answer_perc 来进行更多概括
猜你喜欢
  • 1970-01-01
  • 2021-11-09
  • 2010-09-08
  • 1970-01-01
  • 1970-01-01
  • 2019-05-14
  • 2021-08-20
  • 2021-09-09
  • 1970-01-01
相关资源
最近更新 更多