Classificazione senza supervisione con kmean in R


10

Ho una serie temporale di immagini satellitari (5 bande) e desidero classificarle in base ai kmean in R. La mia sceneggiatura funziona bene (passa in rassegna le mie immagini, converte le immagini in data.frame, raggruppale e riconvertile in un raster):

for (n in files) {
image <- stack(n)    
image <- clip(image,subset)

###classify raster
image.df <- as.data.frame(image)  
cluster.image <- kmeans(na.omit(image.df), 10, iter.max = 10, nstart = 25) ### kmeans, with 10 clusters

#add back NAs using the NAs in band 1 (identic NA positions in all bands), see http://stackoverflow.com/questions/12006366/add-back-nas-after-removing-them/12006502#12006502
image.df.factor <- rep(NA, length(image.df[,1]))
image.df.factor[!is.na(image.df[,1])] <- cluster.image$cluster

#create raster output
clusters <- raster(image)   ## create an empty raster with same extent than "image"  
clusters <- setValues(clusters, image.df.factor) ## fill the empty raster with the class results  
plot(clusters)
}

Il mio problema è: non riesco a confrontare i risultati della classificazione tra loro perché gli assegnatori di cluster differiscono da immagine a immagine. Ad esempio, "acqua" si trova nel primo cluster di immagini numero 1, nei successivi 2 e nei terzi 10, rendendo impossibile confrontare i risultati dell'acqua tra le date.

Come posso risolvere l'assegnazione del cluster?

Posso specificare un punto di partenza fisso per tutte le immagini (sperando che l'acqua venga sempre rilevata per prima e quindi classificata come 1)?

E se sì, come?

Risposte:


6

Penso che non puoi ... Devi prima etichettare ogni classe per confrontarle. Kmean si classifica senza supervisione così senza alcuna informazione preliminare e quindi non può definire alcun tipo di classe.

Se si dispone di un livello di riferimento, è possibile creare un'etichettatura a maggioranza dei voti. Ecco un codice molto più efficiente per il voto a maggioranza rispetto all'utilizzo della funzione del pacchetto "raster" zonal:

require (data.table)
fun <- match.fun(modal)
vals <- getValues(ref) 
zones <- round(getValues(class_file), digits = 0) 
rDT <- data.table(vals, z=zones) 
setkey(rDT, z) 
zr<-rDT[, lapply(.SD, modal,na.rm=T), by=z]

dove si reftrova il file di riferimento della classe raster, class_fileè il risultato kmean.

zr ti dà nella prima colonna il numero di "zona" e nella seconda colonna l'etichetta per la classe.


Avevo paura che non fosse possibile. Grazie per il codice per il voto a maggioranza!
Iris,

4

Per implementare il clustering su uno stack di immagini, non lo si fa banda per banda ma piuttosto sull'intero stack di immagini contemporaneamente. Altrimenti, come sottolineato da @nmatton, la statistica non ha molto senso.

Tuttavia, non sono d'accordo sul fatto che ciò non sia possibile, ma solo ad alta intensità di memoria. Sui dati satellitari reali questo sarà un grosso problema, e forse impossibile su dati ad alta risoluzione, ma è possibile elaborare in memoria forzando i propri raster in un singolo oggetto che può essere passato a una funzione di clustering. Sarà necessario tenere traccia dei valori NA tra i raster perché verranno rimossi durante il clustering e sarà necessario conoscere le posizioni nel raster in modo da poter assegnare i valori del cluster alle celle corrette.

Possiamo passare attraverso un approccio qui. Consente di aggiungere le librerie richieste e alcuni dati di esempio (il logo RGB R per darci 3 bande con cui lavorare).

library(raster)
library(cluster)
r <- stack(system.file("external/rlogo.grd", package="raster")) 
  plot(r)

Innanzitutto, possiamo forzare il nostro oggetto stack raster multibanda in un data.frame usando getValues. Si noti che sto aggiungendo un valore NA alla riga 1, colonna 3, in modo da poter illustrare come gestire i dati.

r.vals <- getValues(r[[1:3]])
  r.vals[1,][3] <- NA

Qui, possiamo metterci al lavoro e creare un indice di cella dei valori non NA che verrà utilizzato per assegnare i risultati del cluster.

idx <- 1:ncell(r)
idx <- idx[-unique(which(is.na(r.vals), arr.ind=TRUE)[,1])]  

Ora creiamo un oggetto cluster dai valori RGB a 3 bande con k = 4. Sto usando il metodo clara K-Medoids perché è buono con dati di grandi dimensioni ed è migliore con distribuzioni dispari. È molto simile a K-Means.

clus <- cluster::clara(na.omit(scale(r.vals)), k=4)

Per semplicità, possiamo creare un raster vuoto estraendo una delle bande raster dal nostro oggetto stack raster originale e assegnandogli i valori NA.

r.clust <- r[[1]]
r.clust[] <- NA

Infine, utilizzando l'indice, assegniamo i valori del cluster alla cella appropriata nel raster vuoto e tracciamo i risultati.

r.clust[idx] <- clus$clustering
plot(r.clust) 

Per i raster enormi potresti voler esaminare il pacchetto bigmemory che scrive le matrici sul disco e funziona su blocchi e c'è una funzione k-mean disponibile. Inoltre, tieni presente che questo non è esattamente ciò per cui R è stato progettato e che un'elaborazione delle immagini o un software GIS potrebbero essere più appropriati. So che SAGA e la cassetta degli attrezzi di Orfeo sono entrambi software gratuiti che hanno clustering k-mean disponibile per stack di immagini. Esiste persino una libreria RSAGA che consente di chiamare il software da R.


Se tutte le immagini sono impilate e raggruppate contemporaneamente, il risultato è un'immagine raggruppata, giusto?
Iris,

@Iris, sì, è così che funziona questo tipo di clustering di immagini e segue le implementazioni nel software di telerilevamento. Un esempio chiaro e pertinente sarebbe l'implementazione dell'isocluster in ArcGIS ( desktop.arcgis.com/en/arcmap/10.3/tools/spatial-analyst-toolbox/… )
Jeffrey Evans,

Quindi questa risposta non aiuta affatto. Il mio problema era che ho cercato di effettuare un rilevamento delle modifiche nel tempo in base a diverse classificazioni delle immagini non controllate, ma ho potuto confrontare i diversi risultati perché le classi sono state assegnate in modo diverso.
Iris,

La classificazione senza supervisione non è un modo fattibile per eseguire il rilevamento delle modifiche. Anche una leggera variazione in una data immagine potrebbe finire con l'assegnazione di pixel in una classe diversa. Questo sarebbe il caso anche se hai fornito centri cluster per K-Means. Ho una funzione entropia nel pacchetto spatialEco che è utile per il rilevamento delle modifiche. Si calcola l'entropia all'interno di una finestra NxN e quindi si ricava delta ad ogni passo temporale. L'entropia negativa rappresenta la perdita e positivo è il guadagno di componenti del paesaggio entro una data grandezza sotto l'entropia massima.
Jeffrey Evans,

Questa è una vecchia domanda e ho scartato l'idea di usare k-mean anni fa. Ma è bello conoscere il pacchetto spaziale Eco per la prossima volta;)
Iris,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.