Неконтролируемая классификация с kmeans в R

10

У меня есть временной ряд спутниковых изображений (5 полос), и я хочу классифицировать их по kmeans в R. Мой скрипт работает нормально (просматривайте мои изображения, конвертируйте изображения в 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 в первом столбце указывается номер зоны, а во втором - метка класса.

nmatton
источник
Я боялся, что это невозможно. Спасибо за код для большинства голосов!
Iris
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. Я использую метод Клары 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, и что программное обеспечение для обработки изображений или ГИС может быть более подходящим. Я знаю, что SAGA и набор инструментов Orfeo являются бесплатными программами, которые имеют кластеризацию k-средних для стеков изображений. Существует даже библиотека RSAGA, которая позволяет вызывать программное обеспечение из R.

Джеффри Эванс
источник
Если все изображения сгруппированы и кластеризованы одновременно, то получается одно кластерное изображение, верно?
Ирис
@ Радужная оболочка, да, именно так работает этот тип кластеризации изображений и следует за реализациями в программном обеспечении дистанционного зондирования. Ярким и актуальным примером будет реализация isocluster в ArcGIS ( desktop.arcgis.com/en/arcmap/10.3/tools/spatial-analyst-toolbox/… )
Джеффри Эванс,
Тогда этот ответ совсем не поможет. Моя проблема заключалась в том, что я пытался сделать обнаружение изменений во времени на основе нескольких неконтролируемых классификаций изображений, но я мог сравнить разные результаты, потому что классы были назначены по-разному.
Ирис
Неконтролируемая классификация не является жизнеспособным способом обнаружения изменений. Даже небольшое изменение в данном изображении может привести к тому, что пиксели будут отнесены к другому классу. Это будет иметь место, даже если вы предоставили кластерные центры для K-Means. У меня есть функция энтропии в пакете SpaceEco, которая полезна для обнаружения изменений. Вы вычисляете энтропию в окне NxN и затем вычисляете дельту на каждом временном шаге. Отрицательная энтропия представляет собой потерю, а положительная величина - это увеличение компонентов ландшафта в пределах заданной величины при максимальной энтропии.
Джеффри Эванс
Это старый вопрос, и я давно отбросил идею использования k-средних. Но приятно знать, что в следующий раз вы получили пакет SpaceEco;)
Iris