Dane czasoprzestrzenne w R. Część 1

Author

Anna Dmowska

library(spacetime)
library(gstat)
library(tidyverse)
library(sf)

1 Dane czasoprzestrzenne

Dane czasoprzestrzenne (ang. spatio-temporal data) to obserwacje, dla których zarejestrowano jednocześnie lokalizację przestrzenną , czas obserwacji oraz atrybuty (wartości analizowanej cechy) zmierzone w tym konkretnym miejscu i momencie czasu.

Struktura danych czasoprzestrzennych obejmuje 3 wymiary:

  1. Przestrzeń (Space): Informacja o lokalizacji i układzie współrzędnych (CRS), np. klasa SpatialPoints

  2. Czas (Time): Indeks czasowy określający datę lub moment pomiaru, często reprezentowany jako klasa POSIXct lub xts

  3. Atrybuty (Attributes): Mierzone parametry zjawiska, np. stężenie pyłu PM10 czy prędkość wiatru.

2 Dane czasoprzestrzenne w R

W środowisku R dane czasoprzestrzenne są reprezentowane głównie poprzez system klas zdefiniowany w pakiecie spacetime, który integruje dane przestrzenne z pakietu sp oraz szeregi czasowe z pakietu xts. Klasy te pozwalają na jednoczesne przechowywanie geometrii (np. punktów, poligonów), indeksu czasu oraz mierzonych atrybutów. Pakiet spacetime dostarcza kilka klas obiektów.

Klasa Opis Zastosowanie
STFDF (Full) Każda lokalizacja ma przypisany pomiar w każdym punkcie czasu Stacje meteorologiczne, dane satelitarne
STSDF (Sparse) Tylko niektóre kombinacje miejsca i czasu mają przypisane dane Monitoring mobilny (czujniki nie mają stałej lokalizacji)
STTDF (Trajectories) Trajektorie: dane o ruchu, gdzie lokalizacja \(s\) jest bezpośrednią funkcją czasu \(t\). Ślady GPS zwierząt, loty samolotów.

W geostatystyce będziemy korzystać z klasy STFDF (ang. Space-Time Full-grid Data Frame). Klasa STF przechowuje wyłącznie geometrię, a klasa STFDF przechowuje także atrybuty pomiarów (dane).

2.1 Struktura obiektu STFDF

Klasa STFDF (ang. Space-Time Full-grid Data Frame) reprezentuje pełną siatkę czasoprzestrzenną, gdzie dla każdej lokalizacji przestrzennej przypisany jest pomiar w każdym punkcie czasu.

Obiekt STFDF składa się z czterech głównych pól (slotów):

  • @sp: Zawiera obiekt klasy Spatial (z pakietu sp), definiujący geometrię (np. SpatialPoints dla stacji pomiarowych lub SpatialPolygons dla jednostek administracyjnych) oraz układ współrzędnych (CRS).

  • @time: Przechowuje indeks czasowy w formacie klasy xts, co pozwala na elastyczne operacje na szeregach czasowych

  • @data: Ramka danych (data.frame) zawierająca atrybuty (zmienne mierzone) przypisane do konkretnych punktów w czasie i przestrzeni

  • @endTime: Wektor klasy POSIXct określający punkty końcowe interwałów czasowych, co pozwala na rozróżnienie między pomiarami natychmiastowymi a danymi zagregowanymi w czasie

2.2 Zrozumienie struktury obiektu STFDF

2.3 Tworzenie obiektu STFDF

Komponent przestrzenny

Utworzymy obiekt przestrzenny klasy SpatialPoints składający się z 3 punktów.

# Wczytanie bibliotek do operacji przestrzennych i czasoprzestrzennych
library(sp)
library(spacetime)
set.seed(123)

# --- KOMPONENT PRZESTRZENNY ---
# Tworzenie macierzy współrzędnych (3 punkty: [0,0], [0,1], [1,1])
sp = cbind(x = c(0,0,1), y = c(0,1,1))
# Przypisanie unikalnych nazw dla wierszy (lokalizacji)
row.names(sp) = paste("P", 1:nrow(sp), sep="")
# Konwersja zwykłej macierzy na obiekt klasy SpatialPoints
sp = SpatialPoints(sp)

