【问题标题】:Create a new variable from the minimum in R从 R 中的最小值创建一个新变量
【发布时间】:2016-05-13 09:43:49
【问题描述】:

数据包含四个字段:id, x1, x2, and x3

id <- c(1,2,3,4,5,6,7,8,9,10)
x1 <- c(2,4,5,3,6,4,3,6,7,7)
x2 <- c(0,1,2,6,7,6,0,8,2,2)
x3 <- c(5,3,4,5,8,3,4,2,5,6)

DF <- data.frame(id, x1,x2,x3)

在我问这个问题之前,让我创建一个新字段 (minX),它是 (x1,x2,x3) 的最小值

DF$minX <- pmin(DF$x1, DF$x2, DF$x3)

我需要新建一个字段y,定义如下

if min(x1,x2,x3) = x1, then y = "x1"
if min(x1,x2,x3) = x2, then y = "x2"
if min(x1,x2,x3) = x3, then y = "x3"

注意:我们假设没有关系。

【问题讨论】:

  • 对于类似问题,另请参阅?max.colnames(DF[-1])[max.col(-DF[-1], "first")]

标签: r


【解决方案1】:

作为一个简单的解决方案,这样做:

VARS <- colnames(DF)[-1]
y <- VARS[apply(DF[, -1], MARGIN = 1, FUN = which.min)]
DF$y <- y

函数which.min 返回最小值的索引。如果最小值不是唯一的,则返回第一个。既然你保证没有平局,这不是问题。

最后,你应该熟悉apply,对吧? MARGIN = 1 表示按行应用函数FUN,而MARGIN = 2 表示按列应用FUN。这是一个有用的功能,可以避免在处理矩阵时需要 for 循环。由于您的数据框只包含数字/整数值,它就像一个矩阵,因此我们可以使用apply

【讨论】:

  • 你需要去掉 ID 列
  • 为什么要创建所有这些中间变量而不仅仅是DF$y &lt;- colnames(DF)[-1][apply(DF[,-1], 1, which.min)]
  • @ProcrastinatusMaximus 需要 which.pmin 并且您的 data.table 解决方案建议在该包中提供。
【解决方案2】:

这是另一个使用 pminmax.col 的选项

library(data.table)
setDT(DF)[, c("minx", "y") := list(do.call(pmin, .SD), 
             names(.SD)[max.col(-1*.SD)]), .SDcols= x1:x3]
DF
#    id x1 x2 x3 minx  y
# 1:  1  2  0  5    0 x2
# 2:  2  4  1  3    1 x2
# 3:  3  5  2  4    2 x2
# 4:  4  3  6  5    3 x1
3 5:  5  6  7  8    6 x1
# 6:  6  4  6  3    3 x3
# 7:  7  3  0  4    0 x2
# 8:  8  6  8  2    2 x3
# 9:  9  7  2  5    2 x2
#10: 10  7  2  6    2 x2

【讨论】:

    【解决方案3】:

    data.table 解决方案:

    # create variables
    id <- c(1,2,3,4,5,6,7,8,9,10)
    x1 <- c(2,4,5,3,6,4,3,6,7,7)
    x2 <- c(0,1,2,6,7,6,0,8,2,2)
    x3 <- c(5,3,4,5,8,3,4,2,5,6)
    DF <- data.frame(id, x1,x2,x3)
    
    # load package and set data table, calculating min
    library(data.table)
    setDT(DF)[, minx := apply(.SD, 1, min), .SDcols=c("x1", "x2", "x3")]
    
    # Create variable with name of minimum
    DF[, y := apply(.SD, 1, function(x) names(x)[which.min(x)]), .SDcols = c("x1", "x2", "x3")]
    
    # call result
    DF
    ##     id x1 x2 x3 minx  y
     1:  1  2  0  5    0 x2
     2:  2  4  1  3    1 x2
     3:  3  5  2  4    2 x2
     4:  4  3  6  5    3 x1
     5:  5  6  7  8    6 x1
     6:  6  4  6  3    3 x3
     7:  7  3  0  4    0 x2
     8:  8  6  8  2    2 x3
     9:  9  7  2  5    2 x2
    10: 10  7  2  6    2 x2
    

    最后一步可以直接调用,不需要计算minx。 请注意data.table 在大型数据集中的速度特别快。

    ######## 编辑添加:DPLYR 方法#########

    为了完整起见,这将是一个dplyr 方法来产生相同的(最终)结果。这个解决方案归功于@eipi10 在我从这个问题(see here) 开始的问题中:

    DF %>% mutate(y = apply(.[,2:4], 1, function(x) names(x)[which.min(x)]))
    

    当应用于 1e6 行数据帧(在我的索尼笔记本电脑中大约 17 秒)时,此解决方案与原始答案中提供的 data.table 所用的时间大致相同。

    【讨论】:

    • apply 函数的替代方案:DF[, y := names(.SD)[which.min(.SD)], by = 1:nrow(DF), .SDcols = 2:4]
    猜你喜欢
    • 2017-04-05
    • 2019-05-13
    • 2019-10-06
    • 1970-01-01
    • 2020-04-12
    • 2019-09-11
    • 2011-01-04
    • 2018-10-15
    • 1970-01-01
    相关资源
    最近更新 更多