Warunkowe przypisanie wartości do sąsiednich komórek rastrowych?

12

Mam raster wartości:

m <- matrix(c(2,4,5,5,2,8,7,3,1,6,
         5,7,5,7,1,6,7,2,6,3,
         4,7,3,4,5,3,7,9,3,8,
         9,3,6,8,3,4,7,3,7,8,
         3,3,7,7,5,3,2,8,9,8,
         7,6,2,6,5,2,2,7,7,7,
         4,7,2,5,7,7,7,3,3,5,
         7,6,7,5,9,6,5,2,3,2,
         4,9,2,5,5,8,3,3,1,2,
         5,2,6,5,1,5,3,7,7,2),nrow=10, ncol=10, byrow = T)
r <- raster(m)
extent(r) <- matrix(c(0, 0, 10, 10), nrow=2)
plot(r)
text(r)

Jak z tego rastra mogę przypisać wartości (lub zmienić wartości) 8 sąsiednim komórkom bieżącej komórki zgodnie z tą ilustracją? W bieżącej komórce umieściłem czerwony punkt z tej linii kodu:

points(xFromCol(r, col=5), yFromRow(r, row=5),col="red",pch=16)

wprowadź opis zdjęcia tutaj

Tutaj oczekiwany wynik to:

wprowadź opis zdjęcia tutaj

gdzie wartość bieżącej komórki (tj. 5 w rastrze wartości) jest zastępowana przez 0.

Ogólnie nowe wartości dla 8 sąsiednich komórek należy obliczyć w następujący sposób:

Nowa wartość = średnia wartości komórek zawartych w czerwonym prostokącie * odległość między bieżącą komórką (czerwony punkt) a sąsiednią komórką (tj. Sqrt (2) dla sąsiednich komórek po przekątnej lub 1 w innym przypadku)

Aktualizacja

Kiedy granice dla sąsiednich komórek są poza granicami rastra, muszę obliczyć nowe wartości dla sąsiednich komórek, które spełniają warunki. Sąsiednie komórki, które nie spełniają warunków, będą równe „NA”.

Na przykład, jeśli pozycją odniesienia jest c (1,1) zamiast c (5,5) za pomocą notacji [wiersz, kol], można obliczyć tylko nową wartość w prawym dolnym rogu. Zatem oczekiwany wynik to:

     [,1] [,2] [,3]       
[1,] NA   NA   NA         
[2,] NA   0    NA         
[3,] NA   NA   New_value

Na przykład, jeśli pozycją odniesienia jest c (3,1), można obliczyć tylko nowe wartości w prawym górnym, prawym i prawym dolnym rogu. Zatem oczekiwany wynik to:

     [,1] [,2] [,3]       
[1,] NA   NA   New_value         
[2,] NA   0    New_value         
[3,] NA   NA   New_value

Oto moja pierwsza próba focalzrobienia tego przy użyciu funkcji, ale mam pewne trudności z utworzeniem automatycznego kodu.

Wybierz sąsiednie komórki

mat_perc <- matrix(c(1,1,1,1,1,
                     1,1,1,1,1,
                     1,1,0,1,1,
                     1,1,1,1,1,
                     1,1,1,1,1), nrow=5, ncol=5, byrow = T)
cell_perc <- adjacent(r, cellFromRowCol(r, 5, 5), directions=mat_perc, pairs=FALSE, sorted=TRUE, include=TRUE)
r_perc <- rasterFromCells(r, cell_perc)
r_perc <- setValues(r_perc,extract(r, cell_perc))
plot(r_perc)
text(r_perc)

jeśli sąsiednia komórka znajduje się w lewym górnym rogu bieżącej komórki

focal_m <- matrix(c(1,1,NA,1,1,NA,NA,NA,NA), nrow=3, ncol=3, byrow = T)
focal_function <- function(x) mean(x,na.rm=T)*sqrt(2)
test <- as.matrix(focal(r_perc, focal_m, focal_function))

