Pertanyaan R Menghitung Jumlah Nilai Identik Berdekatan dalam Bingkai Data atau Array


Saya memiliki dataset ukuran substrat kategoris dari dasar sungai. Karena cara saya mengumpulkan data, saya dapat mengaturnya secara spasial menjadi matriks di mana hubungan mereka dengan tetangga mereka dilestarikan (yaitu, di sebelah kiri, di depan, dll). Contohnya akan terlihat seperti ini:

     P.1 P.2 P.3 P.4 P.5
T 1    G   C   C   P   C
T 2    P   C   B   G   C
T 3   SI  SI   C   B   C
T 4   SI  BR  BR  SI  SI
T 5   BR  CL  BR  BR   B
T 6   BR  BR  BR  BR   C

Dimana P (n) adalah pengukuran titik aktual pada transek yang melintasi aliran dari kiri ke kanan, dan T (n) memberikan transek dari hulu ke hilir. Seperti yang Anda lihat, beberapa jenis substrat (terutama batuan dasar, "BR", dalam contoh ini), memiliki tambalan berdekatan yang lebih besar daripada yang lain. Ini secara ekologis berarti, dan mungkin lebih dari sekadar persentase BR dalam sampel.

Pertanyaan saya adalah ini: Apakah ada cara sederhana untuk menghitung jumlah pengukuran substrat dari jenis yang sama yang berdekatan satu sama lain? Perhatikan bahwa sudut yang berdekatan juga dianggap berdekatan.

EDIT mengikuti komentar yang sangat membantu:

Contoh keluaran adalah daftar setiap jenis patch, dan jumlah pengukuran di setiap patch. Mungkin terlihat seperti ini:

$BR  
[1] 9  

$B  
[1] 1 1  

$C  
[1] 4 3 1  

$P  
[1] 1 1  

$G  
[1] 1 1  

$SI  
[1] 3 2  

5
2018-02-03 20:48


asal


Jawaban:


Masalah kecil yang menyenangkan. Saya melampirkan solusi, itu harus bekerja pada setiap matriks faktor. Itu menggunakan foreach dan data.table paket sehingga Anda mungkin ingin menginstalnya.

Ia bekerja dengan terlebih dahulu menumpuk data dan memetakan setiap lokasi ke suatu nilai. Kemudian iterates melalui matriks asli melakukan rekursi diri serakah pada tetangga tetapi pertama menghapus dirinya sendiri (menghindari menghitung sendiri beberapa kali) dari matriks ditumpuk.

Saya tidak suka beberapa untuk loop dalam solusi ini tetapi mengingat percepatan dari berinteraksi dengan frame yang ditumpuk, saya tidak melihat cara mudah di sekitarnya tanpa kembali bekerja ini sepenuhnya. Implementasi yang lebih baik akan menjalankan ini dalam rangkaian paralel (mungkin dengan jenis patch bukan lokasi) menggunakan paket seperti sinkronisitas untuk meletakkan kunci mutex di sekitar data yang ditumpuk (siapa?).

dcast dalam reshape2 paket juga merupakan opsi yang baik untuk membuat bingkai yang ditumpuk.

Untuk matriks ini:

> d
    P-1 P-2 P-3 P-4 P-5 P-6
T-1   G   P  SI  SI  BR  BR
T-2   C   C  SI  BR  CL  BR
T-3   C   B   C  BR  BR  BR
T-4   P   G   B  SI  BR  BR
T-5   C   C   C  SI   B   C

Ini memberikan hasil sebagai berikut (yang terlihat seperti apa yang Anda minta):

> patchesList
$G
[1] 1 1
$C
[1] 4 3 1
$P
[1] 1 1
$B
[1] 2 1
$SI
[1] 3 2
$BR
[1] 9
$CL
[1] 1

Kode pengaturan data:

rm(list=ls())
d = strsplit("G   C   C   P   C P   C   B   G   C SI  SI   C   B   C SI  BR  BR  SI  SI BR  CL  BR  BR   B BR  BR  BR  BR   C"," ")[[1]]
d=d[-which(d=="")]
d=data.frame(matrix(d,nrow=5),stringsAsFactors=F)
rownames(d) = paste("T",1:5,sep="-")
colnames(d) = paste("P",1:6,sep="-")
levs = unique(unlist(d))

menumpuk data asli (dengan informasi tentang lokasi):

idxsFrame = expand.grid(1:nrow(d),1:ncol(d))
colnames(idxsFrame) = c("ri","cj")
idxsFrame$value = apply(idxsFrame,1,function(x) { d[x[["ri"]],x[["cj"]]] } )
require(data.table)
idxsFrame = data.table(idxsFrame)

mengatur daftar output:

patchesList = vector(mode="list",length=length(levs))
names(patchesList) = levs 
require(foreach)

fungsi rekursif diri yang melakukan pemindaian:

scanSurroundTiles = function(tile) 
{  
  surroundTiles = idxsFrame[ri>=(tile$ri-1) & ri <=(tile$ri+1) & cj>=(tile$cj-1) & cj<=(tile$cj+1),,drop=F]
  baseMatches = surroundTiles[which(surroundTiles$value == tile$value),,drop=F]  
  if(nrow(baseMatches) < 1) 
    return(tile)
  else
  {
    # not possible to do an apply(matches,1,scanSurroundTiles) because of overlap and self-recursiveness on deeper levels
    newMatches <- foreach(mc = 1:nrow(baseMatches), .combine=rbind) %do% # mc = 2; 
    {
      inIdxs = which(idxsFrame$ri==baseMatches$ri[mc] & idxsFrame$cj==baseMatches$cj[mc])
      if(length(inIdxs)>0)
      { assign("idxsFrame",idxsFrame[-inIdxs,,drop=F],globalenv()) 
        return(scanSurroundTiles(baseMatches[mc,,drop=F]))      
      } else
      { return(NULL) } # could have been removed from previous foreach 
    }
    return(rbind(tile,newMatches))
  }
}

lingkaran utama:

for(i in 1:nrow(d))  
{
  for(j in 1:ncol(d)) 
  { 
    sourceTile = idxsFrame[ri==i & cj==j,,drop=F]
    if(nrow(sourceTile) > 0)
    {
      idxsFrame <- idxsFrame[-which(idxsFrame$ri==sourceTile$ri & idxsFrame$cj==sourceTile$cj),,drop=F]
      thisPatch = scanSurroundTiles(sourceTile)
# if you want to do some calc by patch (mean, sd) this is the place to do it by adding other info beyond the type in the stacked frame
      patchesList[[thisPatch$value[1]]] = c(patchesList[[thisPatch$value[1]]],nrow(thisPatch))      
    }  
  }
}

3
2018-02-05 23:30