Использование Time-Weighted Dynamic Time Warpin для построения карты различий между растрами.

Вопросы по статистическому пакету R. Не обязательно гео.
Ответить
_taras_
Активный участник
Сообщения: 221
Зарегистрирован: 28 июл 2018, 08:40
Репутация: 16
Откуда: Киев

Использование Time-Weighted Dynamic Time Warpin для построения карты различий между растрами.

Сообщение _taras_ » 20 дек 2024, 16:50

Доброго времени!
Помогите разобраться как построить именно карту различий между растрами с использованием Time-Weighted Dynamic Time Warpin?

Сами различия между растрами, образующие временной ряд определил с помощю библиотек "twdtw" и dtw.

Код: Выделить всё

 library(terra)
library("twdtw")
library(dtw)

# Установка рабочей директории
Data <- "/home/taras/GRIDS"
setwd(Data)
list.files(pattern="\\.tif$")

# Список файлов
raster_files <- list.files(pattern = "^summer_\\d{4}\\.tif$", full.names = TRUE)

# Загрузка растров
time_series <- rast(raster_files)

# Извлечение годов из имен файлов
years <- as.numeric(gsub("summer_(\\d{4})\\.tif", "\\1", basename(raster_files)))

# Присвоение временных меток
time(time_series) <- as.Date(paste0(years, "-06-15"))  # 15 июня как пример

# Проверка результата
print(time(time_series))

# Эталонная временная серия (в данном случае синусоида как пример)
ref_times <- seq(as.Date("1984-06-15"), as.Date("2023-06-15"), by = "year")
ref_values <- sin(2 * pi * seq_along(ref_times) / 6)  # Синусоида
reference <- data.frame(date = ref_times, value = ref_values)

# Пример динамического выравнивания для каждого растрового временного ряда
distances <- numeric(length(raster_files))
for (i in 1:length(raster_files)) {
  # Извлечение данных для каждого растрового временного ряда
  raster_values <- values(time_series[[i]])
  
  # Преобразование векторных значений растров в одномерный вектор
  raster_values <- as.vector(raster_values)
  
  # Убедитесь, что длина временных рядов одинаковая, если необходимо, интерполируйте
  if(length(raster_values) != length(ref_values)) {
    # Пример: интерполяция значений растров на длину эталона
    raster_values <- approx(raster_values, n = length(ref_values))$y
  }
  
  # Вычисление DTW расстояния
  alignment <- dtw(raster_values, ref_values, keep = TRUE)
  
  # Сохранение расстояния DTW для каждого растрового временного ряда
  distances[i] <- alignment$distance
}

# Вывод результатов
data.frame(year = years, dtw_distance = distances)

Линейный график DTW расстояния по годам:
library(ggplot2)

# Создание data frame
results <- data.frame(year = years, dtw_distance = distances)

# Построение линейного графика
ggplot(results, aes(x = year, y = dtw_distance)) +
  geom_line(color = "blue") +
  geom_point(color = "red") +
  labs(title = "DTW Distance Over Years",
       x = "Year",
       y = "DTW Distance") +
  theme_minimal()
Гистограмма распределения DTW расстояний: 
# Гистограмма распределения DTW расстояний
ggplot(results, aes(x = dtw_distance)) +
  geom_histogram(binwidth = 0.1, fill = "lightblue", color = "black") +
  labs(title = "Distribution of DTW Distances",
       x = "DTW Distance",
       y = "Frequency") +
  theme_minimal()

Попытка в лоб найти различия приводят к результату на рисунке

Код: Выделить всё

# Загрузка растров для 1984 и 2023 года
raster_1984 <- rast("summer_1984.tif")
raster_2023 <- rast("summer_2023.tif")

# Определение размеров блока (например, 100x100 пикселей)
block_size <- 100

# Получаем размеры растров
ncols <- ncol(raster_1984)
nrows <- nrow(raster_1984)

# Создание пустого объекта для хранения результата
difference_raster <- raster_1984
values(difference_raster) <- NA  # Инициализация пустыми значениями