jeśli sąsiednia komórka znajduje się w górnym środkowym rogu bieżącej komórki

focal_m <- matrix(c(1,1,1,1,1,1,NA,NA,NA), nrow=3, ncol=3, byrow = T)
focal_function <- function(x) mean(x,na.rm=T)
test <- as.matrix(focal(r_perc, focal_m, focal_function))

jeśli sąsiednia komórka znajduje się w lewym górnym rogu bieżącej komórki

focal_m <- matrix(c(NA,1,1,NA,1,1,NA,NA,NA), nrow=3, ncol=3, byrow = T)
focal_function <- function(x) mean(x,na.rm=T)*sqrt(2)
test <- as.matrix(focal(r_perc, focal_m, focal_function))

jeśli sąsiednia komórka znajduje się w lewym rogu bieżącej komórki

focal_m <- matrix(c(1,1,NA,1,1,NA,1,1,NA), nrow=3, ncol=3, byrow = T)
focal_function <- function(x) mean(x,na.rm=T)
test <- as.matrix(focal(r_perc, focal_m, focal_function))

jeśli sąsiednia komórka znajduje się w prawym rogu bieżącej komórki

focal_m <- matrix(c(NA,1,1,NA,1,1,NA,1,1), nrow=3, ncol=3, byrow = T)
focal_function <- function(x) mean(x,na.rm=T)
test <- as.matrix(focal(r_perc, focal_m, focal_function))

jeśli sąsiednia komórka znajduje się w lewym dolnym rogu bieżącej komórki

focal_m <- matrix(c(NA,NA,NA,1,1,NA,1,1,NA), nrow=3, ncol=3, byrow = T)
focal_function <- function(x) mean(x,na.rm=T)*sqrt(2)
test <- as.matrix(focal(r_perc, focal_m, focal_function))

jeśli sąsiednia komórka znajduje się w środkowym dolnym rogu bieżącej komórki

focal_m <- matrix(c(NA,NA,NA,1,1,1,1,1,1), nrow=3, ncol=3, byrow = T)
focal_function <- function(x) mean(x,na.rm=T)
test <- as.matrix(focal(r_perc, focal_m, focal_function))

jeśli sąsiednia komórka znajduje się w prawym dolnym rogu bieżącej komórki

focal_m <- matrix(c(NA,NA,NA,NA,1,1,NA,1,1), nrow=3, ncol=3, byrow = T)
focal_function <- function(x) mean(x,na.rm=T)*sqrt(2)
test <- as.matrix(focal(r_perc, focal_m, focal_function))
Pierre
źródło
+1 Chciałbym, żeby wszystkie pytania były tak dobrze sformułowane! Szukasz operacji ogniskowej (statystyki ruchomego okna)? Sprawdź rasterpakiet R i focal()funkcję (s. 90 dokumentacji): cran.r-project.org/web/packages/raster/raster.pdf
Aaron
Bardzo dziękuję Aaronowi za radę! Rzeczywiście, ogniskowanie funkcji wydaje się bardzo przydatne, ale nie znam go. Na przykład dla sąsiedniej komórki = 8 (rysunek w lewym górnym rogu) przetestowałem mat <- matrix(c(1,1,0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0), nrow=5, ncol=5, byrow = T) f.rast <- function(x) mean(x)*sqrt(2) aggr <- as.matrix(focal(r, mat, f.rast)). Jak mogę uzyskać wynik tylko dla 8 sąsiednich komórek bieżącej komórki, a nie dla całego rastra? Tutaj, wynik powinien być: res <- matrix(c(7.42,0,0,0,0,0,0,0,0), nrow=3, ncol=3, byrow = T). Wielkie dzięki !
Pierre
@Pierre Czy musisz obliczyć sąsiednie wartości tylko dla pozycji wiersza 5, kol. 5? Czy przenieść tę pozycję odniesienia na przykład do nowego wiersza pozycji odniesienia 6, kol. 6?
Guzmán,
2
Czy możesz wyjaśnić (edytując pytanie), w jaki sposób należy obliczyć sąsiednie wartości, gdy granice dla sąsiednich komórek są poza limitami rastrowymi? Np .: wiersz 1, kol. 1
Guzmán,
1
Wasze przykłady nie mają sensu. W pierwszym, jeśli pozycją odniesienia jest c (1,1), tylko prawe dolne c (2,2) otrzyma nową wartość, ale wykazałeś, że c (3,3) otrzymuje wartość New_Value. Ponadto c (1,1) stanie się 0, a nie c (2,2).
Farid Cheraghi,

