Непідконтрольна класифікація з kmeans в R


10

У мене є часовий ряд супутникових зображень (5 діапазонів) і хочу класифікувати їх по kmeans у Р. Мій сценарій працює чудово (перебирайте зображення, конвертуйте зображення у data.frame, кластеризуйте їх та перетворюйте їх назад у растровий):

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)
}

Моя проблема полягає в тому, що я не можу порівнювати результати класифікації один з одним, оскільки асигнанти кластера відрізняються від зображення до зображення. Наприклад, "вода" є в першому кластері зображень № 1, в наступному 2 і в третьому 10, що робить неможливим порівняння результатів води між датами.

Як я можу виправити призначення кластеру?

Чи можу я вказати фіксовану початкову точку для всього зображення (сподіваючись, що вода завжди виявляється першою і, таким чином, класифікується як 1)?

І якщо так, то як?

Відповіді:


6

Я думаю, ти не можеш ... Спочатку потрібно позначити кожен клас, щоб порівняти їх. Kmean класифікується без нагляду, без будь-якої попередньої інформації, і тому не може визначати будь-які класи.

Якщо у вас є еталонний рівень, ви можете зробити маркування більшістю голосів. Ось досить ефективніший код для голосування більшості, ніж використання пакету "растровий" 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]

де refваш довідковий файл растрового класу, class_fileваш результат kmeans.

zr дає вам у першому колі номер "зони", а в другому - ярлик для класу.


Я боявся, що це неможливо. Дякую за код для голосування більшості!
Ірис

4

Щоб реалізувати кластеризацію на стеку зображень, ви робите це не по діапазону, а по всьому стеку зображень одночасно. В іншому випадку, як вказував @nmatton, статистика не має особливого сенсу.

Однак я не згоден, що це неможливо, просто інтенсивна пам'ять. Що стосується реальних супутникових даних, це буде величезною проблемою, можливо, неможливою для даних з високою роздільною здатністю, але ви можете обробити в пам'яті, примусивши ваші растр (и) до одного об'єкта, який може бути переданий функції кластеризації. Вам потрібно буде відслідковувати значення NA через растри, оскільки вони будуть видалені під час кластеризації, і вам потрібно знати позиції в растрі, щоб ви могли призначити значення кластера правильним осередкам.

Тут ми можемо пройти один підхід. Додаємо необхідні бібліотеки та приклади даних (логотип RGB R, щоб дати нам 3 смуги для роботи).

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

По-перше, ми можемо примусити наш багатодіапазонний растровий стек-об'єкт до data.frame за допомогою getValues. Зауважте, що я додаю значення NA у рядок 1, стовпець 3, щоб я міг проілюструвати, як працювати з відсутністю даних.

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

Тут ми можемо приступити до бізнесу та створити індекс клітинки значень, що не належать до NA, які будуть використані для призначення результатів кластеру.

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

Тепер ми створюємо об’єкт кластера з 3-х діапазонних значень RGB з k = 4. Я використовую метод clara K-Medoids, тому що він хороший з великими даними і кращий при непарних розподілах. Він дуже схожий на K-Means.

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

Для простоти, ми можемо створити порожній растр, витягнувши одну з растрових смуг з нашого оригінального об'єкта растрових стеків та призначивши йому значення NA.

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

Нарешті, використовуючи індекс, ми присвоюємо значення кластеру відповідному комірці в порожньому растрі та намічаємо результати.

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

Для величезних растерів ви можете заглянути в пакет bigmemory, який записує матриці на диск і працює на блоки, і є k-засоби, що доступні. Також майте на увазі, що це не саме те, для чого було розроблено R, і що обробка зображень чи програмне забезпечення GIS може бути більш підходящим. Я знаю, що SAGA та Orfeo Toolbox - це вільне програмне забезпечення, яке має кластеризацію k-засобів для стеків зображень. Існує навіть бібліотека RSAGA, яка дозволяє викликати програмне забезпечення від Р.


Якщо всі зображення складені та згруповані одночасно, то результат - це одне кластеризоване зображення, правда?
Іріс

@Iris, так, такий спосіб кластеризації зображень працює і слідкує за реалізацією програмного забезпечення дистанційного зондування. Ясним і релевантним прикладом може бути реалізація ізокластерів в ArcGIS ( desktop.arcgis.com/en/arcmap/10.3/tools/spatial-analyst-toolbox/… )
Джеффрі Еванс

Тоді ця відповідь зовсім не допомагає. Моя проблема полягала в тому, що я намагався з часом зробити виявлення змін на основі декількох неперевірених класифікацій зображень, але я міг порівняти різні результати, оскільки класи були призначені по-різному.
Іріс

Непідконтрольна класифікація не є життєздатним способом виявлення змін. Навіть незначні зміни в даному зображенні можуть призвести до присвоєння пікселів іншому класу. Це було б так, навіть якщо ви надали центри кластерів для K-Means. Я маю функцію ентропії в пакеті prostEco, яка корисна для виявлення змін. Ви обчислюєте ентропію у вікні NxN, а потім отримуєте дельту на кожному часовому кроці. Негативна ентропія являє собою втрату, а позитивною - посилення ландшафтних компонентів у заданій величині при максимальній ентропії.
Джефрі Еванс

Це старе питання, і я заперечував ідею використання k-засобів століттями назад. Але приємно знати пакунок просторового Еко для наступного разу;)
Іріс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.