如何根据具有名称类型的变量在 R 中过滤和计数
Posted
技术标签:
【中文标题】如何根据具有名称类型的变量在 R 中过滤和计数【英文标题】:How to filter and count in R based on variables with a type of name 【发布时间】:2021-09-13 14:15:33 【问题描述】:我在 R 中有如下教育数据:
df <- data.frame(
"StudentID" = c(101, 102, 103, 104, 105, 106, 111, 112, 113, 114, 115, 116, 121, 122, 123, 124, 125, 126),
"FedEthn" = c(1, 1, 2, 2, 3, 3, 1, 1, 2, 2, 3, 3, 1, 1, 2, 2, 3, 3),
"HIST.11.LEV" = c(1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 5, 3, 3),
"HIST.11.SCORE" = c(96, 95, 95, 97, 88, 99, 89, 96, 79, 83, 72, 95, 96, 93, 97, 98, 96, 87),
"HIST.12.LEV" = c(2, 2, 1, 2, 1, 1, 2, 3, 2, 2, 2, 2, 4, 3, 3, 3, 3, 3),
"SCI.9.LEV" = c(1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3),
"SCI.9.SCORE" = c(91, 99, 82, 95, 65, 83, 96, 97, 99, 94, 95, 96, 89, 78, 96, 95, 97, 90),
"SCI.10.LEV" = c(1, 2, 1, 2, 1, 1, 3, 3, 2, 2, 2, 3, 3, 3, 4, 3, 4, 3)
)
## StudentID FedEthn HIST.11.LEV HIST.11.SCORE HIST.12.LEV SCI.9.LEV SCI.9.SCORE SCI.10.LEV
## 1 101 1 1 96 2 1 91 1
## 2 102 1 1 95 2 1 99 2
## 3 103 2 1 95 1 1 82 1
## 4 104 2 1 97 2 1 95 2
## 5 105 3 1 88 1 1 65 1
## 6 106 3 1 99 1 1 83 1
## 7 111 1 2 89 2 2 96 3
## 8 112 1 2 96 3 2 97 3
## 9 113 2 2 79 2 2 99 2
## 10 114 2 2 83 2 2 94 2
## 11 115 3 2 72 2 2 95 2
## 12 116 3 2 95 2 2 96 3
## 13 121 1 3 96 4 3 89 3
## 14 122 1 3 93 3 3 78 3
## 15 123 2 3 97 3 3 96 4
## 16 124 2 3 98 3 3 95 3
## 17 125 3 3 96 3 3 97 4
## 18 126 3 3 87 3 3 90 3
HIST.11.LEV 代表学生在 11 年级历史课程中的学术水平。 (5 = 最高学术水平,1 = 最低学术水平。例如,5 可能是 AP 或 IB 课程。)HIST.11.SCORE 表示学生在课程中的分数。
当学生在一门课程中获得 95 分或更高分时,他们就有资格在下一年升读更高的学术水平(例如 HIST.12.LEV = 1 + HIST.11.LEV)。然而,这些符合条件的学生中只有一部分真正升迁,老师必须同意。我正在分析的是,符合条件的学生的升学率是否因报告的联邦种族而异。
到目前为止,我是这样实现的:
var.level <- 1
var.ethn <- 1
actual.move.ups <-
(df %>% filter(FedEthn==var.ethn,
HIST.11.LEV==var.level,
HIST.11.SCORE>94,
HIST.12.LEV==var.level+1) %>%
count) +
(df %>% filter(FedEthn==var.ethn,
SCI.9.LEV==var.level,
SCI.9.SCORE>94,
SCI.10.LEV==var.level+1) %>%
count)
eligible.move.ups <-
(df %>% filter(FedEthn==var.ethn,
HIST.11.LEV==var.level,
HIST.11.SCORE>94) %>%
count) +
(df %>% filter(FedEthn==var.ethn,
SCI.9.LEV==var.level,
SCI.9.SCORE>94) %>%
count)
这可行,我可以从 1:5 迭代 var.level 并从 1:7 迭代 var.ethnicity 并将结果存储在数据框中。但在我的实际数据中,这种方法需要 df %>% filter(...) %>% count 的 15 次迭代(我会将它们全部相加)。原因是,在我的实际数据中,有 15 个机会在 5 个科目(HIST、SCI、MATH、ENG、WL)和 4 个年级(9、10、11、12)之间升迁。
我的问题是,是否有一种更紧凑的方法来过滤和计算 COURSE.GRADE.LEV==i、COURSE.GRADE+1.LEV==i+1 和 COURSE.GRADE.SCORE>94 的所有实例键入/硬编码每个课程名称(HIST、SCI、MATH、ENG、WL)和每个年级(9、10、11、12)。而且,将结果存储在数据框中的最佳方式是什么?
对于我上面的示例数据,这是理想的输出。不过,数据框不需要具有这种精确的结构。
## FedEthn L1.Actual L1.Eligible L2.Actual L2.Eligible L3.Actual L3.Eligible
## 1 1 3 3 3 3 1 1
## 2 2 2 3 0 1 1 3
## 3 3 0 1 1 3 1 2
*注意:我读过this helpful answer,但是对于我的变量名,年级(9、10、11、12)没有一致的字符串位置(例如,SCI。9 与 HIST。11)。此外,在某些情况下,我需要多次计算一行,因为一个学生可以在多个班级中升迁。也许解决方案是在执行计数之前将数据从宽调整为长?
【问题讨论】:
为了更清楚起见,我不只是获得每个种族的总总数/计数是有原因的。在某些学术水平(.LEV = 2 和 3)中,学生升迁的比例通常更高。而且种族分布在各个学术层次上也不尽相同。这就是为什么我需要在每个学术级别(.LEV = 1 到 5)重复计数。 【参考方案1】:使用来自@akrun 的this great answer,我想出了一个解决方案。不过,我认为我仍然让它变得不必要地复杂,我希望接受其他人更简洁的答案。
course.names <- c("HIST.","SCI.")
grade.levels <- 9:11
tally.actual <- function(var.ethn, var.level)
total.tally.actual <- NULL
for(i in course.names)
course.tally.actual <- NULL
for(j in grade.levels)
new.tally.actual <- df %>% filter(
FedEthn == var.ethn,
!!(rlang::sym(paste0(i,j,".LEV"))) == var.level,
!!(rlang::sym(paste0(i,(j+1),".LEV"))) == (var.level+1),
!!(rlang::sym(paste0(i,j,".SCORE"))) > 94
) %>% count
course.tally.actual <- c(new.tally.actual, course.tally.actual)
total.tally.actual <- c(total.tally.actual, course.tally.actual)
return(sum(unlist(total.tally.actual)))
tally.eligible <- function(var.ethn, var.level)
total.tally.eligible <- NULL
for(i in course.names)
course.tally.eligible <- NULL
for(j in grade.levels)
new.tally.eligible <- df %>% filter(
FedEthn == var.ethn,
!!(rlang::sym(paste0(i,j,".LEV"))) == var.level,
!!(rlang::sym(paste0(i,j,".SCORE"))) > 94
) %>% count
course.tally.eligible <- c(new.tally.eligible, course.tally.eligible)
total.tally.eligible <- c(total.tally.eligible, course.tally.eligible)
return(sum(unlist(total.tally.eligible)))
results <- data.frame("FedEthn" = 1:3,
"L1.Actual" = NA, "L1.Eligible" = NA,
"L2.Actual" = NA, "L2.Eligible" = NA,
"L3.Actual" = NA, "L3.Eligible" = NA)
for(var.ethn in 1:3)
for(var.level in 1:3)
results[var.ethn,(var.level*2)] <- tally.actual(var.ethn,var.level)
results[var.ethn,(var.level*2+1)] <- tally.eligible(var.ethn,var.level)
这种方法有效,但它要求 df 包含课程(SCI、MATH、HIST、ENG、WL)和年份(9、10、11、12)的所有组合。请参阅下文了解我如何添加到原始 df。包括所有可能的组合对我的实际数据来说不是问题,但我希望有一个解决方案不需要添加一堆用 NA 填充的列:
df$HIST.9.LEV = NA
df$HIST.9.SCORE = NA
df$HIST.10.LEV = NA
df$HIST.10.SCORE = NA
df$HIST.12.SCORE = NA
df$SCI.10.SCORE = NA
df$SCI.11.LEV = NA
df$SCI.11.SCORE = NA
df$SCI.12.LEV = NA
df$SCI.12.SCORE = NA
【讨论】:
以上是关于如何根据具有名称类型的变量在 R 中过滤和计数的主要内容,如果未能解决你的问题,请参考以下文章
如何创建具有 1 个自变量和 3 个因变量的计数和百分比表和折线图