# Обрабатываем блоки по частям
for (i in seq(1, nrows, block_size)) {
  for (j in seq(1, ncols, block_size)) {
    
    # Ограничиваем индексы на случай, если блок выходит за пределы
    row_idx <- i:min(i + block_size - 1, nrows)
    col_idx <- j:min(j + block_size - 1, ncols)
    
    # Создаем координаты для текущего блока
    grid <- expand.grid(row = row_idx, col = col_idx)
    
    # Извлекаем значения для текущего блока
    block_1984 <- extract(raster_1984, grid)
    block_2023 <- extract(raster_2023, grid)
    
    # Диагностика: выводим значения для блока
    print(paste("Block 1984:", toString(block_1984)))
    print(paste("Block 2023:", toString(block_2023)))
    
    # Убираем NA значения
    valid_indices <- !is.na(block_1984) & !is.na(block_2023)
    block_1984 <- block_1984[valid_indices]
    block_2023 <- block_2023[valid_indices]
    
    # Диагностика: выводим очищенные блоки
    print(paste("Valid Block 1984:", toString(block_1984)))
    print(paste("Valid Block 2023:", toString(block_2023)))
    
    # Применяем DTW для текущего блока
    if (length(block_1984) > 0 && length(block_2023) > 0) {
      dtw_result <- dtw(block_1984, block_2023)
      
      # Диагностика: выводим результат DTW
      print(paste("DTW Distance:", dtw_result$distance))
      
      # Сохраняем результат в соответствующем месте
      diff_results[row_idx, col_idx] <- dtw_result$distance
    }
  }
}

# Преобразуем результаты в новый растр
raster_diff <- raster_1984
values(raster_diff) <- diff_results

# Сохранение нового растра
writeRaster(raster_diff, "difference_raster.tif", overwrite=TRUE)

# Визуализация разницы
plot(difference_raster, main = "DTW Difference between 2023 and 1984 (Block-wise)", col = terrain.colors(100)) 
Вложения
Rplot01.png
Rplot01.png (50.66 КБ) 1570 просмотров

gamm
Гуру
Сообщения: 4140
Зарегистрирован: 15 окт 2010, 08:33
Репутация: 1100
Ваше звание: программист
Откуда: Казань

Re: Использование Time-Weighted Dynamic Time Warpin для построения карты различий между растрами.

Сообщение gamm » 20 дек 2024, 19:59

у вас в raster_values лежат в один столбец все пиксели одного растра (миллионы штук), которые затем натягиваются на короткий временной ряд (десятки штук). Поскольку это полная бессмыслица, то дальше смотреть не стал.

попробуйте изложить словами, чего хотите сделать, безотносительно к инструменту. Описание задачи, лучше с картинками (рисовать можно от руки, важно смысл прояснить, и приложить фото). Может и самому понятнее будет.

_taras_
Активный участник
Сообщения: 221
Зарегистрирован: 28 июл 2018, 08:40
Репутация: 16
Откуда: Киев

Re: Использование Time-Weighted Dynamic Time Warpin для построения карты различий между растрами.

Сообщение _taras_ » 23 дек 2024, 17:48

Попробую описать, как Вы советуете.
Имеется природоохранная территория, для которой надобно оценить динамику развития растительности, её тренд, выявить участки с максимальными изменениями. Для нее имеется практически непрерывный набор снимков за 40 лет и рассчитаны различные индексы. На примере 1 индекса (NDVI) провел анализ временных изменений.
Группировку годов по степени изменчивости значений индекса по каждому сезону (дальше в качестве примера использую данные за лето). определял с помощью кластерного анализа. Для этого создавались растры среднего значения за 3 месяца м мз них делалась выборка. Кластеризацию временных рядов делал библиотекой «dtwclust» и провел оценку «адекватности» полученного результата. Оказалось, что года очень схожи, за исключением отдельных лет, когда на развитие растительности наложилось совокупность неблагоприятных факторов.

Теперь касательно самого вопроса.
На территории имеются участки, которые сильно изменились за прошедшее время — появились постройки, заросла часть водоемов. Я хотел построить карту различий между растрами с разбив каждый растр на несколько групп и затем сравнив их. Но я выбрал неверный инструмент.
Сейчас к.м.к. есть два варианта.
Первый — найти разницу между начальным годом и через, допустим, каждые 5 лет. Разбить полученный растр на ряд групп и дать их описание.
Второй — попробовать определить общий тренд изменений индекса, так же через 5 лет.

Буду рад любым дополнениям и замечаниям.

gamm
Гуру
Сообщения: 4140
Зарегистрирован: 15 окт 2010, 08:33
Репутация: 1100
Ваше звание: программист
Откуда: Казань

