按行计算最大值

10

我想创建一个新的列,该列等于该行所有列的最大值。

以下是一个示例:

library(data.table)
data <- data.table(head(iris))
data[ , Species := NULL]
data

   Sepal.Length Sepal.Width Petal.Length Petal.Width
1:          5.1         3.5          1.4         0.2
2:          4.9         3.0          1.4         0.2
3:          4.7         3.2          1.3         0.2
4:          4.6         3.1          1.5         0.2
5:          5.0         3.6          1.4         0.2
6:          5.4         3.9          1.7         0.4

我不能在这里真正使用max函数,因为它将找到所有列的最大值,例如data[, max_value := max(Sepal.Length, Sepal.Width, Petal.Length, Petal.Width)]。我想要的是像这样的东西:

   Sepal.Length Sepal.Width Petal.Length Petal.Width max_value
1:          5.1         3.5          1.4         0.2       5.1
2:          4.9         3.0          1.4         0.2       4.9
3:          4.7         3.2          1.3         0.2       4.7
4:          4.6         3.1          1.5         0.2       4.6
5:          5.0         3.6          1.4         0.2       5.0
6:          5.4         3.9          1.7         0.4       5.4

1
我觉得在这里使用矩阵作为更好的存储方式,但是有一个data[,mymax:=apply(.SD,1,max)]的操作会将其转换为一个中间步骤的矩阵。 - Frank
3个回答

11

我不保证它的速度,但这至少避免了强制转换为矩阵:

data[,mymax:=do.call(pmax,.SD)]

如何从您的答案中获取第二大、第三大或第n大的值。 - Deepesh
@Deepesh,我认为这需要不同的方法。也许你需要更多的搜索或发布一个新问题。 - Frank

8

使用 dplyr 可以这样做:

library(dplyr)
setDF(data) %>% 
  rowwise() %>% 
  mutate(max = max(Sepal.Length, Sepal.Width, Petal.Length, Petal.Width))

#Source: local data frame [10 x 5]
#Groups: <by row>
#
#   Sepal.Length Sepal.Width Petal.Length Petal.Width max
#1           5.1         3.5          1.4         0.2 5.1
#2           4.9         3.0          1.4         0.2 4.9
#3           4.7         3.2          1.3         0.2 4.7
#4           4.6         3.1          1.5         0.2 4.6
#5           5.0         3.6          1.4         0.2 5.0
#6           5.4         3.9          1.7         0.4 5.4

或者如@akrun所建议的:

setDF(data) %>% mutate(max=pmax(Sepal.Length, Sepal.Width, Petal.Length, Petal.Width))

这比使用rowwise()方法要快得多:

n <- 10e6; nc <- 4; DT <- data.table(replicate(nc,rnorm(n))) 

mbm <- microbenchmark(
  steven = DT %>% rowwise() %>% mutate(V5 = max(V1, V2, V3, V4)),
  frank = DT[,c(.SD,list(do.call(pmax,.SD)))], 
  akrun = DT %>% mutate(V5 = pmax(V1, V2, V3, V4)), times = 25, unit = "relative")

enter image description here

#Unit: relative
#   expr      min        lq      mean   median        uq       max neval cld
# steven 17.93647 18.024734 17.535764 17.42948 17.484920 16.446384    25   b
#  frank  1.00000  1.000000  1.000000  1.00000  1.000000  1.000000    25  a 
#  akrun  1.00220  1.002281  1.013604  1.00240  1.003089  1.001262    25  a 

4
您还可以使用 pmax 函数,例如 setDF(data) %>% mutate(max=pmax(Sepal.Length, Sepal.Width, Petal.Length, Petal.Width)) 。该函数的作用是返回每一行中指定变量的最大值。 - akrun
那个图看起来很不错,你能包含用于制作它的命令吗?当我删除 setDT/setDF(我不理解为什么要包含它们)和 :=(使其与不修改 DT 的 dplyr 行相似)时,性能相似。n <- 10e6; nc <- 4; DT <- data.table(replicate(nc,rnorm(n))); microbenchmark(frank = DT[,c(.SD,list(do.call(pmax,.SD)))], akrun = DT %>% mutate(V5=pmax(V1, V2, V3, V4)), times = 10);identical(frank,akrun) 不知道为什么结果不同。 - Frank
1
@Frank ggplot对于microbenchmark对象有一个autoplot方法:autoplot(mbm) - Steven Beaupré
1
也许添加已接受答案的性能,因为在我看来它显然非常低效。 - David Arenburg
我认为应该删除rowwise的答案。 - Hugh
显示剩余2条评论

6
使用by=1:nrow(data)按行"分组"(这使每行成为自己的一组):
data[, max_value:=max(Sepal.Length, Sepal.Width, Petal.Length, Petal.Width), by=1:nrow(data)]

data
   Sepal.Length Sepal.Width Petal.Length Petal.Width max_value
1:          5.1         3.5          1.4         0.2       5.1
2:          4.9         3.0          1.4         0.2       4.9
3:          4.7         3.2          1.3         0.2       4.7
4:          4.6         3.1          1.5         0.2       4.6
5:          5.0         3.6          1.4         0.2       5.0
6:          5.4         3.9          1.7         0.4       5.4

这是使用 by 的聪明方法。谢谢! - Boxuan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接