2012-12-07 117 views
7

我需要抓取構成對稱矩陣的較低三角形的所有三個元素三角形。我想不出如何按照最左邊的列向下,然後是右邊的下一列的順序抓住所有這些部分,等等。我知道numbe ROF下三角內小三角形是:在較低的三角形內抓取三角形

n = x(x - 1)/2 
where: x = nrow(mats[[i]]) 

在這裏,我創建了三個矩陣,用字母(這是我更容易概念化這種方式)和元素,我的順序尋找:

FUN <- function(n) { 
    matrix(LETTERS[1:(n*n)], n) 
} 

mats <- lapply(3:5, FUN) 

所以這是我想獲得(我把它放在代碼,而不是輸出格式)上面創建的每個矩陣的輸出:

list(c("B", "C", "F")) 

list(c("B", "C", "G"), c("C", "D", "H"), c("G", "H", "L")) 

list(c("B", "C", "H"), c("C", "D", "I"), c("D", "E", "J"), 
    c("H", "I", "N"), c("I", "J", "O"), c("N", "O", "T")) 

我怎樣才能不要他的任務可能以最快的方式停留在R基地?

不知道這視覺的,我以後有什麼是有用的,但它可能是:

enter image description here

+0

是5x5矩陣,你會期望最大的有測試? –

+0

不,它可能會更大(儘管我非常懷疑它會更大)。 –

+0

@TylerRinker - 我不得不強制關閉我的R會話,同時嘗試在10K * 10K矩陣上進行一些基準測試。 1K * 1K是幾秒鐘的問題。我想知道那裏的人可能會有更有效的實施。 – thelatemail

回答

5

尼斯的問題!下面是如何使用一點遞歸的(後面跟一個更簡單的版本)

triangle <- function(base.idx, mat) { 
    upper.idx <- base.idx - 1L 
    right.idx <- base.idx + nrow(mat) 
    paste(mat[c(upper.idx, base.idx, right.idx)], collapse = " ") 
} 

get.triangles <- function(mat) { 
    N <- nrow(mat) 
    if (N == 3L) { 
     return(triangle(3L, mat)) 
    } else { 
     left.idx <- 3:N 
     right.mat <- mat[2:N, 2:N] 
     left.triangles <- sapply(left.idx, triangle, mat) 
     right.triangles <- Recall(right.mat) 
     return(c(left.triangles, right.triangles)) 
    } 
} 

x <- lapply(mats, get.triangles) 

# [[1]] 
# [1] "B C F" 
# 
# [[2]] 
# [1] "B C G" "C D H" "G H L" 
# 
# [[3]] 
# [1] "B C H" "C D I" "D E J" "H I N" "I J O" "N O T" 

我將不被輸出完全按照自己的要求只是發表意見解決這個問題。這是因爲創建返回一個平坦的列表總是難以處理遞歸函數:不知爲何,你總是與嵌套列表結束了......

所以最後一步應該是:

lapply(x, strsplit, split = " ") 

,它會與您要求的格式相同。


這裏是一個更簡單的版本(忘了遞歸!)

get.triangles <- function(mat) { 
    base.idx <- seq_along(mat)[row(mat) > col(mat) + 1] 
    upper.idx <- base.idx - 1L 
    right.idx <- base.idx + nrow(mat) 

    lapply(mapply(c, upper.idx, base.idx, right.idx, SIMPLIFY = FALSE), 
      function(i)mat[i]) 
} 
+0

非常感謝你的作品。我將利用這個方法而不用遞歸,因爲不需要使用'strsplit'(如果它是一個數字矩陣,不需要使用'as.numeric')。 +1 –

3

編輯添加SIMPLIFY=FALSE現在給你想要什麼:

基本上,這種方法得到的您想要的三角形的所有左上角的索引,然後抓取[單元格] + [單元格在右下方]。快感。此方法的另一個好處是它適用於matrixdata.frame對象。

bot.tris <- function(data) { 
    idx1 <- unlist(sapply((nrow(data)-2):1,function(x) tail(2:(nrow(data)-1),x))) 
    idx2 <- rep(1:(nrow(data)-2),(nrow(data)-2):1) 
    mapply(function(x,y) {c(data[x,y],data[x+1,y],data[x+1,y+1])},idx1,idx2,SIMPLIFY=FALSE) 
} 

而結果:

> result <- lapply(mats,bot.tris) 
> str(result) 
List of 3 
$ :List of 1 
    ..$ : chr [1:3] "B" "C" "F" 
$ :List of 3 
    ..$ : chr [1:3] "B" "C" "G" 
    ..$ : chr [1:3] "C" "D" "H" 
    ..$ : chr [1:3] "G" "H" "L" 
$ :List of 6 
    ..$ : chr [1:3] "B" "C" "H" 
    ..$ : chr [1:3] "C" "D" "I" 
    ..$ : chr [1:3] "D" "E" "J" 
    ..$ : chr [1:3] "H" "I" "N" 
    ..$ : chr [1:3] "I" "J" "O" 
    ..$ : chr [1:3] "N" "O" "T" 
+1

這種方法肯定是少編碼,很容易理解。我對這兩種反應進行了基準測試,flodel的反應速度更快。這裏的兩個函數比我所有的都快(沒有)。非常感謝你解決這個問題。 +1 –

+0

*「這裏的兩個函數比我所有的都快(沒有)」* - 我喜歡那個:-) – thelatemail