1 hücre / piksel tohumlarından bir rasterde rastgele şekilli hücre kümeleri mi oluşturuyorsunuz?


11

Başlığımın dediği gibi, bir raster içinde tohumlardan hücre kümelerini "büyütmek" istiyorum. Temel rasterim 1 ve 0'larla dolu, 1'ler kara ve 0'ın deniz / NA alanlarını gösteriyor. 1'lerden tohumlarım olarak 60 rastgele piksel / hücre seçmek ve daha sonra önceden tanımlanmış bir no. piksel / hücre sayısı o tohumdan sınırlanır. Tekniğin 'yayılan boya' olarak adlandırılabileceğini duydum ama üzerinde fazla bir şans bulamadım. Tohum hücresi 2 değerine çevrilecek ve daha sonra 1'lerin etrafından seçilen bir sonraki hücre de 2'ye dönüştürülecektir. 2'ler daha sonra dönüştürülemez.

Bu iş parçacığı biraz yardımcı olur, ben de R'de GIS verilerini okuma ve değiştirme konusunda bilgili olduğum için bunu R'de yapmaya istekli olacağım. Ancak, istediğim, mevcut kümeyi çevreleyen pikselleri rastgele seçmek için bir dizi kural .

Birisi bir CBS ortamında bu daha temel hücresel otomata yaptıysa, o zaman herhangi bir tavsiye / rehberlik takdir ediyorum.

Misal:

250 hücre hedefim var. Rastgele 1 değerine sahip bir hücre seçiyorum. Bu, 2 değerine çevrildi. Daha sonra, tohum hücresinin komşularından biri = 1 olan 2'ye döndü. Daha sonra, hücrelerin komşularından biri 2 değeriyle seçilir ve 2'ye dönüştürülür. Bu, 250 hücre numaralı sürekli bir şekle ulaşılıncaya kadar devam eder.

Düzenleme: Diğer Sorular

Whuber'ın büyük cevabına dayanarak, kod hakkında birkaç sorum var:

  1. Yetiştirilen hücrelerin değerlerini, oluşturuldukları sırayı temsil eden değişken değerlerden ziyade sadece bir '2'ye nasıl tahsis edebilirim?
  2. '1'lerim alanında 60 küme oluşturmam gerekiyor. Rastgele başlangıç ​​pozisyonları seçmenin yollarını buldum ama expandnazikçe yazdığınız işlevi kullanarak her şeyin bir döngü içinde çalışmasını sağlamak için mücadele ediyorum. Birbirleriyle çarpışmayan ve aynı nihai matriste bulunan 60 küme oluşturmanın bir yolunu önerebilir misiniz?

Edit: Sorunun başka açıklaması

Her bir hücre kümesi, tanımlanmış boyuttaki korunmuş bir alanı, örneğin 250 hücreyi temsil edecektir. Her alanın başlaması ve 1 değeri olan hücrelere dönüşmesi gerekir, çünkü bu karayı temsil eder ve 0 değeri olan hücrelerden kaçınır, çünkü bu denizdir. Bu alanların hangi dağılımlarının tesadüfen olacağını gösteren boş bir model oluşturmak için bu yinelemede her bir yinelemede 60 korumalı alanla 1000 kez yinelemem gerekiyor. Bu nedenle, 60 alanın her birindeki toplam hücre sayısının, 1000 iterasyonun her birinde aynı olması gerekir, böylece karşılaştırılabilirler. Bu nedenle, alanlar dokunursa sorun olmaz, ancak bir çarpışma varsa, ideal olarak küme 250 hedefine ulaşılana kadar mevcut başka bir yönde büyüyecektir.

Bu 1000 korumalı alan ağının her biri oluşturulduktan sonra, (a) belirli tür aralıkları ile kesişip kesişmediklerini ve (b) belirli türlerin% 'sinin bu rastgele ağları araladığını görmek için biyolojik çeşitlilik önlemleri gibi diğer raster verilerine karşı maske olarak kullanılacaktır. korunan alanların kaplanması.

