【问题标题】:do.call and order to sort each row to descending order of a matrix?do.call 和 order 将每一行排序为矩阵的降序?
【发布时间】:2017-01-11 15:01:13
【问题描述】:

我想按行按降序对这个矩阵进行排序

 > set.seed(123); a <- matrix(rbinom(100,10,0.3),ncol=10)

      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
 [1,]    2    6    5    6    1    1    4    4    2     1
 [2,]    4    3    4    5    3    3    1    3    4     4
 [3,]    3    4    3    4    3    4    3    4    3     2
 [4,]    5    3    7    4    2    1    2    0    4     4
 [5,]    5    1    4    0    2    3    4    3    1     2
 [6,]    1    5    4    3    1    2    3    2    3     2
 [7,]    3    2    3    4    2    1    4    2    6     4
 [8,]    5    1    3    2    3    4    4    3    5     1
 [9,]    3    2    2    2    2    5    4    2    5     3
[10,]    3    6    1    2    5    2    3    1    2     3

但是

> do.call(order,as.list(a[1,],a[2,]))
[1] 1

如何使用 do.call 和 order 对矩阵进行排序?

编辑。修正了上面的矩阵以符合上面的代码。

【问题讨论】:

  • 您是在保留矩阵结构的同时尝试对每一行进行独立排序还是按多行排序??
  • 也许this helps
  • @JosephWood 对每一行进行独立排序。我目前使用apply(1,function(x) order(x,decreasing=T)) 进行操作,但速度太慢了。
  • @Sotos 我读到了,但排序的顺序很奇怪。
  • 一个简单的for 循环在这里可能会做得很好。类似for(x in seq_len(nrow(a))) a[x,] &lt;- order(a[x,],decreasing=T)

标签: r sorting matrix do.call


【解决方案1】:

两种选择:

# Jaap
do.call(rbind, lapply(split(a, row(a)), sort, decreasing = TRUE))

# adaption of lmo's solution in the comments
for(i in 1:nrow(a)) a[i,] <- a[i,][order(a[i,], decreasing = TRUE)]