sp
SpatialPoints:
   x y
P1 0 0
P2 0 1
P3 1 1
Coordinate Reference System (CRS) arguments: NA 
# Szybki podgląd rozmieszczenia punktów w przestrzeni
# Rysowanie punktów
plot(sp, pch = 19, cex = 2, col = "royalblue", main = "Lokalizacje punktów")
# Dodawanie etykiet
# coordinates(sp) - wyciąga macierz współrzędnych x i y
# labels - bierze nazwy wierszy, które wcześniej nadaliśmy (point1, point2, itd.)
# pos = 3 - umieszcza tekst NAD punktem (1=dół, 2=lewo, 3=góra, 4=prawo)
# offset = 0.5 - dodaje lekki odstęp między punktem a tekstem
text(coordinates(sp), labels = row.names(sp), pos = 2, cex = 1.1, col = "black")

Komponent przestrzenny

Komponent czasowy składa się z 4 okresów w czasie - od godziny 10 do 13, co godzinę.

# --- KOMPONENT CZASOWY ---
# Utworzenie wektora 4 punktów czasowych (co godzinę, od 10:00 do 13:00)
# format POSIXct jest wymagany przez pakiet spacetime
czas = as.POSIXct("2025-08-05", tz = "GMT") + 3600*(10:13)
czas
[1] "2025-08-05 10:00:00 GMT" "2025-08-05 11:00:00 GMT"
[3] "2025-08-05 12:00:00 GMT" "2025-08-05 13:00:00 GMT"

Komponent danych (atrybuty)

W punktach P1-P3 o godzinie 10, 11, 12, 13 zmierzono temperaturę powietrza. Dane te są przechowywane w obiekcie temp. Wiersze odpowiadają kolejnym lokalizacją, a kolumny kolejnym momentom w czasie.

temp = data.frame(T1 = c(9.44, 19.8, 31.6),
                  T2 = c(10.1, 20.1, 31.7),
                  T3 = c(10.5, 18.17, 29.3),
                  T4 = c(9.55, 21.20, 30.40))
rownames(temp) = c("P1", "P2", "P3")
temp
      T1   T2    T3    T4
P1  9.44 10.1 10.50  9.55
P2 19.80 20.1 18.17 21.20
P3 31.60 31.7 29.30 30.40

Przekształcimy dane na wektor. Należy zwrócić uwagę na kolejność punktów wartości. Najpierw występują wartości dla czasu T1 dla P1, P2, P3, następnie dla czasu T2 dla P1, P2, P3, itd.

wektor = unlist(as.vector(temp))
wektor
  T11   T12   T13   T21   T22   T23   T31   T32   T33   T41   T42   T43 
 9.44 19.80 31.60 10.10 20.10 31.70 10.50 18.17 29.30  9.55 21.20 30.40 

Tworzymy komponent danych. Liczba wierszy = Liczba punktów * Liczba okresów czasu, czyli w przykładzie 3(P) * 4(T) = 12. Wartości muszą być najpierw posortowane wg czasu (T1:T4), a dla każdego momentu czasu wg obiektów przestrzennych (P1:P3). W poniższej tabeli ID T11 oznacza T1

dane <- data.frame(
  Temp = wektor,
  # T zmienia się co 1 (T1, T2, T3, T4, T1...) 
  ID    = paste0(rep(c("T1", "T2", "T3", "T4"), each = 3),rep(c("P1", "P2", "P3"), times = 4))
  # P powinno stać w miejscu przez 4 wiersze (P1, P1, P1, P1, P2...)
)

rownames(dane) = dane$ID
dane
      Temp   ID
T1P1  9.44 T1P1
T1P2 19.80 T1P2
T1P3 31.60 T1P3
T2P1 10.10 T2P1
T2P2 20.10 T2P2
T2P3 31.70 T2P3
T3P1 10.50 T3P1
T3P2 18.17 T3P2
T3P3 29.30 T3P3
T4P1  9.55 T4P1
T4P2 21.20 T4P2
T4P3 30.40 T4P3

2.3.1 Konstrukcja obiektu STFDF

W obiekcie STFDF każdy punkt ma dane w każdym momencie czasu. Do konstrukcji obiektu możemy użyć funkcji STFDF() lub funkcji stConstruct()