Odpowiedzi:

4

Poniższa funkcja AssignValuesToAdjacentRasterCellszwraca nowy obiekt RasterLayer z pożądanymi wartościami przypisanymi z oryginalnego wejścia rastrowego . Funkcja sprawdza, czy sąsiednie komórki z pozycji odniesienia znajdują się w granicach rastra. Wyświetla także komunikaty, jeśli jakieś ograniczenie jest wyłączone. Jeśli musisz przesunąć pozycję referencyjną, możesz po prostu napisać iterację zmieniającą pozycję wejściową na c ( i , j ).

Wprowadzanie danych

# Load packages
library("raster")

# Load matrix data
m <- matrix(c(2,4,5,5,2,8,7,3,1,6,
              5,7,5,7,1,6,7,2,6,3,
              4,7,3,4,5,3,7,9,3,8,
              9,3,6,8,3,4,7,3,7,8,
              3,3,7,7,5,3,2,8,9,8,
              7,6,2,6,5,2,2,7,7,7,
              4,7,2,5,7,7,7,3,3,5,
              7,6,7,5,9,6,5,2,3,2,
              4,9,2,5,5,8,3,3,1,2,
              5,2,6,5,1,5,3,7,7,2), nrow=10, ncol=10, byrow = TRUE)

# Convert matrix to RasterLayer object
r <- raster(m)

# Assign extent to raster
extent(r) <- matrix(c(0, 0, 10, 10), nrow=2)

# Plot original raster
plot(r)
text(r)
points(xFromCol(r, col=5), yFromRow(r, row=5), col="red", pch=16)

Funkcjonować

# Function to assigning values to the adjacent raster cells based on conditions
# Input raster: RasterLayer object
# Input position: two-dimension vector (e.g. c(5,5))