Şimdiye kadarki yardımınız için @whuber'a teşekkürler, bana yardım etmek için daha fazla zaman harcamayı beklemiyorum, ancak talep ettiğiniz gibi durumumu açıklamaya çalışacağımı düşündüm.


R'nin yanı sıra, bu analiz için başka hangi programlama dillerini / yazılımlarını kullanmak istiyorsunuz?
Aaron

ArcGIS veya QGIS kullanmaktan da memnuniyet duyarım. Ne yazık ki python'a aşina değilim. Bir bash terminali üzerinden GDAL de bir olasılıktır.
JPD

Yanıtlar:


12

Diğer platformlarda nasıl ele alınabileceğini göstermek Riçin biraz da olsa kodlanmamış bir çözüm sunacağım R.

R(Diğer bazı platformların yanı sıra, özellikle işlevsel bir programlama stilini tercih edenler) endişesi, büyük bir dizinin sürekli güncellenmesinin çok pahalı olabileceğidir. Bunun yerine, bu algoritma, (a) şimdiye kadar doldurulmuş tüm hücrelerin listelendiği ve (b) seçilebilecek tüm hücrelerin (doldurulmuş hücrelerin çevresinde) bulunduğu kendi özel veri yapısını korur. listelendi. Bu veri yapısının manipüle edilmesi, bir diziye doğrudan endekslenmekten daha az verimli olmasına rağmen, değiştirilen verileri küçük bir boyutta tutarak, muhtemelen çok daha az hesaplama süresi alacaktır. (Bunu Rda optimize etmek için hiçbir çaba gösterilmedi . Durum vektörlerinin önceden tahsis edilmesi, içinde çalışmaya devam etmeyi tercih ederseniz, bazı yürütme sürelerinden tasarruf etmelidir R.)

Kod yorumlanır ve okunması kolay olmalıdır. Algoritmayı olabildiğince eksiksiz hale getirmek için, sonucu çizmek için sonunda hiçbir eklenti kullanılmaz. Zor olan tek nokta, verimlilik ve basitlik için 1D dizinleri kullanarak 2D ızgaralara endekslemeyi tercih etmesidir. Bir neighborshücrenin erişilebilir komşularının ne olabileceğini anlamak ve daha sonra bunları 1D indeksine dönüştürmek için 2D indekslemeye ihtiyaç duyan fonksiyonda bir dönüşüm gerçekleşir . Bu dönüşüm standart, bu yüzden diğer GIS platformlarında sütun ve satır dizinlerinin rollerini ters çevirmek isteyebileceğinize işaret etmek dışında daha fazla yorum yapmayacağım. (In R, satır dizinleri sütun dizinleri değişmeden önce değişir.)

Bunu göstermek için, bu kod xaraziyi temsil eden bir ızgarayı ve erişilemeyen noktaların nehir benzeri bir özelliğini alır, bu ızgarada (nehrin alt kıvrımının yakınında) belirli bir yerde (5, 21) başlar ve 250 noktayı kapsayacak şekilde rastgele genişletir. . Toplam zamanlama 0.03 saniyedir. (Dizinin boyutu, 5000 sütun ile 10.000 ila 3000 satır arasında bir faktör artırıldığında, zamanlama yalnızca 0.09 saniyeye kadar yükselir - sadece 3 veya daha fazla bir faktör - bu algoritmanın ölçeklenebilirliğini gösterir.) Bunun yerine sadece 0, 1 ve 2'lik bir ızgara çıkarır, yeni hücrelerin tahsis edildiği sırayı verir. Şekilde en eski hücreler yeşildir, altınlardan somon renklerine geçer.

harita

Her bir hücrenin sekiz noktalı bir mahallesinin kullanıldığı açık olmalıdır. Diğer mahalleler için, nbrhooddeğeri yalnızca başlangıcına yakın bir yerde değiştirin expand: belirli bir hücreye göre dizin ofsetleri listesidir. Örneğin, bir "D4" mahallesi olarak belirtilebilir matrix(c(-1,0, 1,0, 0,-1, 0,1), nrow=2).