# Tworzenie obiektu, gdzie czas traktowany jest jako momenty (punkty w czasie)
stfdf = STFDF(sp = sp, time = czas, data = dane)

# Sprawdzenie struktury gotowego obiektu
print(stfdf)
An object of class "STFDF"
Slot "data":
      Temp   ID
T1P1  9.44 T1P1
T1P2 19.80 T1P2
T1P3 31.60 T1P3
T2P1 10.10 T2P1
T2P2 20.10 T2P2
T2P3 31.70 T2P3
T3P1 10.50 T3P1
T3P2 18.17 T3P2
T3P3 29.30 T3P3
T4P1  9.55 T4P1
T4P2 21.20 T4P2
T4P3 30.40 T4P3

Slot "sp":
SpatialPoints:
   x y
P1 0 0
P2 0 1
P3 1 1
Coordinate Reference System (CRS) arguments: NA 

Slot "time":
                    timeIndex
2025-08-05 10:00:00         1
2025-08-05 11:00:00         2
2025-08-05 12:00:00         3
2025-08-05 13:00:00         4

Slot "endTime":
[1] "2025-08-05 11:00:00 GMT" "2025-08-05 12:00:00 GMT"
[3] "2025-08-05 13:00:00 GMT" "2025-08-05 14:00:00 GMT"

2.3.2 Struktura obiektu STFDF

dim(stfdf)
    space      time variables 
        3         4         2 
str(stfdf)
Formal class 'STFDF' [package "spacetime"] with 4 slots
  ..@ data   :'data.frame': 12 obs. of  2 variables:
  .. ..$ Temp: num [1:12] 9.44 19.8 31.6 10.1 20.1 ...
  .. ..$ ID  : chr [1:12] "T1P1" "T1P2" "T1P3" "T2P1" ...
  ..@ sp     :Formal class 'SpatialPoints' [package "sp"] with 3 slots
  .. .. ..@ coords     : num [1:3, 1:2] 0 0 1 0 1 1
  .. .. .. ..- attr(*, "dimnames")=List of 2
  .. .. .. .. ..$ : chr [1:3] "P1" "P2" "P3"
  .. .. .. .. ..$ : chr [1:2] "x" "y"
  .. .. ..@ bbox       : num [1:2, 1:2] 0 0 1 1
  .. .. .. ..- attr(*, "dimnames")=List of 2
  .. .. .. .. ..$ : chr [1:2] "x" "y"
  .. .. .. .. ..$ : chr [1:2] "min" "max"
  .. .. ..@ proj4string:Formal class 'CRS' [package "sp"] with 1 slot
  .. .. .. .. ..@ projargs: chr NA
  ..@ time   :An xts object on 2025-08-05 10:00:00 / 2025-08-05 13:00:00 containing: 
  Data:    integer [4, 1]
  Columns: timeIndex
  Index:   POSIXct,POSIXt [4] (TZ: "GMT")
  ..@ endTime: POSIXct[1:4], format: "2025-08-05 11:00:00" "2025-08-05 12:00:00" ...

Plik składa się z 4 slotów: data, sp, time oraz endTime. Aby odwołać się do konkretnego slotu używa się znaku @.

  • Slot sp przechowuje obiekty przestrzenne typu SpatialPoints
stfdf@sp
SpatialPoints:
   x y
P1 0 0
P2 0 1
P3 1 1
Coordinate Reference System (CRS) arguments: NA 
plot(stfdf@sp, cex = 3, col = "red", pch = 20)

  • Slot sp przechowuje także informacje o zasięgu danych (bbox) oraz współrzędnych (coords).
stfdf@sp@bbox
  min max
x   0   1
y   0   1
stfdf@sp@coords
   x y
P1 0 0
P2 0 1
P3 1 1
  • Slot time przechowuje informacje o momentach w czasie. W tym przypadku czas został zdefiniowany co godzinę od 10 do 13.00
stfdf@time
                    timeIndex
2025-08-05 10:00:00         1
2025-08-05 11:00:00         2
2025-08-05 12:00:00         3
2025-08-05 13:00:00         4
  • Slot data przechowuje informację o atrybutach
stfdf@data
      Temp   ID