AssignValuesToAdjacentRasterCells <- function(raster, position) {

  # Reference position
  rowPosition = position[1]
  colPosition = position[2]

  # Adjacent cells positions
  adjacentBelow1 = rowPosition + 1
  adjacentBelow2 = rowPosition + 2
  adjacentUpper1 = rowPosition - 1
  adjacentUpper2 = rowPosition - 2
  adjacentLeft1 = colPosition - 1 
  adjacentLeft2 = colPosition - 2 
  adjacentRight1 = colPosition + 1
  adjacentRight2 = colPosition + 2

  # Check if adjacent cells positions are out of raster positions limits
  belowBound1 = adjacentBelow1 <= nrow(raster)
  belowBound2 = adjacentBelow2 <= nrow(raster)
  upperBound1 = adjacentUpper1 > 0
  upperBound2 = adjacentUpper2 > 0
  leftBound1 = adjacentLeft1 > 0 
  leftBound2 = adjacentLeft2 > 0 
  rightBound1 = adjacentRight1 <= ncol(raster)
  rightBound2 = adjacentRight2 <= ncol(raster) 

  if(upperBound2 & leftBound2) {

    val1 = mean(r[adjacentUpper2:adjacentUpper1, adjacentLeft2:adjacentLeft1]) * sqrt(2)

  } else {

    val1 = NA

  }

  if(upperBound2 & leftBound1 & rightBound1) {

    val2 = mean(r[adjacentUpper1:adjacentUpper2, adjacentLeft1:adjacentRight1])

  } else {

    val2 = NA

  }

  if(upperBound2 & rightBound2) {

    val3 = mean(r[adjacentUpper2:adjacentUpper1, adjacentRight1:adjacentRight2]) * sqrt(2)

  } else {

    val3 = NA

  }

  if(upperBound1 & belowBound1 & leftBound2) {

    val4 = mean(r[adjacentUpper1:adjacentBelow1, adjacentLeft2:adjacentLeft1])

  } else {

    val4 = NA

  }

  val5 = 0

  if(upperBound1 & belowBound1 & rightBound2) {

    val6 = mean(r[adjacentUpper1:adjacentBelow1, adjacentRight1:adjacentRight2])

  } else {

    val6 = NA

  }

  if(belowBound2 & leftBound2) {

    val7 = mean(r[adjacentBelow1:adjacentBelow2, adjacentLeft2:adjacentLeft1]) * sqrt(2)

  } else {

    val7 = NA

  }

  if(belowBound2 & leftBound1 & rightBound1) {

    val8 = mean(r[adjacentBelow1:adjacentBelow2, adjacentLeft1:adjacentRight1])

  } else {

    val8 = NA

  }

  if(belowBound2 & rightBound2) {

    val9 = mean(r[adjacentBelow1:adjacentBelow2, adjacentRight1:adjacentRight2]) * sqrt(2)

  } else {

    val9 = NA

  }

  # Build matrix
  mValues = matrix(data = c(val1, val2, val3,
                            val4, val5, val6,
                            val7, val8, val9), nrow = 3, ncol = 3, byrow = TRUE)    

  if(upperBound1) {

    a = adjacentUpper1

  } else {

    # Warning message
    cat(paste("\n Upper bound out of raster limits!"))
    a = rowPosition
    mValues <- mValues[-1,]

  }

  if(belowBound1) {

    b = adjacentBelow1

  } else {

    # Warning message
    cat(paste("\n Below bound out of raster limits!"))
    b = rowPosition
    mValues <- mValues[-3,]

  }

  if(leftBound1) {

    c = adjacentLeft1

  } else {

    # Warning message
    cat(paste("\n Left bound out of raster limits!"))
    c = colPosition
    mValues <- mValues[,-1]

  }

  if(rightBound1) {

    d = adjacentRight1

  } else {

    # Warning
    cat(paste("\n Right bound out of raster limits!"))
    d = colPosition
    mValues <- mValues[,-3]

  }

  # Convert matrix to RasterLayer object
  rValues = raster(mValues)

  # Assign values to raster
  raster[a:b, c:d] = rValues[,]  

  # Assign extent to raster
  extent(raster) <- matrix(c(0, 0, 10, 10), nrow = 2)

  # Return raster with assigned values
  return(raster)      

}

Uruchom przykłady

# Run function AssignValuesToAdjacentRasterCells

# reference position (1,1)
example1 <- AssignValuesToAdjacentRasterCells(raster = r, position = c(1,1))

# reference position (1,5)
example2 <- AssignValuesToAdjacentRasterCells(raster = r, position = c(1,5))

# reference position (1,10)
example3 <- AssignValuesToAdjacentRasterCells(raster = r, position = c(1,10))

# reference position (5,1)
example4 <- AssignValuesToAdjacentRasterCells(raster = r, position = c(5,1))

# reference position (5,5)
example5 <- AssignValuesToAdjacentRasterCells(raster = r, position = c(5,5))

# reference position (5,10)
example6 <- AssignValuesToAdjacentRasterCells(raster = r, position = c(5,10))

# reference position (10,1)
example7 <- AssignValuesToAdjacentRasterCells(raster = r, position = c(10,1))

# reference position (10,5)
example8 <- AssignValuesToAdjacentRasterCells(raster = r, position = c(10,5))

# reference position (10,10)
example9 <- AssignValuesToAdjacentRasterCells(raster = r, position = c(10,10))

Przykłady wykresów

# Plot examples
par(mfrow=(c(3,3)))

plot(example1, main = "Position ref. (1,1)")
text(example1)
points(xFromCol(example1, col=1), yFromRow(example1, row=1), col="red", cex=2.5, lwd=2.5)

plot(example2, main = "Position ref. (1,5)")
text(example2)
points(xFromCol(example2, col=5), yFromRow(example2, row=1), col="red", cex=2.5, lwd=2.5)

plot(example3, main = "Position ref. (1,10)")
text(example3)
points(xFromCol(example3, col=10), yFromRow(example3, row=1), col="red", cex=2.5, lwd=2.5)

plot(example4, main = "Position ref. (5,1)")
text(example4)
points(xFromCol(example4, col=1), yFromRow(example4, row=5), col="red", cex=2.5, lwd=2.5)

plot(example5, main = "Position ref. (5,5)")
text(example5)
points(xFromCol(example5, col=5), yFromRow(example5, row=5), col="red", cex=2.5, lwd=2.5)

plot(example6, main = "Position ref. (5,10)")
text(example6)
points(xFromCol(example6, col=10), yFromRow(example6, row=5), col="red", cex=2.5, lwd=2.5)

plot(example7, main = "Position ref. (10,1)")
text(example7)
points(xFromCol(example7, col=1), yFromRow(example7, row=10), col="red", cex=2.5, lwd=2.5)

plot(example8, main = "Position ref. (10,5)")
text(example8)
points(xFromCol(example8, col=5), yFromRow(example8, row=10), col="red", cex=2.5, lwd=2.5)

plot(example9, main = "Position ref. (10,10)")
text(example9)
points(xFromCol(example9, col=10), yFromRow(example9, row=10), col="red", cex=2.5, lwd=2.5)

Przykład ryciny

exampleFigure

Uwaga: średnie NAwartości białych krwinek

Guzmán
źródło
3

Dla operatora macierzy na małej macierzy ma to sens i jest wykonalne. Możesz jednak naprawdę przemyśleć swoją logikę, stosując taką funkcję do dużego rastra. Pod względem koncepcyjnym nie jest to tak naprawdę w przypadku ogólnego zastosowania. Mówisz o tym, co tradycyjnie nazywane jest statystyką blokową. Jednak statystyki bloków z natury zaczynają się od jednego rogu rastra i zastępują bloki wartości w określonym rozmiarze okna operatorem. Zwykle ten typ operatora służy do agregowania danych. Byłoby to znacznie łatwiejsze w użyciu, gdybyś pomyślał w kategoriach wykorzystania warunków do obliczenia wartości środkowej macierzy. W ten sposób możesz łatwo użyć funkcji ogniskowej.

Należy pamiętać, że funkcja ogniskowej rastra odczytuje w blokach danych, które reprezentują wartości ogniskowe w zdefiniowanym sąsiedztwie na podstawie macierzy przekazanej do argumentu w. Wynikiem jest wektor dla każdej okolicy, a wynik operatora ogniskowej jest przypisany tylko do komórki ogniskowej, a nie do całej okolicy. Pomyśl o tym, jak chwytanie macierzy otaczającej wartość komórki, działanie na niej, przypisywanie nowej wartości do komórki, a następnie przechodzenie do następnej komórki.

Jeśli upewnisz się, że na.rm = FAŁSZ, to wektor zawsze będzie reprezentował dokładne sąsiedztwo (tj. Ten sam wektor długości) i zostanie przekształcony w obiekt macierzowy, na którym można operować w ramach funkcji. Z tego powodu możesz po prostu napisać funkcję, która pobiera oczekiwany wektor, wymusza matrycę, stosuje logikę notacji sąsiedztwa, a następnie przypisuje pojedynczą wartość jako wynik. Tę funkcję można następnie przekazać do funkcji raster :: focal.

Oto, co dzieje się w każdej komórce na podstawie prostego przymusu i oceny okna ogniskowego. Obiekt „w” byłby zasadniczo taką samą definicją macierzy, jak w przypadku ogniskowej przekazania argumentu w. To określa rozmiar wektora podzbioru w każdej ocenie ogniskowej.

w=c(5,5)
x <- runif(w[1]*w[2])
x[25] <- NA
print(x)
( x <- matrix(x, nrow=w[1], ncol=w[2]) ) 
( se <- mean(x, na.rm=TRUE) * sqrt(2) )
ifelse( as.vector(x[(length(as.vector(x)) + 1)/2]) <= se, 1, 0) 

Teraz utwórz funkcję, która może być zastosowana do ogniskowania, stosując powyższą logikę. W takim przypadku możesz przypisać obiekt se jako wartość lub użyć go jako warunku w czymś takim jak „ifelse”, aby przypisać wartość na podstawie oceny. Dodaję instrukcję ifelse, aby zilustrować, w jaki sposób można ocenić wiele warunków sąsiedztwa i zastosować warunek położenia macierzy (notacji sąsiedztwa). W tej funkcji manekina przymus x względem macierzy jest całkowicie niepotrzebny i służy jedynie zilustrowaniu, jak by to było zrobione. Można zastosować warunki notacji sąsiedztwa bezpośrednio do wektora, bez przymusu macierzy, ponieważ pozycja w wektorze dotyczyłaby jego położenia w oknie ogniskowym i pozostała stała.

f.rast <- function(x, dims=c(5,5)) {
  x <- matrix(x, nrow=dims[1], ncol=dims[2]) 
  se <- mean(x, na.rm=TRUE) * sqrt(2)
  ifelse( as.vector(x[(length(as.vector(x)) + 1)/2]) <= se, 1, 0)   
}  

I zastosuj to do rastra

library(raster)
r <- raster(nrows=100, ncols=100)
  r[] <- runif( ncell(r) )
  plot(r)

( r.class <- focal(r, w = matrix(1, nrow=w[1], ncol=w[2]), fun=f.rast) )
plot(r.class)  
Jeffrey Evans
źródło
2

Możesz łatwo zaktualizować wartości rastra, zastępując raster za pomocą notacji [row, col]. Zauważ, że rząd i kolumna zaczynają się od lewego górnego rogu rastra; r [1,1] to wskaźnik lewego górnego piksela, a r [2,1] to ten pod r [1,1].

wprowadź opis zdjęcia tutaj

# the function to update raster cell values
focal_raster_update <- function(r, row, col) {
  # copy the raster to hold the temporary values
  r_copy <- r
  r_copy[row,col] <- 0
  #upper left
  r_copy[row-1,col-1] <- mean(r[(row-2):(row-1),(col-2):(col-1)]) * sqrt(2)
  #upper mid
  r_copy[row-1,col] <- mean(r[(row-2):(row-1),(col-1):(col+1)])
  #upper right
  r_copy[row-1,col+1] <- mean(r[(row-2):(row-1),(col+1):(col+2)]) * sqrt(2)
  #left
  r_copy[row,col-1] <- mean(r[(row-1):(row+1),(col-2):(col-1)])
  #right
  r_copy[row,col+1] <- mean(r[(row-1):(row+1),(col+1):(col+2)])
  #bottom left
  r_copy[row+1,col-1] <- mean(r[(row+1):(row+2),(col-2):(col-1)]) * sqrt(2)
  #bottom mid
  r_copy[row+1,col] <- mean(r[(row+1):(row+2),(col-1):(col+1)])
  #bottom right
  r_copy[row+1,col+1] <- mean(r[(row+1):(row+2),(col+1):(col+2)]) * sqrt(2)
  return(r_copy)
}
col <- 5
row <- 5
r <- focal_raster_update(r,row,col)

dev.set(1)
plot(r)
text(r,digits=2)
Farid Cheraghi
źródło