Bu yayılma yönteminin problemleri olduğu da açıktır: arkada delikler bırakır. Amaçlanan bu değilse, bu sorunu çözmenin çeşitli yolları vardır. Örneğin, bulunan hücreleri ilk sırada tutun, böylece bulunan en eski hücreler de doldurulan en eski hücreler olur. Yine de bazı randomizasyonlar uygulanabilir, ancak mevcut hücreler artık tekdüze (eşit) olasılıklarla seçilmeyecektir. Başka, daha karmaşık bir yol, kaç dolu komşuya sahip olduklarına bağlı olasılıkları olan mevcut hücreleri seçmek olacaktır. Bir hücre çevrelendiğinde, seçim şansını o kadar yüksek yapabilirsiniz ki birkaç delik dolmadan bırakılacaktır.

Bunun, hücre hücre ilerlemeyecek, ancak her nesildeki tüm hücre alanlarını güncelleyecek bir hücresel otomat (CA) olmadığını yorumlayarak bitireceğim. Fark incedir: CA ile hücreler için seçim olasılıkları aynı olmaz.

#
# Expand a patch randomly within indicator array `x` (1=unoccupied) by
# `n.size` cells beginning at index `start`.
#
expand <- function(x, n.size, start) {
  if (x[start] != 1) stop("Attempting to begin on an unoccupied cell")
  n.rows <- dim(x)[1]
  n.cols <- dim(x)[2]
  nbrhood <- matrix(c(-1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1), nrow=2)
  #
  # Adjoin one more random cell and update `state`, which records
  # (1) the immediately available cells and (2) already occupied cells.
  #
  grow <- function(state) {
    #
    # Find all available neighbors that lie within the extent of `x` and
    # are unoccupied.
    #
    neighbors <- function(i) {
      n <- c((i-1)%%n.rows+1, floor((i-1)/n.rows+1)) + nbrhood
      n <- n[, n[1,] >= 1 & n[2,] >= 1 & n[1,] <= n.rows & n[2,] <= n.cols, 
             drop=FALSE]             # Remain inside the extent of `x`.
      n <- n[1,] + (n[2,]-1)*n.rows  # Convert to *vector* indexes into `x`.
      n <- n[x[n]==1]                # Stick to valid cells in `x`.
      n <- setdiff(n, state$occupied)# Remove any occupied cells.
      return (n)
    }
    #
    # Select one available cell uniformly at random.
    # Return an updated state.
    #
    j <- ceiling(runif(1) * length(state$available))
    i <- state$available[j]
    return(list(index=i,
                available = union(state$available[-j], neighbors(i)),
                occupied = c(state$occupied, i)))
  }
  #
  # Initialize the state.
  # (If `start` is missing, choose a value at random.)
  #
  if(missing(start)) {
    indexes <- 1:(n.rows * n.cols)
    indexes <- indexes[x[indexes]==1]
    start <- sample(indexes, 1)
  }
  if(length(start)==2) start <- start[1] + (start[2]-1)*n.rows
  state <- list(available=start, occupied=c())
  #
  # Grow for as long as possible and as long as needed.
  #
  i <- 1
  indices <- c(NA, n.size)
  while(length(state$available) > 0 && i <= n.size) {
    state <- grow(state)
    indices[i] <- state$index
    i <- i+1
  }
  #
  # Return a grid of generation numbers from 1, 2, ... through n.size.
  #
  indices <- indices[!is.na(indices)]
  y <- matrix(NA, n.rows, n.cols)
  y[indices] <- 1:length(indices)
  return(y)
}
#
# Create an interesting grid `x`.
#
n.rows <- 3000
n.cols <- 5000
x <- matrix(1, n.rows, n.cols)
ij <- sapply(1:n.cols, function(i) 
      c(ceiling(n.rows * 0.5 * (1 + exp(-0.5*i/n.cols) * sin(8*i/n.cols))), i))
x[t(ij)] <- 0; x[t(ij - c(1,0))] <- 0; x[t(ij + c(1,0))] <- 0
#
# Expand around a specified location in a random but reproducible way.
#
set.seed(17)
system.time(y <- expand(x, 250, matrix(c(5, 21), 1)))
#
# Plot `y` over `x`.
#
library(raster)
plot(raster(x[n.rows:1,], xmx=n.cols, ymx=n.rows), col=c("#2020a0", "#f0f0f0"))
plot(raster(y[n.rows:1,] , xmx=n.cols, ymx=n.rows), 
     col=terrain.colors(255), alpha=.8, add=TRUE)