T1P1  9.44 T1P1
T1P2 19.80 T1P2
T1P3 31.60 T1P3
T2P1 10.10 T2P1
T2P2 20.10 T2P2
T2P3 31.70 T2P3
T3P1 10.50 T3P1
T3P2 18.17 T3P2
T3P3 29.30 T3P3
T4P1  9.55 T4P1
T4P2 21.20 T4P2
T4P3 30.40 T4P3
stfdf@data$Temp
 [1]  9.44 19.80 31.60 10.10 20.10 31.70 10.50 18.17 29.30  9.55 21.20 30.40

2.4 Selekcja

Obiekt klasy STFDF są obiektami trójwymiarowymi, których selekcję można wykonywać za pomocą [].

obj[space, time, attr, drop = TRUE]

  • Wybór danych dla pierwszej lokalizacji P1
stfdf[1,]
                     Temp   ID timeIndex
2025-08-05 10:00:00  9.44 T1P1         1
2025-08-05 11:00:00 10.10 T2P1         2
2025-08-05 12:00:00 10.50 T3P1         3
2025-08-05 13:00:00  9.55 T4P1         4
dim(stfdf[1,])
[1] 4 3
  • Wybór danych dla momentu w czasie 2 i 3 (godzina 11 i 12)
stfdf[, 2:3]
An object of class "STFDF"
Slot "data":
   Temp   ID
1 10.10 T2P1
2 20.10 T2P2
3 31.70 T2P3
4 10.50 T3P1
5 18.17 T3P2
6 29.30 T3P3

Slot "sp":
SpatialPoints:
   x y
P1 0 0
P2 0 1
P3 1 1
Coordinate Reference System (CRS) arguments: NA 

Slot "time":
                    timeIndex
2025-08-05 11:00:00         2
2025-08-05 12:00:00         3

Slot "endTime":
[1] "2025-08-05 12:00:00 GMT" "2025-08-05 13:00:00 GMT"
dim(stfdf[, 2:3])
    space      time variables 
        3         2         2 

Po selekcji nadal mapy 3 punkty, 2 zmienne ale dane zostały ograniczone tylko do godziny 11.00 i 12.00.

stfdf[, , "Temp"]
An object of class "STFDF"
Slot "data":
    Temp
1   9.44
2  19.80
3  31.60
4  10.10
5  20.10
6  31.70
7  10.50
8  18.17
9  29.30
10  9.55
11 21.20
12 30.40

Slot "sp":
SpatialPoints:
   x y
P1 0 0
P2 0 1
P3 1 1
Coordinate Reference System (CRS) arguments: NA 

Slot "time":
                    timeIndex
2025-08-05 10:00:00         1
2025-08-05 11:00:00         2
2025-08-05 12:00:00         3
2025-08-05 13:00:00         4

Slot "endTime":
[1] "2025-08-05 11:00:00 GMT" "2025-08-05 12:00:00 GMT"
[3] "2025-08-05 13:00:00 GMT" "2025-08-05 14:00:00 GMT"
dim(stfdf[, , "Temp"])
    space      time variables 
        3         4         1 
  • Wybór zmiennej Temp dla punktu P1 dla godzin 11 i 12.
stfdf[1, 2:3 , "Temp"]
                    Temp timeIndex
2025-08-05 11:00:00 10.1         2
2025-08-05 12:00:00 10.5         3

Wybierz dane dla godziny 13, dla punktu P3. Ile wynosiła temperatura w punkcie P3 o godzinie 13.00?

3 Wizualizacja

Do wizualizacji danych wykorzystuje się funkcję stplot(). Przy ustawieniach domyślnych zostaną wyświetlone panele dla każdego momentu w czasie pokazujące rozkład wartości zmierzonych w lokalizacjach.

stplot(stfdf)

3.1 Diagram Hovmollera,

Opcja mode = "xt wyświetla tzw. diagram Hovmollera, gdzie na osi X są lokalizacje, a na osi Y czas, kolor odpowiada wartością wyświetlanej zmiennej. Diagram ten pozwala m.in na identyfikację braków danych oraz trendów w przestrzeni/czasie.

stplot(stfdf, mode = "xt", xlab = "Lokalizacja", ylab = "Czas")