2012-12-07 18 views
7

Ich habe die Notwendigkeit, alle drei Elemente Dreiecke zu greifen, die das untere Dreieck einer symmetrischen Matrix bilden. Ich kann mir nicht vorstellen, wie ich all diese Teile in der Reihenfolge der weit links stehenden Spalte und dann der nächsten Spalte nach rechts und so weiter ergreife. Ich weiß, dass die numbe rof Minidreiecke innerhalb des unteren Dreiecks ist:Grab Dreiecke innerhalb eines unteren Dreiecks

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

Hier habe ich drei Matrizen mit Buchstaben erstellt (es ist einfacher für mich, auf diese Weise zu konzipieren) und die Elemente in der Reihenfolge, ich bin das ist also der Ausgang ich mag würde zu bekommen (ich habe es in Code statt Ausgabeformat) für jede der Matrizen oben erstellt

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

mats <- lapply(3:5, FUN) 

: Suche

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")) 

Wie kann ich tu t seine Aufgabe auf die schnellste Art und Weise während des Aufenthalts in der Basis R?

nicht sicher, ob diese Sicht von dem, was ich bin nach hilfreich, aber es kann sein:

enter image description here

+0

Ist eine 5x5-Matrix die größte, die Sie haben zu testen erwarten würde? –

+0

Nein, es könnte größer sein (obwohl ich sehr bezweifle, dass es jemals viel größer wäre). –

+0

@TylerRinker - Ich musste gerade meine R-Sitzung schließen, während ich ein Benchmarking auf einer 10K * 10K-Matrix versuchte. 1K * 1K war eine Angelegenheit von ein paar Sekunden. Ich frage mich, ob Leute da draußen effizientere Implementierungen haben könnten. – thelatemail

Antwort

5

Nizza Problem! Hier ist, wie Sie es mit ein wenig Rekursion lösen kann (gefolgt von einer viel einfacheren Version)

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" 

Ich werde einfach einen Kommentar auf die Ausgabe nicht genau zu sein, wie Sie gefragt. Es ist, weil rekursiven Funktionen erstellen, die eine flache Liste sind immer schwierig zurückkehren, mit zu arbeiten: irgendwie immer Sie mit verschachtelten Listen am Ende ...

So ist der letzte Schritt sein soll:

lapply(x, strsplit, split = " ") 

und es wird in dem Format sein, nach dem Sie gefragt haben.


Und hier ist eine noch einfachere Version (über Rekursion vergessen!)

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

danke, das funktioniert sehr gut. Ich werde die Methode ohne Rekursion verwenden, da es nicht nötig ist, 'strsplit' zu verwenden (und wenn es eine numerische Matrix ist, muss man' as.numeric' nicht verwenden). +1 –

3

Edited eine SIMPLIFY=FALSE hinzufügen, die jetzt gibt genau das, was Sie wollen:

Grundsätzlich ist diese Methode wird die Indexe aller oberen linken Ecken der Dreiecke, die Sie wollen, und dann die [Zelle unter] + [Zelle unter + nach rechts]. Nervenkitzel. Ein zusätzlicher Vorteil dieser Methode ist, dass sie für Objekte matrix und data.frame funktioniert.

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) 
} 

Und das Ergebnis:

> 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

Dieser Ansatz ist definitiv weniger Codierung und sehr einfach zu verstehen.Ich bewertete beide Antworten und Flodel ist schneller. Beide Funktionen sind schneller als das, was ich hatte (nichts). Vielen Dank für die Lösung des Problems. +1 –

+0

* "Beide Funktionen hier sind schneller als das, was ich hatte (nichts)" * - Ich mag das :-) – thelatemail

Verwandte Themen