Küçük değişikliklerle, expandbirden çok küme oluşturmak için döngü yapabiliriz . Kümeleri burada 2, 3, ..., vb. Çalıştıracak bir tanımlayıcı ile ayırmanız önerilir.

İlk olarak, bir değişiklik expand, (a) geri dönmek için NA, bir hata ve (b) değerleri vardır, ilk satırında indicesyerine bir matris y. ( yHer çağrıda yeni bir matris oluşturmak için zaman kaybetmeyin .) Bu değişiklik yapıldığında, döngü kolaydır: rastgele bir başlangıç ​​seçin, etrafında genişlemeyi deneyin, indicesbaşarılıysa küme dizinlerini biriktirin ve bitene kadar tekrarlayın. Döngünün önemli bir parçası, birçok bitişik kümenin bulunamaması durumunda yineleme sayısını sınırlamaktır: bu ile yapılır count.max.

İşte 60 küme merkezinin rasgele bir şekilde seçildiği bir örnek.

size.clusters <- 250
n.clusters <- 60
count.max <- 200
set.seed(17)
system.time({
  n <- n.rows * n.cols
  cells.left <- 1:n
  cells.left[x!=1] <- -1 # Indicates occupancy of cells
  i <- 0
  indices <- c()
  ids <- c()
  while(i < n.clusters && length(cells.left) >= size.clusters && count.max > 0) {
    count.max <- count.max-1
    xy <- sample(cells.left[cells.left > 0], 1)
    cluster <- expand(x, size.clusters, xy)
    if (!is.na(cluster[1]) && length(cluster)==size.clusters) {
      i <- i+1
      ids <- c(ids, rep(i, size.clusters))
      indices <- c(indices, cluster)
      cells.left[indices] <- -1
    }                
  }
  y <- matrix(NA, n.rows, n.cols)
  y[indices] <- ids
})
cat(paste(i, "cluster(s) created.", sep=" "))

310 x 500 ızgaraya uygulandığında sonuç (kümelerin görünür olması için yeterince küçük ve kaba yapılır). Yürütülmesi iki saniye sürer; 3100 x 5000 ızgarada (100 kat daha büyük) daha uzun (24 saniye) sürer, ancak zamanlama oldukça iyi ölçeklenir. (C ++ gibi diğer platformlarda, zamanlama neredeyse ızgara boyutuna bağlı olmamalıdır.)

60 küme


Merhaba Whuber. Bunun için çok teşekkürler, gerçekten minnettarım. Ben sadece biraz deniyorum ve yakında birkaç takip soru ile geri gelebilir.
JPD

+1 CBS SE ile ilgili daha karmaşık sorulara bu kadar kapsamlı cevaplar verdiğiniz için teşekkür ederiz.
Radar

@whuber. Cevabınıza göre soruyu biraz genişlettik. Tekrar teşekkürler!
JPD

1
1. cevabı oldukça basittir: çizgisini değiştirmek y[indices] <- 1:length(indices)tarafından y[indices] <- 2. # 2'nin cevabı neredeyse basittir: sadece döngü.
whuber

@whuber. Güncelleme için tekrar teşekkürler. Şimdi, kümeler çatışması ve sonuçta ortaya çıkan kümelerin boyutta tanımlanan sayıdan daha az olması sorunu var size.clusters. Şu anda mevcut bir kümeye dönüşmeye çalıştığını, başarısız olduğunu, ancak yine de başarılı bir genişleme olarak kaydolduğunu varsaydığım için, bir kümenin doğru boyuta ulaştığından nasıl emin olabilirim. Daha sonra ortalama bir sıfır model tarzı veri kümesi oluşturarak 60 kümenin üretimini 1000 kez yinelemeyi planlıyorum. Rastgele konumlandırma bir fordöngü içinde her seferinde değişir mi?
JPD

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.