我有一个问题,我想了一段时间,但找不到解决方案。
让我们考虑一些人工数据框,它是 0.9 和 0.1 分位数:
set.seed(42)
x = data.frame("Norm" = rnorm(100),
"Unif" = runif(100),
"Exp" = rexp(100))
quants_b <- apply(x, 2, quantile, 0.90)
quants_s <- apply(x, 2, quantile, 0.10)
我想在这个数据框中做的是检查哪些值大于其对应的分位数 0.9 和小于对应的分位数 0.1,并将所有这些值更改为限制。
简单来说:
我想检查哪些值超过 0.9 分位数,并且所有这些值都转换为 0.9 分位数
我想用 0.1 分位数做同样的事情。
问题的麻烦
我认为这个问题乍一看很容易,但它有一个陷阱——我们必须同时进行转换,因为如果我们先改变上限然后再降低,转换分位数之间可以改变。
(请注意,我们要用 quants_s
和 quants_b
的元素替换第一个变量,用第二个元素替换第二个变量,依此类推)。
我的想法
我的第一个想法是使用 dplyr
包和其中的函数 mutate_all
。
x %>% dplyr::mutate_all(
function(x) {
ifelse(sweep(x, 2,STATS=quants_s, `<`), quants_s,
ifelse(sweep(x, 2,STATS=quants_b, `>`),
quants_b, x)
)
}
)
这段代码直观上非常简单——我们只需将所有小于 quants_s
的值更改为 quants_s
,将大于 quants_b
的值更改为 quants_b
。其余数据保持不变。
但是我遇到了以下错误,我不知道如何省略它:
Error: Problem with `mutate()` input `Norm`.
x 'dims' cannot be of length 0
i Input `Norm` is `(function (x) ...`.
Run `rlang::last_error()` to see where the error occurred.
你能帮我解决这个问题/指出另一个解决方案吗?
答案 0 :(得分:3)
我认为使用“钳位”方法中的 pmin
和 pmax
应该可以轻松解决此问题。
从预先计算限制开始:
quants <- apply(x, 2, quantile, c(0.1, 0.9))
quants
# Norm Unif Exp
# 10% -1.211724 0.08499473 0.1257829
# 90% 1.372974 0.88512802 2.5315087
然后一步应用:
head(x, 15)
# Norm Unif Exp # outside bounds
# 1 1.37095845 0.88511769 0.7350033
# 2 -0.56469817 0.51711106 0.2718374
# 3 0.36312841 0.85193098 1.6570686
# 4 0.63286260 0.44279627 0.9729376
# 5 0.40426832 0.15788010 0.9210097
# 6 -0.10612452 0.44232464 2.4238688
# 7 1.51152200 0.96773367 2.5686363 # <-- Norm Unif Exp
# 8 -0.09465904 0.48458793 1.5920526
# 9 2.01842371 0.25245844 0.3064365 # <-- Norm
# 10 -0.06271410 0.25968998 0.2982843
# 11 1.30486965 0.54201594 1.2682549
# 12 2.28664539 0.64987584 1.5215655 # <-- Norm
# 13 -1.38886070 0.33641913 0.8123740 # <-- Norm
# 14 -0.27878877 0.06094975 0.1296444 # <-- Unif
# 15 -0.13332134 0.45131085 0.2484241
x[] <- Map(function(x, q1, q9) pmax(q1, pmin(q9, x)), x, quants[1,], quants[2,])
head(x, 15)
# Norm Unif Exp
# 1 1.37095845 0.88511769 0.7350033
# 2 -0.56469817 0.51711106 0.2718374
# 3 0.36312841 0.85193098 1.6570686
# 4 0.63286260 0.44279627 0.9729376
# 5 0.40426832 0.15788010 0.9210097
# 6 -0.10612452 0.44232464 2.4238688
# 7 1.37297365 0.88512802 2.5315087 # <-- Norm Unif Exp
# 8 -0.09465904 0.48458793 1.5920526
# 9 1.37297365 0.25245844 0.3064365 # <-- Norm
# 10 -0.06271410 0.25968998 0.2982843
# 11 1.30486965 0.54201594 1.2682549
# 12 1.37297365 0.64987584 1.5215655 # <-- Norm
# 13 -1.21172411 0.33641913 0.8123740 # <-- Norm
# 14 -0.27878877 0.08499473 0.1296444 # <-- Unif
# 15 -0.13332134 0.45131085 0.2484241
答案 1 :(得分:1)
也许我遗漏了一些微妙的东西,但这里有一个使用 dplyr
的直接方法:
library(dplyr)
x %>%
mutate(across(everything(), ~case_when(. > quantile(.,0.9) ~ quantile(.,0.9),
. < quantile(.,0.1) ~ quantile(.,0.1),
TRUE ~ .)))
这里我们可以看到效果:
x %>%
mutate(across(everything(), ~case_when(. > quantile(.,0.9) ~ "High",
. < quantile(.,0.1) ~ "Low",
TRUE ~ ""),.names = "{.col}Δ")) %>%
mutate(across(!contains("Δ"),~case_when(. > quantile(.,0.9) ~ quantile(.,0.9),
. < quantile(.,0.1) ~ quantile(.,0.1),
TRUE ~ .))) %>%
select(sort(tidyselect::peek_vars())) %>%
head(n=15)
# Exp ExpΔ Norm NormΔ Unif UnifΔ
#1 0.7350033 1.37095845 0.88511769
#2 0.2718374 -0.56469817 0.51711106
#3 1.6570686 0.36312841 0.85193098
#4 0.9729376 0.63286260 0.44279627
#5 0.9210097 0.40426832 0.15788010
#6 2.4238688 -0.10612452 0.44232464
#7 2.5315087 High 1.37297365 High 0.88512802 High
#8 1.5920526 -0.09465904 0.48458793
#9 0.3064365 1.37297365 High 0.25245844
#10 0.2982843 -0.06271410 0.25968998
#11 1.2682549 1.30486965 0.54201594
#12 1.5215655 1.37297365 High 0.64987584
#13 0.8123740 -1.21172411 Low 0.33641913
#14 0.1296444 -0.27878877 0.08499473 Low
#15 0.2484241 -0.13332134 0.45131085
答案 2 :(得分:1)
一个选项是
library(dplyr)
x %>%
mutate(across(everything(), ~ifelse(. > quantile(., 0.9), quantile(., 0.9),
ifelse(
. < quantile(., 0.1), quantile(., 0.1),
.))))