假设我有一个名为score.master的数据文件,如下所示:
school perc.prof num.tested
A 8 482
B 6-9 34
C 40-49 49
D GE50 81
E 80-89 26在这里,A学校的熟练程度为8%,被测试的学生人数为482人。但是,假设当num.tested低于某个数字(在本例中为任意为100)时,将引入数据抑制。在大多数情况下,给出了perc.prof的范围,但在其他情况下,给出了"GE50“这样的值,表示大于或等于50。
我的问题是,在一个更大的数据集中,用中值替换范围的最佳方法是什么?因此,例如,我希望最后的数据集如下所示:
school perc.prof num.tested
A 8 482
B 8 34
C 44 49
D 75 81
E 85 26我知道这可以像这样手工完成:
score.master$perc.prof[score.master$perc.prof == "6-9"] <- round(median(6:9), 0)但是实际的数据集有更多的范围组合。我认为选择正确值的一种方法是长度;所有提供的值都是1-2个字符长(熟练程度不超过99 %),而范围值是3个或更长的字符。
发布于 2019-09-04 17:56:42
您可以使用stringr::str_split()获得下界和上界,然后计算中值。"GE50“和类似的东西不能泛化,您可以使用ifelse()来处理特殊情况。
df <- data.frame(perc.prof = c('8', '6-9', '40-49', 'GE50', '80-89'))
df$lower.upper <- sapply(stringr::str_split(df$perc.prof, '-'), as.integer)
df$perc.prof.median <- sapply(df$lower.upper, median)
df$lower.upper <- NULL
> df
perc.prof perc.prof.median
1 8 8.0
2 6-9 7.5
3 40-49 44.5
4 GE50 NA
5 80-89 84.5发布于 2019-09-04 17:48:45
这是一个潮汐的方法。首先,我将"GE50“替换为预期的输出,然后在可能的情况下使用tidyr::separate拆分perc.prof。最后一步要么使用给定的perc.prof (如果是大型学校),要么使用小学校的中位数。
library(tidyverse)
df %>%
mutate(perc.prof = if_else(perc.prof == "GE50", "75", perc.prof)) %>%
separate(perc.prof, c("low", "high"), remove = F, convert = T) %>%
mutate(perc.prof.adj = if_else(num.tested > 100,
as.numeric(perc.prof),
rowSums(select(., low, high), na.rm = T)/2)
)
school perc.prof low high num.tested perc.prof.adj
1 A 8 8 NA 482 8.0
2 B 6-9 6 9 34 7.5
3 C 40-49 40 49 49 44.5
4 D 75 75 NA 81 37.5
5 E 80-89 80 89 26 84.5发布于 2019-09-04 17:53:53
您可以执行以下操作以将您的范围与中位数进行转换。但是,我没有处理"GExx“或"LExx”的情况,因为它定义得不够好。
请注意,我的解决方案需要stringr包。
score.master$perc.prof <- sapply(score.master$perc.prof, function(x){
sep <- stringr::str_locate(x, "-")[, 1]
if(is.na(sep)) {
x
} else {
as.character(round(median(as.integer(stringr::str_sub(x, c(1L, sep+1), c(sep-1, -1L))))))
}
})https://stackoverflow.com/questions/57793073
复制相似问题