Re: Использование Time-Weighted Dynamic Time Warpin для построения карты различий между растрами.

Сообщение gamm » 23 дек 2024, 21:42

_taras_ писал(а):
23 дек 2024, 17:48
Имеется природоохранная территория, для которой надобно оценить динамику развития растительности, её тренд, выявить участки с максимальными изменениями. Для нее имеется практически непрерывный набор снимков за 40 лет и рассчитаны различные индексы.
сколько дат за год (шаг по времени), совпадают ли даты у разных годов, и можно ли игнорировать фенологию (ранняя весна/поздняя весна и пр.)
На примере 1 индекса (NDVI) провел анализ временных изменений.
Группировку годов по степени изменчивости значений индекса по каждому сезону (дальше в качестве примера использую данные за лето). определял с помощью кластерного анализа. Для этого создавались растры среднего значения за 3 месяца м мз них делалась выборка. Кластеризацию временных рядов делал библиотекой «dtwclust» и провел оценку «адекватности» полученного результата.
что такое здесь "временной ряд", к какой пространственной единице относится, шаг и разрешение по времени
Я хотел построить карту различий между растрами с разбив каждый растр на несколько групп и затем сравнив их.
растр один или временной ряд растров? что такое "разбить растр на группы", это пространственные группы, объединенные по какому признаку?

Раз это природоохранная территория, то скорее всего состояние климаксное, т.е. стабильное + локальные нарушения, как естественные, так и антрпопогенные, но их относительно немного по территории. Если считать, что при усреднении за квартал мы фенологию нивелируем, то напрашивается разбиение территории на однородные зоны (например ландшафтные, на соответствующем уровне). Тогда в зоне изменение индекса должно быть одинаковым, и можно просто построить регрессию значений индекса в зоне от текущего года на следующий, и получить из нее вероятность (локальных) отклонений от общей тенденции (по разности прогноза и факта).
Если внутри года значний индекса много, то можно пробовать кластеризовать временные ряды попиксельно, опять по зонам, компенсируя разную фенологию между годами, но которую считаем одинаковой в зоне - усредняем ряды по зоне за каждый из двух лет (для скорости), совмещаем усредненные, распространяем совмещение на все ряды зоны, и клстеризуем их обычными методами как многомерные вектора.

P.S. Можно еще пакет ptw посмотреть, он тоже совмещает временные ряды, но в рамках параметрической модели, вроде он должен быстрее работать.

_taras_
Активный участник
Сообщения: 221
Зарегистрирован: 28 июл 2018, 08:40
Репутация: 16
Откуда: Киев

Re: Использование Time-Weighted Dynamic Time Warpin для построения карты различий между растрами.

Сообщение _taras_ » 24 дек 2024, 01:47

gamm писал(а):
23 дек 2024, 21:42
сколько дат за год (шаг по времени), совпадают ли даты у разных годов, и можно ли игнорировать фенологию (ранняя весна/поздняя весна и пр.)
Снимки имеют периодичность 1 раз в месяц. Снимки старался брать за одну и туже дату (плюс-минус неделя). Всего 425 (88% от общего кол-ва) растров с мая 1984 по декабрь 2022 года. 54 месяца - сплошная облачность или отсутствуют. Это как правило зима и ноябрь. Весна тоже характеризовалась сильной облачностью, но интересующее меня участки страдали слабо. Лето и начало осени почти без туч. Развитие растительности начинается в середине марта начале апреля и заканчивается в конце октября, начале ноября.
что такое здесь "временной ряд", к какой пространственной единице относится, шаг и разрешение по времени
Вопрос не очень понял... Снимки Landsat 4-9, WGS84 zone=36N, разрешение по времени - 1 месяц. На их основе делал расчеты индексов.
растр один или временной ряд растров? что такое "разбить растр на группы", это пространственные группы, объединенные по какому признаку?
Надобно получить "срез" состояния растительности на основе индекса за определенный промежуток времени. "разбить растр на группы" - имелась ввиду пространственная кластеризация, объединенных по степени изменения значений или тренда ( тут два варианта).
Раз это природоохранная территория, то скорее всего состояние климаксное, т.е. стабильное + локальные нарушения, как естественные, так и антрпопогенные, но их относительно немного по территории.
Не совсем. Это водно-болотная и плавневая растительность и ее развитие целиком зависит от доступной воды. Пока стороны более-мене соблюдают договренности по поуску (например летом м около 200 м^3 cek), то воды хватает и людишкам и растительности. В этом же году был массовый сброс воды весной и водохранилища пока не вышли на прежний уровень.
Если считать, что при усреднении за квартал мы фенологию нивелируем, то напрашивается разбиение территории на однородные зоны (например ландшафтные, на соответствующем уровне). Тогда в зоне изменение индекса должно быть одинаковым, и можно просто построить регрессию значений индекса в зоне от текущего года на следующий, и получить из нее вероятность (локальных) отклонений от общей тенденции (по разности прогноза и факта).
Да, я так и планирую поступить. Т.е. выделить временной тренд по сезонам и затем использовать ландшафтные метрики.

gamm
Гуру
Сообщения: 4140
Зарегистрирован: 15 окт 2010, 08:33
Репутация: 1100
Ваше звание: программист
Откуда: Казань

Re: Использование Time-Weighted Dynamic Time Warpin для построения карты различий между растрами.

Сообщение gamm » 24 дек 2024, 09:09

_taras_ писал(а):
24 дек 2024, 01:47
Вопрос не очень понял... Снимки Landsat 4-9, WGS84 zone=36N, разрешение по времени - 1 месяц. На их основе делал расчеты индексов.
вопрос вот про это:
определял с помощью кластерного анализа. Для этого создавались растры среднего значения за 3 месяца м мз них делалась выборка. Кластеризацию временных рядов делал библиотекой «dtwclust» и провел оценку «адекватности» полученного результата.
Т.е. получили 4 квартальных средних для каждого пикселя каждого года. Какие временные ряды кластеризовались, попиксельные годовые, по 4 числа за год на пиксель?
растр один или временной ряд растров? что такое "разбить растр на группы", это пространственные группы, объединенные по какому признаку?
Надобно получить "срез" состояния растительности на основе индекса за определенный промежуток времени. "разбить растр на группы" - имелась ввиду пространственная кластеризация, объединенных по степени изменения значений или тренда ( тут два варианта).
тот же вопрос - что кластеризуется, пиксельные ряды из 4 чисел на год? Или имеется в виду объединение пикселей с примерно одинаковым значением в данном году (средним за год)? Про какой тренд идет речь, 1 летнее значение на пиксель, тренд по годам? или среднее за год, тренд по годам?
Это водно-болотная и плавневая растительность и ее развитие целиком зависит от доступной воды.
территория, видимо, небольшая, уровень воды можно считать одинаковым? тогда регрессия с года на год (по зонам) должна нивелировать влияние уровня, и отклонения от нее покажут изменения собственно растительности. Но это не точно :D

P.S. Для коротких усредненных по кварталам рядов смысла использовать dtw нет никакого, фенология нивелирована, и ряды слишком короткие.

_taras_
Активный участник
Сообщения: 221
Зарегистрирован: 28 июл 2018, 08:40
Репутация: 16
Откуда: Киев

Re: Использование Time-Weighted Dynamic Time Warpin для построения карты различий между растрами.

Сообщение _taras_ » 25 дек 2024, 15:21

Вероятно в моей писанине возникла неопределенность "Кто на ком стоял? (С)"
Для выделения пространственных и временных изменений пробую применить два похода.
Первый - кластеризация данных вдернутых из растров и второй - оценка временных изменений непосредственно по растрам.
gamm писал(а):
24 дек 2024, 09:09
Т.е. получили 4 квартальных средних для каждого пикселя каждого года. Какие временные ряды кластеризовались, попиксельные годовые, по 4 числа за год на пиксель?
В каждом году для каждого сезона сделал растр со средними значениями каждого пикселя. Получаются временные наборы весна, лето (например summary_1984 .... summary_2023), осень. Итого каждая серия имеет по 40 шт растров. Потом из этого набора формировал таблицу для кластеризации. (Есть карта ESA WorldCover, что позволяет выбрать необходимый тип растительности.). Делал так:

Код: Выделить всё

library(parallel)
library(tidyr)
library(dtwclust)
library(dplyr)
library(ggplot2)
library(psych)
library(proxy)
library(fpc)
library(cluster)

# Загрузка данных
df <- read.table("/home/taras/DWT_sammer.csv", sep = ",", dec = ".", header = TRUE, stringsAsFactors = FALSE)
ncol(df)
df <-subset(df, cover_2 == 90, select=c(1:39))
df <- na.omit(df) %>%
  filter_all(all_vars(. >= -1 & . <= 1))
  
