【问题标题】:Change column values when specific condition is satisfied满足特定条件时更改列值
【发布时间】:2021-06-26 16:51:46
【问题描述】:

我有一个问题,我想了一段时间,但无法找出解决方案。

让我们考虑一些人工数据框,它是 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_squants_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.1-ile,那么无论我们如何处理另一个值(可能高于或不高于 0.9-ile),当第二次操作完成时,这个数字就是 仍然低于0.1-ile。

标签: r dataframe if-statement dplyr


【解决方案1】:

我认为这应该可以通过pminpmax 在“钳制”方法中轻松解决。

从预先计算限制开始:

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

【讨论】:

    【解决方案2】:

    也许我遗漏了一些微妙的东西,但这是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      
    

    【讨论】:

      【解决方案3】:

      一个选项是

      library(dplyr)
      x %>%
         mutate(across(everything(), ~ifelse(. > quantile(., 0.9), quantile(., 0.9),
                                       ifelse(
                                           . < quantile(., 0.1), quantile(., 0.1),
                                            .))))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-05-19
        • 1970-01-01
        • 2021-05-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-16
        • 2013-05-28
        相关资源
        最近更新 更多