R 确定三个值中最大值的最快/最简单算法/函数

R 确定三个值中最大值的最快/最简单算法/函数,r,algorithm,conditional,dplyr,R,Algorithm,Conditional,Dplyr,这是一个非常基本的编程问题,但为了将来,我只想知道哪种方法是处理这种常见情况的最佳方法 我有三列,级别在0和10之间,我希望确定其中哪一列的值最高,并在变异列或以其他方式创建的“最大”列中显示列的名称。在任何情况下,我更喜欢c而不是b而不是a列,因为此开关将用于从其他列中提取值,这些列可能与这些列不同 下面的代码可以做到这一点,但是有没有一种更简短的方法呢 set.seed(7) mat <- matrix(as.integer(runif(15, 0, 10)), nrow = 5, n

这是一个非常基本的编程问题,但为了将来,我只想知道哪种方法是处理这种常见情况的最佳方法

我有三列,级别在0和10之间,我希望确定其中哪一列的值最高,并在变异列或以其他方式创建的“最大”列中显示列的名称。在任何情况下,我更喜欢c而不是b而不是a列,因为此开关将用于从其他列中提取值,这些列可能与这些列不同

下面的代码可以做到这一点,但是有没有一种更简短的方法呢

set.seed(7)
mat <- matrix(as.integer(runif(15, 0, 10)), nrow = 5, ncol = 3)
colnames(mat) <- letters[1:3]
(mat)

matBestOf <- 
    data.frame(mat) %>% 
    mutate(Largest = ifelse(c >= b & c >= a, "c",
                     ifelse(b >= c & b >= a, "b",
                     "a"))
           )
matBestOf
#   a b c Largest
# 1 9 7 1       a
# 2 3 3 2       b
# 3 1 9 7       b
# 4 0 1 0       b
# 5 2 4 4       c
这里有一个max.col选项:

我使用select将列按您指定的顺序排列,这样我们就可以简单地使用ties.method=first。everything可确保其他列(如果存在)也会被选中,但会出现在前三列之后。

使用apply和rev将c优先于b,而不是a:

cbind.data.frame(mat,
      Largest = apply(mat, 1,
                      function(i)rev(colnames(mat))[rev(i) == max(i)][1]))
#   a b c Largest
# 1 9 7 1       a
# 2 3 3 2       b
# 3 1 9 7       b
# 4 0 1 0       b
# 5 2 4 4       c
编辑:基准测试

将rev置于apply之外会使代码在更大数据上的速度提高3-4倍,但仍然不如dplyr解决方案快

library(dplyr)

# bigger dummy data
bigmat <- matrix(rep(mat, 10000), ncol = 20)
colnames(bigmat) <- letters[1:ncol(bigmat)]


microbenchmark::microbenchmark(
  dplyr = {bigmat %>% 
      data.frame() %>% 
      select(c,b,a, everything()) %>%
      mutate(Largest = names(.)[max.col(., ties.method = "first")])},
  base_apply_v1 = {
    cbind.data.frame(bigmat,
                     Largest = apply(bigmat, 1,
                                     function(i)rev(colnames(bigmat))[rev(i) == max(i)][1]))
  },
  base_apply_v2 = {
    myFlip <- bigmat[nrow(bigmat):1, ncol(bigmat):1]
    myNames <- colnames(myFlip)
    cbind.data.frame(bigmat,
                     Largest = apply(myFlip, 1,
                                     function(i)myNames[i == max(i)][1]))
  }
  )

# Unit: milliseconds
#           expr       min       lq      mean    median        uq        max neval cld
#          dplyr  3.271673  3.52583  4.665696  3.730951  5.915583   8.405259   100 a  
#  base_apply_v1 86.191320 91.94412 99.370839 93.709812 96.214598 196.007909   100   c
#  base_apply_v2 23.121803 26.70536 30.906054 28.042854 29.065466 134.257780   100  b 
下面是一个使用data.table的选项


也许这对你有帮助。如果您在解决方案中进行了一些不必要的测试,那么代码中只需要进行3次比较,并且只需要执行3次比较中的2次。请参见示例2:非常好!谢谢你的反馈和有用的链接:我到处都找过这样的东西。[以上代码已更新。]@leerssej mat需要转换为data.frame,请参见编辑。2新函数:everything和max.col,并重新学习如何将索引转换为其相关值。谢谢大家!@里尔塞吉,欢迎你!顺便说一句,在c对b对a的情况下,您也可以省略select语句并更改ties.method=last。@Docendiscimus用last更新了您的帖子,希望您不介意,它提供了0.3分钟更好的性能:在bigmat数据上。@zx8754,没问题,谢谢您的更新和基准测试
cbind.data.frame(mat,
      Largest = apply(mat, 1,
                      function(i)rev(colnames(mat))[rev(i) == max(i)][1]))
#   a b c Largest
# 1 9 7 1       a
# 2 3 3 2       b
# 3 1 9 7       b
# 4 0 1 0       b
# 5 2 4 4       c
library(dplyr)

# bigger dummy data
bigmat <- matrix(rep(mat, 10000), ncol = 20)
colnames(bigmat) <- letters[1:ncol(bigmat)]


microbenchmark::microbenchmark(
  dplyr = {bigmat %>% 
      data.frame() %>% 
      select(c,b,a, everything()) %>%
      mutate(Largest = names(.)[max.col(., ties.method = "first")])},
  base_apply_v1 = {
    cbind.data.frame(bigmat,
                     Largest = apply(bigmat, 1,
                                     function(i)rev(colnames(bigmat))[rev(i) == max(i)][1]))
  },
  base_apply_v2 = {
    myFlip <- bigmat[nrow(bigmat):1, ncol(bigmat):1]
    myNames <- colnames(myFlip)
    cbind.data.frame(bigmat,
                     Largest = apply(myFlip, 1,
                                     function(i)myNames[i == max(i)][1]))
  }
  )

# Unit: milliseconds
#           expr       min       lq      mean    median        uq        max neval cld
#          dplyr  3.271673  3.52583  4.665696  3.730951  5.915583   8.405259   100 a  
#  base_apply_v1 86.191320 91.94412 99.370839 93.709812 96.214598 196.007909   100   c
#  base_apply_v2 23.121803 26.70536 30.906054 28.042854 29.065466 134.257780   100  b 
library(data.table)
as.data.table(mat)[, Largest := rev(colnames(mat))[which.max(rev(unlist(.SD)))] , 1:nrow(mat)][]
#    a b c Largest
#1: 9 7 1       a
#2: 3 3 2       b
#3: 1 9 7       b
#4: 0 1 0       b
#5: 2 4 4       c