簡體   English   中英

測試矩陣或數據幀的行是否按R排序

[英]Testing if rows of a matrix or data frame are sorted in R

什么是測試矩陣中的行是否排序的有效方法? [更新:請參閱Aaron的Rcpp答案 - 直截了當且非常快。]

我正在移植一些使用issorted(,'rows')代碼。 因為看起來is.unsorted並沒有超出向量,我正在寫或尋找其他東西。 天真的方法是檢查矩陣(或數據框)的排序版本是否與原始版本相同,但這顯然效率低下。

注意:為了排序, 在Matlab中進行排序sortrows() ,我的代碼基本上使用SortedDF <- DF[do.call(order, DF),] (它包含在一個更大的函數中,它將矩陣轉換為數據幀,將參數傳遞給order等)。 如果有更快的實現(數據表浮現在腦海中),我不會感到驚訝。


更新1:澄清:我沒有測試排列行內或列內。 (這種排序通常會產生代數不同的矩陣。)

作為創建未排序矩陣的示例:

set.seed(0)
x <- as.data.frame(matrix(sample(3, 60, replace = TRUE), ncol = 6, byrow = TRUE))

它的排序版本是:

y <- x[do.call(order, x),]

一個正確的測試,比如testSorted ,對於testSorted(x)將返回FALSE ,對於testSorted(y)將返回TRUE

更新2:以下答案都很好 - 它們很簡潔並且可以進行測試。 關於效率,看起來這些都是對數據進行排序。

我已經嘗試使用相當大的矩陣,例如1M x 10,(只是更改上面的x的創建),並且所有矩陣都具有相同的時間和內存成本。 特別之處在於它們對未分類對象(1Mx10大約5.5秒)消耗的時間比分類對象( y大約0.5秒)消耗的時間更長。 這表明他們在測試前進行了分類。

我通過創建一個z矩陣進行測試:

z <- y
z[,2] <- y[,1]
z[,1] <- y[,2]

在這種情況下,所有方法都需要大約0.85秒才能完成。 無論如何,在5.5秒內完成並不可怕(事實上,對於對象排序所需的時間似乎是正確的),但是知道排序矩陣快11倍表明沒有排序的測試可能是均勻的快點。 在1M行矩陣的情況下, x前三行是:

  V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1  3  1  2  2  3  1  3  3  2   2
2  1  1  1  3  2  3  2  3  3   2
3  3  3  1  2  1  1  2  1  2   3

沒有必要超越第2行,盡管矢量化並不是一個壞主意。

(我還為x的創建添加了byrow參數,因此行值不依賴於x的大小。)

更新3:可以使用Linux中的sort -c命令找到此測試的另一個比較。 如果文件已經寫入(使用write.table() ),包含1M行,那么time sort -c myfile.txt對於未排序數據需要0.003秒,對於排序數據需要0.101秒。 我不打算寫出文件,但這是一個有用的比較。

更新4: Aaron的Rcpp方法擊敗了這里提供的所有其他方法,並且我已經嘗試過(包括上面的sort -c比較:內存中預計將擊敗磁盤)。 至於相對於其他方法的比例,很難說:分母太小而無法給出准確的測量結果,而且我沒有廣泛探索微microbenchmark 對於某些矩陣(例如用rnorm制作的矩陣),加速可能非常大(4-5個數量級),但這是誤導性的 - 檢查可以在僅幾行之后終止。 我已經加速了大約25-60的示例矩陣和未分類的大約1.1X,因為如果數據被排序,競爭方法已經非常快。

由於這是正確的事情(即沒有排序,只是測試),並且非常快,它是公認的答案。

如果y被排序,則do.call(order,y)返回1:nrow(y)。

 testSorted = function(y){all(do.call(order,y)==1:nrow(y))}

請注意,這不會比較矩陣,但一旦發現不匹配就不會消失。

好吧,你為什么不用:

all(do.call(order, y)==seq(nrow(y)))

這避免了創建有序矩陣,並確保它檢查您的訂購風格。

好吧,蠻力方法是循環和比較,一旦發現違規就中止。

這種方法可以在R中輕松實現和測試,然后轉移到一個簡單的C ++函數,我們可以通過內聯Rcpp連接到R(如果必須的話,還可以連接到普通的C),因為循環是真正受益於實現的一個實現。編譯語言。

否則,您是否可以使用diff()類的東西並檢查所有增量是否為非負值?

更新 :我決定使用Rcpp練習......

library(Rcpp)
library(inline)
isRowSorted <- cxxfunction(signature(A="numeric"), body='
  Rcpp::NumericMatrix Am(A);
  for(int i = 1; i < Am.nrow(); i++) {
    for(int j = 0; j < Am.ncol(); j++) {
      if( Am(i-1,j) < Am(i,j) ) { break; }
      if( Am(i-1,j) > Am(i,j) ) { return(wrap(false)); }
    }
  }
  return(wrap(true));
', plugin="Rcpp")

rownames(y) <- NULL # because as.matrix is faster without rownames
isRowSorted(as.matrix(y))

新:這個只有R的黑客對所有矩陣的速度都是一樣的; 它對於排序矩陣來說肯定更快; 對於未分類的,它取決於未分類的性質。

iss3 <- function(x) {
  x2 <- sign(do.call(cbind, lapply(x, diff)))
  x3 <- t(x2)*(2^((ncol(x)-1):0))
  all(colSums(x3)>=0)
}

原文:對於一些未分類的矩陣,這個更快。 多快將取決於未分類元素的位置; 這會逐列地查看矩陣,因此左側的未排序將比右側的未排序快得多,而頂部/底部幾乎無關緊要。

iss2 <- function(y) {
  b <- c(0,nrow(y))
  for(i in 1:ncol(y)) {
    z <- rle(y[,i])
    b2 <- cumsum(z$lengths)
    sp <- split(z$values, cut(b2, breaks=b))
    for(spi in sp) {
      if(is.unsorted(spi)) return(FALSE)
    }
    b <- c(0, b2)
  }
  return(TRUE)
}

您可以將do.call語句與is.unsorted一起is.unsorted

issorted.matrix <- function(A) {!is.unsorted(do.call("order",data.frame(A)))}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM