2017-01-18 11 views
10

Próbuję napisać kod R, aby zwrócić największą liczbę kolejnych liczb w macierzy. Kolejne pary mogą być poziome, pionowe i obie przekątne.R: zwracaj największą liczbę kolejnych liczb w macierzy

np , jeśli mają matrycę:

ma = array(c(8,4,3,1,7,5,9,15,6,10,16,11,2,14,12,13), dim = c(4,4)) 

najwyższe kolejnych parach (1) w poziomie: 16 i 12; (2) Pionowo: 16 i 11 (3) po przekątnej(): 16 i 13; i (4) po przekątnej (/): 16 i 15.

Jak mogę to zrobić w R?

+3

'S <- MA [1: 3] + MA [2: 4]; which (s == max (s), arr.ind = TRUE) 'dla uzyskania indeksów pierwszej pary dla wierszy; jego para będzie bezpośrednio pod nim. W przypadku kolumn możesz po prostu przerzucić przecinki. Diagonale będą nieco więcej pracy. – alistaire

+1

Przekątne powinny być po prostu 's <- ma [1: 3,1: 3] + ma [2: 4,2: 4]; który (s == max (s), arr.ind = TRUE) 'nie? – BonStats

+0

szukasz następnej pary o największej sumie? W przeciwnym razie, jak porównać pary? – C8H10N4O2

Odpowiedz

1

Oto rozwiązanie wykorzystujące arytmetykę macierzy, która będzie o wiele bardziej wydajna niż pętla zagnieżdżona nad wierszami i kolumnami, szczególnie na dużych macierzach.

directionalSums <- function(x){ 
    stopifnot(is.matrix(x)) 

    # padding functions to allow matrix addition 
    padL <- function(x) cbind(-Inf,x) 
    padR <- function(x) cbind(x,-Inf) 
    padU <- function(x) rbind(-Inf,x) 
    padD <- function(x) rbind(x,-Inf) 

    # these padding functions are just for readability 
    padLU <- function(x) padL(padU(x)) 
    padLD <- function(x) padL(padD(x)) 
    padRU <- function(x) padR(padU(x)) 
    padRD <- function(x) padR(padD(x)) 

    m <- nrow(x) 
    n <- ncol(x) 

    sumR <- padR((padL(x) + padR(x))[1:m,2:n]) 
    sumD <- padD((padU(x) + padD(x))[2:m,1:n]) 
    sumRD <- padRD((padLU(x) + padRD(x))[2:m,2:n]) 
    sumRU <- padRU((padRU(x) + padLD(x))[2:m,2:n]) 

    list(`right`=sumR, 
     `down`=sumD, 
     `right and down`=sumRD, 
     `right and up`=sumRU) 

} 

Spróbujmy.

(sumList <- directionalSums(ma)) 

maxLocList <- lapply(sumList, function(x) which(x==max(x), arr.ind=TRUE)) 

for (i in 1:length(maxLocList)){ 
    nameD <- names(maxLocList)[i] 
    startCell <- maxLocList[[i]] 
    maxSum <- sumList[[i]][startCell] 
    x1 <- ma[startCell] 
    x2 <- maxSum - x1 
    writeLines(paste0('The max-sum consec. pair going ', 
        nameD, ' starts at [', 
        paste(startCell, collapse=', '), 
        '], with sum ', maxSum, 
        ' and components ', x1, ' and ',x2) 
      ) 
} 

Zwraca:

$right 
    [,1] [,2] [,3] [,4] 
[1,] 15 13 8 -Inf 
[2,] 9 15 24 -Inf 
[3,] 12 25 28 -Inf 
[4,] 16 26 24 -Inf 

$down 
    [,1] [,2] [,3] [,4] 
[1,] 12 12 16 16 
[2,] 7 14 26 26 
[3,] 4 24 27 25 
[4,] -Inf -Inf -Inf -Inf 

$`right and down` 
    [,1] [,2] [,3] [,4] 
[1,] 13 17 20 -Inf 
[2,] 13 21 22 -Inf 
[3,] 18 20 29 -Inf 
[4,] -Inf -Inf -Inf -Inf 

$`right and up` 
    [,1] [,2] [,3] [,4] 
[1,] -Inf -Inf -Inf -Inf 
[2,] 11 11 12 -Inf 
[3,] 8 19 30 -Inf 
[4,] 10 31 23 -Inf 

The max-sum consec. pair going right starts at [3, 3], with sum 28 and components 16 and 12 
The max-sum consec. pair going down starts at [3, 3], with sum 27 and components 16 and 11 
The max-sum consec. pair going right and down starts at [3, 3], with sum 29 and components 16 and 13 
The max-sum consec. pair going right and up starts at [4, 2], with sum 31 and components 15 and 16 
0

Oto sposób, aby to zrobić za pomocą prostego (ale długiego) kodu.

Ponieważ szukasz pary o największej liczbie kolejnych, powinieneś najpierw utworzyć funkcję, która pobiera komórkę i znajduje wszystkie jej kolejne sumy.

consec <- function(ma,y,x){ 
    return(
    c(if(x<ncol(ma))    ma[y,x] + ma[y,x+1], 
     if(x>1)      ma[y,x] + ma[y,x-1], 
     if(y<nrow(ma))    ma[y,x] + ma[y+1,x], 
     if(y>1)      ma[y,x] + ma[y-1,x], 
     if(x<ncol(ma) & y<nrow(ma)) ma[y,x] + ma[y+1,x+1], 
     if(x>1 & y<nrow(ma))  ma[y,x] + ma[y+1,x-1], 
     if(x<ncol(ma) & y>1)  ma[y,x] + ma[y-1,x+1], 
     if(x>1 & y>1)    ma[y,x] + ma[y-1,x-1]) 
) 
} 

Lewa połowa tej funkcji (sprawozdania if) upewnić się, że nie wykraczają poza granice, ponieważ komórka na granicy będzie mieć mniej niż 8 sąsiadów, aby utworzyć parę z rzędu. Prawa połowa, a następnie get jest sumą kolejnych par i dodaje ją do listy.

Teraz, jeśli użyjesz consec(ma, 3, 2), otrzymasz wektor sum następujących po sobie wartości dla ma[3,2].

Następnie chcemy wypełnić drugą macierz z najwyższą kolejną sumą dla każdej komórki. Możesz użyć następującego kodu, aby utworzyć pustą macierz o odpowiednich wymiarach.

ma2 <- matrix(0, nrow = nrow(ma), ncol = ncol(ma)) 

Teraz wypełnij go za pomocą pętli i utworzonej wcześniej funkcji consec.

for(i in 1:nrow(ma)){ 
    for(j in 1:ncol(ma)){ 
    ma2[i,j] <- max(consec(ma,i,j)) 
    } 
} 

Teraz, gdy mamy macierz kolejnych sum, możemy znaleźć największe sumy w nim, a współrzędne to będzie odpowiadać, gdzie chcemy szukać w oryginalnej matrycy.

ma.max <- which(ma2 == max(ma2), arr.ind = TRUE) 

Teraz, jeśli istnieje tylko jedna para liczb, która jest maksymalna, a następnie ma.max będzie mieć dwie linie (dwie permutacje tej samej pary). Możesz użyć:

ma[ma.max[1,1], ma.max[1,2]]; ma[ma.max[2,1], ma.max[2,2]] 

Aby je wyświetlić. W takim przypadku otrzymujemy 15 i 16, więc zadziałało.

Jeśli masz więcej maksimów, zwiększ liczbę w powyższym kodzie, aby uzyskać następną parę (3 i 4) i tak dalej. Możesz nawet zmodyfikować funkcję consec, na przykład, jeśli nie chcesz kolejnych przekątnych, a następnie usuń ostatnie cztery wiersze listy.