[英]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)))
這避免了創建有序矩陣,並確保它檢查您的訂購風格。
更新 :我決定使用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.