【问题标题】:ifelse with sorted values by rowifelse 按行排序值
【发布时间】:2021-10-24 17:27:47
【问题描述】:

我有一个数据框(示例数据):

id <- c(1, 2, 3)
ex1 <- c(0.8,   0.2, 0.3)
ex2 <- c(0.1,   0.4, 0.04)
ex3 <- c(0.04,  0.3, 0.5)
ex <- c(1, 1, 1)
ran <- c(0.5, 0.7, 0.6)
dat <- data.frame(id, ex1, ex2, ex3, ex, ran)

dat
  id ex1  ex2  ex3 ex ran
1  1 0.8 0.10 0.04  1 0.5
2  2 0.2 0.40 0.30  1 0.7
3  3 0.3 0.04 0.50  1 0.6

我想用 if-else-condition 更改“ex”的值。当“ran”小于或等于 ex$ 变量的最大值时,“ex”应更改为 5(任意)。它也应该大于其他 ex$ 变量,但它们应该被排序 - 第二大值添加到最小值。以下是所有 id 的示例,从 id 1 开始:

dat$ex <- ifelse(dat$ran <= dat$ex1 & dat$ran > dat$ex1 + dat$ex2, 5, dat$ex)

这里ex1是最大值,其次是ex1和ex2。

对于 id 2,应该是:

dat$ex <- ifelse(dat$ran <= dat$ex2 & dat$ran > dat$ex3 + dat$ex1, 5, dat$ex)

这里ex2是最大值,其次是ex3,然后是ex1。

对于 id 3:

dat$ex <- ifelse(dat$ran <= dat$ex3 & dat$ran > dat$ex1 + dat$ex2, 5, dat$ex)

这里ex3是最大值,其次是ex1,然后是ex2。

现在的问题是:如何概括 ifelse 语句?注意:重要的是,两个较小值的总和按照示例中的实现方式执行。我需要通过 id 在 ifelse 中识别 ex1、ex2 和 ex3 的排序值。

【问题讨论】:

    标签: r if-statement


    【解决方案1】:

    这是我们使用dplyrtidyr 完成任务的一种方法:

    library(dplyr)
    library(tidyr)
    dat %>% 
      pivot_longer(
        cols = ex1:ex3
      ) %>% 
      arrange(id, desc(value)) %>% 
      group_by(id) %>% 
      mutate(ex = ifelse(ran <= value[1] & ran > sum(value[2], value[3]), 5, ex)) %>% 
      pivot_wider(
        names_from=name
      ) 
    

    输出:

     id    ex   ran   ex1   ex2   ex3
      <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
    1     1     5   0.5   0.8  0.1   0.04
    2     2     1   0.7   0.2  0.4   0.3 
    3     3     1   0.6   0.3  0.04  0.5 
    

    【讨论】:

    • 后续问题:是否可以在 mutate 中使用“ex$”变量的名称?因此,例如,您可以使用“ex1”中的“1”作为“ex”的新值(如果它高于/等于“ran”并且低于“sum(ex2, ex3)”)。如果“ex2”位于“arrange(id, desc(value))”中的位置 1,则“2”作为“ex”的新值。或者另一个例子:使用最大/最小/中间“ex$”变量的名称作为“mutate(ex = ifelse(ran sum(value[2] , 值[3]), 5, ex))".
    • 请打开一个新问题,参考这个问题!
    【解决方案2】:

    我们可能会使用pmax

    library(dplyr)
    library(purrr)
    dat %>% 
       mutate(ex=  case_when(ran <=invoke(pmax, across(matches('^ex\\d+'))) ~ 5,
            TRUE ~ ex))
      id ex1  ex2  ex3 ex ran
    1  1 0.8 0.10 0.04  5 0.5
    2  2 0.2 0.40 0.30  1 0.7
    3  3 0.3 0.04 0.50  1 0.6
    

    【讨论】:

      【解决方案3】:
      exes <- t(apply(subset(dat, select = grep("^ex.+", names(dat))), 1, function(z) c(max(z), sum(z[-which.max(z)]))))
      exes
      #   [,1] [,2]
      # 1  0.8 0.14
      # 2  0.4 0.50
      # 3  0.5 0.34
      
      ifelse(dat$ran <= exes[,1] & dat$ran > exes[,2], 5, dat$ran)
      #   1   2   3 
      # 5.0 0.7 0.6 
      

      演练:

      • subset(dat, ...) 是一种从帧中动态提取列的方法,无论其类型如何(例如,data.frametbl_dfdata.table),并且没有将帧丢弃到列的风险(即,看到mtcars[,2] 不再是一个框架);还有其他方法可以做到这一点,一些在基础 R 中,一些在其他包中,如 dplyrdata.table

      • apply(dat, 1, ..)对各个列的行进行操作;因为当MARGIN=1(第二个参数)时,它会转置结果,所以我们需要将t(.)它恢复到正确的形状;

      • exes 现在是一个矩阵,其第一列包含ex# 变量的最大值,第二列包含非最大值ex# 变量的总和

      从这里开始,我认为exes 的使用是您正在寻找的“通用”解决方案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-27
        • 2019-05-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-08
        • 2016-03-10
        • 1970-01-01
        相关资源
        最近更新 更多