【问题标题】:R sapply/lapply with multiple ifelse statementsR sapply/lapply 与多个 ifelse 语句
【发布时间】:2017-07-07 20:55:22
【问题描述】:

我正在尝试使用 sapply 或 lapply 简化以下多个 ifelse 代码(仍然无法区分它们)。

我的目标是根据位置分配积分,如下所示。

df$Point <- ifelse(df$Placement_v2 <= 1, 10,
ifelse(df$Placement_v2 <= 10, 9, 
ifelse(df$Placement_v2 <= 25, 8,
ifelse(df$Placement_v2 <= 50, 7, 1) )))

此代码工作正常,但我想制作一个数据框,并使用 sapply 或 lapply(或任何其他函数)简单地制作我上面的代码。

我已经尝试过这段代码,但没有按预期工作。只有位置为 1 的行获得 10 分,其他行最终获得 1。

df$Point <- sapply(df2$Placement, function(x) ifelse(df$Placement_v2 <= x, df2$Point[df2$Placement == x], 1 ) )

我该如何解决这个问题?

【问题讨论】:

    标签: r if-statement lapply sapply


    【解决方案1】:

    解决此问题的几种方法。我将使用data.table

    library(data.table)
    
    set.seed(123)
    df <- data.table(Placement_v2 = runif(200, -10, 100))
    

    第一个选项,将评估移至函数,然后将 lapply 函数移至您的 Placement_v2 列。这样做的好处是比嵌套的 ifelse 语句更简洁。

    funky <- function(x) {
    
      if (x <= 1) {
        val <- 10
      } else if (x <= 10){
        val <- 9
      } else if (x <= 25){
        val <- 8
      } else if (x <= 50){
        val <- 7
      } else {
        val <- 1
      }
    
      return(val)
    
    }
    
    df[, Point := unlist(lapply(Placement_v2, funky))]
    

    结果:

         Placement_v2 Point
      1:    21.633527     8
      2:    76.713565     1
      3:    34.987461     7
      4:    87.131914     1
      5:    93.451401     1
     ---                   
    196:    41.318597     7
    197:    34.751585     7
    198:    62.515336     1
    199:     6.758128     9
    200:    53.015376     1
    

    我会改为通过对数据进行子集化并按每个子集分配来解决此问题。您可以通过指定每个子集 df[Placement_v2 &lt;= 1]df[Placement_v2 &gt;= 1 &amp; Placement_v2 &lt;= 10] 等来做到这一点。但是,如果您按照正确的顺序执行此操作,则可以避免双重相等评估。

    df[, Point := 1]
    df[Placement_v2 <= 50, Point := 7]
    df[Placement_v2 <= 25, Point := 8]
    df[Placement_v2 <= 10, Point := 9]
    df[Placement_v2 <=  1, Point := 10]
    

    结果相同:

         Placement_v2 Point
      1:    21.633527     8
      2:    76.713565     1
      3:    34.987461     7
      4:    87.131914     1
      5:    93.451401     1
     ---                   
    196:    41.318597     7
    197:    34.751585     7
    198:    62.515336     1
    199:     6.758128     9
    200:    53.015376     1
    

    【讨论】:

      【解决方案2】:

      您可以创建一个包含值和替换的数据框。然后你可以使用cut 来查找合适的值

      dict = data.frame(replacement = c(10, 9, 8, 7, 1, 1),
          values = c(0, 1, 10, 25, 50, 1e5))
      
      #DATA
      set.seed(42)
      placement = sample(1:100, 15)
      
      cbind(placement,
          new_placement = dict$replacement[as.integer(cut(placement, breaks = dict$values))])
      #     placement new_placement
      # [1,]        92             1
      # [2,]        93             1
      # [3,]        29             7
      # [4,]        81             1
      # [5,]        62             1
      # [6,]        50             7
      # [7,]        70             1
      # [8,]        13             8
      # [9,]        61             1
      #[10,]        65             1
      #[11,]        42             7
      #[12,]        91             1
      #[13,]        83             1
      #[14,]        23             8
      #[15,]        40             7
      

      【讨论】:

      • 感谢您的回复。您的代码运行良好。我只是想了解有关 cut 功能的更多信息。我的水平显示为 (1,10] (10,25] (25,50] (50,100] (100,200] (200,1e+07])。有没有办法让它像 1] (1,10] ( 10,25] (25,50] (50, 100] (100, 200] (200 ?我试图不在我的数据框中使用 0 或 1e5。
      猜你喜欢
      • 2022-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多