set.seed(123) # Для воспроизводимости результатов
df <- df[sample(nrow(df), 100), ]
# Преобразование данных из wide в long формат
df_long <- df %>%
  pivot_longer(cols = everything(), names_to = "key", values_to = "value") %>%
  mutate(key = as.numeric(stringr::str_remove(key, "X_")))
# Создание колонки для временной метки
df_long$time <- rep(1:100, each = ncol(df))
# Визуализация данных
df_long %>%
  ggplot(aes(x = time, y = value, color = key)) +
  geom_line(size = 0.2) +
  ggtitle("Control chart sequences") + 
  facet_wrap(~ key, nrow = 2)
# Преобразование данных в список
df_list <- as.list(utils::unstack(df_long, value ~ key))
# Нормализация данных
df_list_z <- dtwclust::zscore(df_list)
# Иерархическая кластеризация с использованием DTW
num_cores <- detectCores() - 1
# Кластеризация в параллельном режиме
cluster_dtw_h <- mclapply(2:35, function(k) {
  tsclust(df_list_z, type = "hierarchical", k = k, distance = "dtw", 
          control = hierarchical_control(method = "complete"), 
          seed = 390, args = tsclust_args(dist = list(window.size = 5L)))
}, mc.cores = num_cores)
# Анализ результатов для k = 4
plot(cluster_dtw_h[[3]]) # k = 4
plot(cluster_dtw_h[[3]], type = "sc") # Series and prototypes
(Про методы выбора оптимального k и проверки "правильности" полученной кластеризации в курсе)
территория, видимо, небольшая, уровень воды можно считать одинаковым? тогда регрессия с года на год (по зонам) должна нивелировать влияние уровня, и отклонения от нее покажут изменения собственно растительности. Но это не точно :D
Позвольте, я детально через день-два отвечу т.к. заседания потоком, а после них уже никакой. Территория имеет уклон в сторону моря (карта высот есть, но как ее использовать не знаю).
Для коротких усредненных по кварталам рядов смысла использовать dtw нет никакого, фенология нивелирована, и ряды слишком короткие.
Фенологию будет рассматриваться следующим этапом (уже определены ключевые месяца). Сейчас хочу обкатать единую методику. Насчет коротких рядов... Работаем с тем, что есть.

gamm
Гуру
Сообщения: 4140
Зарегистрирован: 15 окт 2010, 08:33
Репутация: 1100
Ваше звание: программист
Откуда: Казань

Re: Использование Time-Weighted Dynamic Time Warpin для построения карты различий между растрами.

Сообщение gamm » 25 дек 2024, 21:00

стало немного понятнее. Т.е. есть 4 серии временных рядов растров, весенние, летние, осенние, зимние.
В каждом растре много пикселей (сколько?), получается много столбцов-временных рядов (сколько? к чему относятся - к каким пространственным единицам?)
Есть какая-то таблица DWT_sammer.csv, в которой непонятно что (видимо, какие-то летние ряды - сколько их, к чему относятся?)
И главный вопрос - какой прок от этой кластеризации с точки зрения решаемой задачи? Вроде по постановке нужно искать пиксели и момент времени (где и когда случилось нарушение), т.е. когда в этом пикселе временной ряд пошел не туда, куда идут соседи (где нет нарушений). Или предполагается смотреть, как на классы разбивается однородный объект, типа ландшафтного выдела? и что это даст?
P.S. Поскольку со временем тоже напряг, автоматически включился "телеграфный" режим "рабочего совещания", бывает 🤔

gamm
Гуру
Сообщения: 4140
Зарегистрирован: 15 окт 2010, 08:33
Репутация: 1100
Ваше звание: программист
Откуда: Казань

Re: Использование Time-Weighted Dynamic Time Warpin для построения карты различий между растрами.

Сообщение gamm » 26 дек 2024, 18:45

кстати, раз уж все равно R. Лучше вместо экзерсизов с кластеризацией соорудить нормальную модель, с автокорреляцией, случайными эффектами, и прочими прибамбасами, типа GLS/GLMM/GAMM. Только нужно нормальную постановку задачи, не вербальную, а математическую.

Ответить

Вернуться в «R»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 2 гостя