给予:

   [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
1     6    6    5    4    4    2    2    1    1     1
2     5    4    4    4    4    3    3    3    3     1
3     4    4    4    4    3    3    3    3    3     2
4     7    5    4    4    4    3    2    2    1     0
5     5    4    4    3    3    2    2    1    1     0
6     5    4    3    3    3    2    2    2    1     1
7     6    4    4    4    3    3    2    2    2     1
8     5    5    4    4    3    3    3    2    1     1
9     5    5    4    3    3    2    2    2    2     2
10    6    5    3    3    3    2    2    2    1     1

基准测试:

library(microbenchmark)
microbenchmark(dc.lapply.sort = do.call(rbind, lapply(split(a, row(a)), sort, decreasing = TRUE)),
               t.apply.sort = t(apply(a, 1, sort, decreasing = TRUE)),
               for.order = for(i in 1:nrow(a)) a[i,] <- a[i,][order(a[i,], decreasing = TRUE)],
               for.sort = for(i in 1:nrow(a)) a[i,] <- sort(a[i,], decreasing = TRUE),
               for.sort.list = for(x in seq_len(nrow(a))) a[x,] <- a[x,][sort.list(a[x,], decreasing = TRUE, method="radix")])

给予:

Unit: microseconds
           expr     min       lq      mean   median       uq      max neval cld
 dc.lapply.sort 189.811 206.5890 222.52223 217.8070 228.0905  332.034   100   c
   t.apply.sort 185.474 200.4515 212.59608 210.4930 220.0025  286.288   100  bc
      for.order  82.631  91.1860  98.66552  97.8475 102.9680  176.666   100 a  
       for.sort 167.939 187.5025 192.90728 192.1195 198.8690  256.494   100  b 
  for.sort.list 187.617 206.4475 230.82960 215.7060 221.6115 1541.343   100   c

但应注意,基准测试仅对较大的数据集有意义,因此:

set.seed(123)
a <- matrix(rbinom(10e5, 10, 0.3), ncol = 10)

microbenchmark(dc.lapply.sort = do.call(rbind, lapply(split(a, row(a)), sort, decreasing = TRUE)),
               t.apply.sort = t(apply(a, 1, sort, decreasing = TRUE)),
               for.order = for(i in 1:nrow(a)) a[i,] <- a[i,][order(a[i,], decreasing = TRUE)],
               for.sort = for(i in 1:nrow(a)) a[i,] <- sort(a[i,], decreasing = TRUE),
               for.sort.list = for(x in seq_len(nrow(a))) a[x,] <- a[x,][sort.list(a[x,], decreasing = TRUE, method="radix")],
               times = 10)

给予:

Unit: seconds
           expr      min       lq     mean   median       uq      max neval  cld
 dc.lapply.sort 6.790179 6.924036 7.036330 7.013996 7.121343 7.351729    10    d
   t.apply.sort 5.032052 5.057022 5.151560 5.081459 5.177159 5.538416    10   c 
      for.order 1.368351 1.463285 1.514652 1.471467 1.583873 1.736544    10 a   
       for.sort 5.028314 5.102993 5.317597 5.154104 5.348614 6.123278    10   c 
  for.sort.list 2.417857 2.464817 2.573294 2.519408 2.726118 2.815964    10  b  

结论:for-loop 结合order 仍然是最快的解决方案。


使用grr-package 的order2sort2 函数可以进一步提高速度。将它们与上面最快的解决方案进行比较:

set.seed(123)
a <- matrix(rbinom(10e5, 10, 0.3), ncol = 10)

microbenchmark(for.order = for(i in 1:nrow(a)) a[i,] <- a[i,][order(a[i,], decreasing = TRUE)],
               for.order2 = for(i in 1:nrow(a)) a[i,] <- a[i,][rev(grr::order2(a[i,]))],
               for.sort2 = for(i in 1:nrow(a)) a[i,] <- rev(grr::sort2(a[i,])),
               times = 10)

给予:

Unit: milliseconds
       expr       min        lq      mean    median        uq      max neval cld
  for.order 1243.8140 1263.4423 1316.4662 1305.1823 1378.5836 1404.251    10   c
 for.order2  956.1536  962.8226 1110.1778 1090.9984 1233.4241 1368.416    10  b 
  for.sort2  830.1887  843.6765  920.5668  847.1601  972.8703 1144.135    10 a  

【讨论】:

  • t(apply(a, 1, sort, decreasing = TRUE))
  • 我无法理解排序。 a 的第一行按sort(c(3, 5, 3, 3, 2, 4, 3, 3, 4, 2)) 递减的顺序是2 2 3 3 3 3 3 4 4 5——这和1 1 1 2 2 4 4 5 6 6 完全不同,这是在做什么?
  • 你如何把它变成降序? do.call(rbind, lapply(split(a, row(a)), sort(decreasing=TRUE))) 会触发一个 x 缺失的错误,这按升序而不是降序工作。
  • @ReganAlpha 已更新;另请注意,您提供的用于生成矩阵的代码并未提供您包含在问题中的矩阵
  • @hhh 我不确定。也许grr-package 中的order2sort2 函数可以提供帮助。请参阅答案末尾的更新。
【解决方案2】:

t(apply(a, 1, sort, decreasing = TRUE)) 给出:

#       [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
#  [1,]    6    6    5    4    4    2    2    1    1     1
#  [2,]    5    4    4    4    4    3    3    3    3     1
#  [3,]    4    4    4    4    3    3    3    3    3     2
#  [4,]    7    5    4    4    4    3    2    2    1     0
#  [5,]    5    4    4    3    3    2    2    1    1     0
#  [6,]    5    4    3    3    3    2    2    2    1     1
#  [7,]    6    4    4    4    3    3    2    2    2     1
#  [8,]    5    5    4    4    3    3    3    2    1     1
#  [9,]    5    5    4    3    3    2    2    2    2     2
# [10,]    6    5    3    3    3    2    2    2    1     1

【讨论】:

  • 你觉得哪个更快?我尝试了这个小例子&gt; system.time(t(apply(a, 1, sort, decreasing = TRUE))) user system elapsed 0 0 0 &gt; system.time(t(apply(a, 1, function(x) order(x,decreasing=T)))) user system elapsed 0 0 0 ,但还没有答案。 Jaap 的解决方案更快吗? ://
  • 你可以microbenchmark他们,他们是一样的:microbenchmark::microbenchmark( t(apply(a, 1, sort, decreasing = TRUE)), do.call(rbind, lapply(split(a, row(a)), sort, decreasing = TRUE)), times = 1000L )。在我的机器上,平均时间:330 微秒,中位数时间:两者均为 300 微秒
【解决方案3】:

我也做了微基准测试,似乎订单解决方案获胜:)

>     microbenchmark(jaap1 = do.call(rbind, lapply(split(a, row(a)), sort, decreasing = TRUE)),
+                    apom = t(apply(a, 1, sort, decreasing = TRUE)),
+                    jaap2 = for(i in 1:nrow(a)) a[i,] <- a[i,][order(a[i,], decreasing = TRUE)],
+                    jaap3 = for(i in 1:nrow(a)) a[i,] <- sort(a[i,], decreasing = TRUE), 
+                    alpha = t(apply(a, 1, function(x) order(x, decreasing = T))),
+                    times = 1000L)
Unit: microseconds
  expr     min       lq     mean   median       uq      max neval
 jaap1 318.193 364.6125 404.3224 389.5845 417.6405 1422.087  1000
  apom 276.764 340.2740 389.1302 364.9650 398.3680 2854.710  1000
 jaap2 121.332 158.4845 189.5616 182.2070 202.2390 1170.602  1000
 jaap3 247.387 309.2445 351.6959 332.2710 365.3640 1361.720  1000
 alpha 139.244 178.7460 209.6122 202.8580 226.7585 1092.301  1000

【讨论】:

  • 强调:不仅仅是order 解决方案,而是for 循环。
  • @Imo:我无法理解如何将 for 循环与 here 等未定义变量一起使用,我使用虚拟变量来存储中间结果,但我不能像 mmm[1,] 那样引用它们它们尚未启动,因此使用 for-loop 我需要先以某种方式启动变量?
  • 我不太明白你的问题。您确实需要在引用它们之前启动变量。如果您事先知道对象的大小和形状,则应该创建它。例如,要初始化上述内容,您可以在运行循环之前使用a &lt;- matrix(0, 10, 10),然后将其填写。如果您提出不同的问题并且在对 SO 进行一些搜索后没有找到解决方案,则可能值得发布为一个新问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-24
  • 1970-01-01
  • 2014-06-02
  • 2016-05-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多