计算不同时间点动物之间的距离
Calculate the distance between animals at different time points
我有三只动物一年的东向和北向 GPS 坐标。我想计算每个时间点每只动物之间的距离。
我不知道该怎么做,我们将不胜感激。
我提供了一个数据示例以备不时之需。
ID GPS.E GPS.S Date Time
1 Animal 1 417547 393907 2017-01-01 06:19
2 Animal 1 417769 395000 2017-01-01 16:34
3 Animal 1 418418 394985 2017-01-02 08:18
4 Animal 1 419448 395405 2017-01-02 15:57
5 Animal 1 418249 396145 2017-01-03 07:24
6 Animal 1 417399 396238 2017-01-03 17:44
7 Animal 1 417320 396119 2017-01-04 06:33
8 Animal 1 417770 396080 2017-01-04 17:01
9 Animal 1 417232 396812 2017-01-05 08:43
10 Animal 1 417716 396745 2017-01-05 16:43
11 Animal 2 416571 396099 2017-01-01 06:24
12 Animal 2 416423 395996 2017-01-01 16:15
13 Animal 2 416184 395916 2017-01-02 08:28
14 Animal 2 416002 395858 2017-01-02 15:34
15 Animal 2 415454 395993 2017-01-03 07:14
16 Animal 2 415450 397175 2017-01-03 17:27
17 Animal 2 415781 396949 2017-01-04 06:12
18 Animal 2 415702 396949 2017-01-04 17:23
19 Animal 2 415017 397185 2017-01-05 08:12
20 Animal 2 414516 396990 2017-01-05 16:18
21 Animal 3 418971 394300 2017-01-01 05:59
22 Animal 3 418275 394558 2017-01-01 16:45
23 Animal 3 419881 394940 2017-01-02 08:20
24 Animal 3 420304 394669 2017-01-02 15:25
25 Animal 3 419585 394825 2017-01-03 07:20
26 Animal 3 421528 396153 2017-01-03 17:03
27 Animal 3 420045 396510 2017-01-04 06:27
28 Animal 3 419636 396349 2017-01-04 17:17
29 Animal 3 419499 396212 2017-01-05 08:22
30 Animal 3 420515 395898 2017-01-05 16:14 ````
The desired output is
ID Distance to Animal 1 Distance to Animal 2 Distance to Animal 3
Animal 1
Animal 1
Animal 1
Animal 1
Animal 1
Animal 1
Animal 1
Animal 1
Animal 1
Animal 1
Animal 2
Animal 2
Animal 2
Animal 2
etc.
看起来像一个简单的问题,但出奇地难以解决(至少对我而言)..
请亲手检查一些答案,以确保我正确理解坐标。距离是(应该是)米..
library( data.table )
library( sf )
library( geosphere )
library( tidyverse )
#sample data
DT <- data.table::fread("rowid ID GPS.E GPS.S Date Time
1 Animal1 417547 393907 2017-01-01 06:19
2 Animal1 417769 395000 2017-01-01 16:34
3 Animal1 418418 394985 2017-01-02 08:18
4 Animal1 419448 395405 2017-01-02 15:57
5 Animal1 418249 396145 2017-01-03 07:24
6 Animal1 417399 396238 2017-01-03 17:44
7 Animal1 417320 396119 2017-01-04 06:33
8 Animal1 417770 396080 2017-01-04 17:01
9 Animal1 417232 396812 2017-01-05 08:43
10 Animal1 417716 396745 2017-01-05 16:43
11 Animal2 416571 396099 2017-01-01 06:24
12 Animal2 416423 395996 2017-01-01 16:15
13 Animal2 416184 395916 2017-01-02 08:28
14 Animal2 416002 395858 2017-01-02 15:34
15 Animal2 415454 395993 2017-01-03 07:14
16 Animal2 415450 397175 2017-01-03 17:27
17 Animal2 415781 396949 2017-01-04 06:12
18 Animal2 415702 396949 2017-01-04 17:23
19 Animal2 415017 397185 2017-01-05 08:12
20 Animal2 414516 396990 2017-01-05 16:18
21 Animal3 418971 394300 2017-01-01 05:59
22 Animal3 418275 394558 2017-01-01 16:45
23 Animal3 419881 394940 2017-01-02 08:20
24 Animal3 420304 394669 2017-01-02 15:25
25 Animal3 419585 394825 2017-01-03 07:20
26 Animal3 421528 396153 2017-01-03 17:03
27 Animal3 420045 396510 2017-01-04 06:27
28 Animal3 419636 396349 2017-01-04 17:17
29 Animal3 419499 396212 2017-01-05 08:22
30 Animal3 420515 395898 2017-01-05 16:14")
DT[, datetime := as.POSIXct( paste(Date, Time ), format = "%Y-%m-%d %H:%M" ) ]
#convert cvoordinates to 'normal' wgs84 lon/lat
library( sf )
DT[ , c("lon", "lat") := DT %>%
sf::st_as_sf( coords = c("GPS.S", "GPS.E"), crs = 32629 ) %>%
sf::st_transform( 4326 ) %>% sf::st_coordinates() %>% data.table::as.data.table() ][]
#split by animal
L <- split( DT, by = "ID" )
#update to get closest rownumbers
lapply( L, function(x) {
lapply( L, function(y) {
#update x with the rowid of the nearest timestamp in y
x[, unique(y$ID) := y[x, x.rowid, roll = "nearest", on = .(datetime)] ]
})
})
#bind together again
DT <- data.table::rbindlist( L )
#melt to long format
DT.melt <- data.table::melt(DT,
measure.vars = patterns("^Animal[0-9]+"),
variable.name = "ID2",
variable.factor = FALSE,
value.name = "rowid2" )
#join in the coordinates of the ID2-animal
DT.melt[ DT, `:=`( lon2 = i.lon, lat2 = i.lat ), on = .(rowid2 = rowid) ][]
#calculate the distance between c(lon, lat) and c(lon2, lat2)
# I do no know the data.table approach here, so a small switch to the tidyverse
DT.melt <- DT.melt %>%
dplyr::mutate( distance = purrr::pmap(
list( a = lon,
b = lat,
x = lon2,
y = lat2 ),
~ round( geosphere::distHaversine( c(..1, ..2), c(..3, ..4) ) ) ) )
#now, cast to wide again
dcast( DT.melt, rowid + ID + GPS.E + GPS.S + Date + Time ~ ID2, value.var = "distance" )
#output
# rowid ID GPS.E GPS.S Date Time Animal1 Animal2 Animal3
# 1: 1 Animal1 417547 393907 2017-01-01 06:19 0 2403 1487
# 2: 2 Animal1 417769 395000 2017-01-01 16:34 0 1682 675
# 3: 3 Animal1 418418 394985 2017-01-02 08:18 0 2435 1474
# 4: 4 Animal1 419448 395405 2017-01-02 15:57 0 3499 1134
# 5: 5 Animal1 418249 396145 2017-01-03 07:24 0 2819 1885
# 6: 6 Animal1 417399 396238 2017-01-03 17:44 0 2175 4159
# 7: 7 Animal1 417320 396119 2017-01-04 06:33 0 1758 2772
# 8: 8 Animal1 417770 396080 2017-01-04 17:01 0 2257 1898
# 9: 9 Animal1 417232 396812 2017-01-05 08:43 0 2261 2360
# 10: 10 Animal1 417716 396745 2017-01-05 16:43 0 3232 2943
# 11: 11 Animal2 416571 396099 2017-01-01 06:24 2403 0 3013
# 12: 12 Animal2 416423 395996 2017-01-01 16:15 1682 0 2355
# 13: 13 Animal2 416184 395916 2017-01-02 08:28 2435 0 3849
# 14: 14 Animal2 416002 395858 2017-01-02 15:34 3499 0 4492
# 15: 15 Animal2 415454 395993 2017-01-03 07:14 2819 0 4321
# 16: 16 Animal2 415450 397175 2017-01-03 17:27 2175 0 6205
# 17: 17 Animal2 415781 396949 2017-01-04 06:12 1758 0 4316
# 18: 18 Animal2 415702 396949 2017-01-04 17:23 2257 0 4007
# 19: 19 Animal2 415017 397185 2017-01-05 08:12 2261 0 4617
# 20: 20 Animal2 414516 396990 2017-01-05 16:18 3232 0 6139
# 21: 21 Animal3 418971 394300 2017-01-01 05:59 1487 3013 0
# 22: 22 Animal3 418275 394558 2017-01-01 16:45 675 2355 0
# 23: 23 Animal3 419881 394940 2017-01-02 08:20 1474 3849 0
# 24: 24 Animal3 420304 394669 2017-01-02 15:25 1134 4492 0
# 25: 25 Animal3 419585 394825 2017-01-03 07:20 1885 4321 0
# 26: 26 Animal3 421528 396153 2017-01-03 17:03 4159 6205 0
# 27: 27 Animal3 420045 396510 2017-01-04 06:27 2772 4316 0
# 28: 28 Animal3 419636 396349 2017-01-04 17:17 1898 4007 0
# 29: 29 Animal3 419499 396212 2017-01-05 08:22 2360 4617 0
# 30: 30 Animal3 420515 395898 2017-01-05 16:14 2943 6139 0
# rowid ID GPS.E GPS.S Date Time Animal1 Animal2 Animal3
我有三只动物一年的东向和北向 GPS 坐标。我想计算每个时间点每只动物之间的距离。
我不知道该怎么做,我们将不胜感激。
我提供了一个数据示例以备不时之需。
ID GPS.E GPS.S Date Time
1 Animal 1 417547 393907 2017-01-01 06:19
2 Animal 1 417769 395000 2017-01-01 16:34
3 Animal 1 418418 394985 2017-01-02 08:18
4 Animal 1 419448 395405 2017-01-02 15:57
5 Animal 1 418249 396145 2017-01-03 07:24
6 Animal 1 417399 396238 2017-01-03 17:44
7 Animal 1 417320 396119 2017-01-04 06:33
8 Animal 1 417770 396080 2017-01-04 17:01
9 Animal 1 417232 396812 2017-01-05 08:43
10 Animal 1 417716 396745 2017-01-05 16:43
11 Animal 2 416571 396099 2017-01-01 06:24
12 Animal 2 416423 395996 2017-01-01 16:15
13 Animal 2 416184 395916 2017-01-02 08:28
14 Animal 2 416002 395858 2017-01-02 15:34
15 Animal 2 415454 395993 2017-01-03 07:14
16 Animal 2 415450 397175 2017-01-03 17:27
17 Animal 2 415781 396949 2017-01-04 06:12
18 Animal 2 415702 396949 2017-01-04 17:23
19 Animal 2 415017 397185 2017-01-05 08:12
20 Animal 2 414516 396990 2017-01-05 16:18
21 Animal 3 418971 394300 2017-01-01 05:59
22 Animal 3 418275 394558 2017-01-01 16:45
23 Animal 3 419881 394940 2017-01-02 08:20
24 Animal 3 420304 394669 2017-01-02 15:25
25 Animal 3 419585 394825 2017-01-03 07:20
26 Animal 3 421528 396153 2017-01-03 17:03
27 Animal 3 420045 396510 2017-01-04 06:27
28 Animal 3 419636 396349 2017-01-04 17:17
29 Animal 3 419499 396212 2017-01-05 08:22
30 Animal 3 420515 395898 2017-01-05 16:14 ````
The desired output is
ID Distance to Animal 1 Distance to Animal 2 Distance to Animal 3
Animal 1
Animal 1
Animal 1
Animal 1
Animal 1
Animal 1
Animal 1
Animal 1
Animal 1
Animal 1
Animal 2
Animal 2
Animal 2
Animal 2
etc.
看起来像一个简单的问题,但出奇地难以解决(至少对我而言)..
请亲手检查一些答案,以确保我正确理解坐标。距离是(应该是)米..
library( data.table )
library( sf )
library( geosphere )
library( tidyverse )
#sample data
DT <- data.table::fread("rowid ID GPS.E GPS.S Date Time
1 Animal1 417547 393907 2017-01-01 06:19
2 Animal1 417769 395000 2017-01-01 16:34
3 Animal1 418418 394985 2017-01-02 08:18
4 Animal1 419448 395405 2017-01-02 15:57
5 Animal1 418249 396145 2017-01-03 07:24
6 Animal1 417399 396238 2017-01-03 17:44
7 Animal1 417320 396119 2017-01-04 06:33
8 Animal1 417770 396080 2017-01-04 17:01
9 Animal1 417232 396812 2017-01-05 08:43
10 Animal1 417716 396745 2017-01-05 16:43
11 Animal2 416571 396099 2017-01-01 06:24
12 Animal2 416423 395996 2017-01-01 16:15
13 Animal2 416184 395916 2017-01-02 08:28
14 Animal2 416002 395858 2017-01-02 15:34
15 Animal2 415454 395993 2017-01-03 07:14
16 Animal2 415450 397175 2017-01-03 17:27
17 Animal2 415781 396949 2017-01-04 06:12
18 Animal2 415702 396949 2017-01-04 17:23
19 Animal2 415017 397185 2017-01-05 08:12
20 Animal2 414516 396990 2017-01-05 16:18
21 Animal3 418971 394300 2017-01-01 05:59
22 Animal3 418275 394558 2017-01-01 16:45
23 Animal3 419881 394940 2017-01-02 08:20
24 Animal3 420304 394669 2017-01-02 15:25
25 Animal3 419585 394825 2017-01-03 07:20
26 Animal3 421528 396153 2017-01-03 17:03
27 Animal3 420045 396510 2017-01-04 06:27
28 Animal3 419636 396349 2017-01-04 17:17
29 Animal3 419499 396212 2017-01-05 08:22
30 Animal3 420515 395898 2017-01-05 16:14")
DT[, datetime := as.POSIXct( paste(Date, Time ), format = "%Y-%m-%d %H:%M" ) ]
#convert cvoordinates to 'normal' wgs84 lon/lat
library( sf )
DT[ , c("lon", "lat") := DT %>%
sf::st_as_sf( coords = c("GPS.S", "GPS.E"), crs = 32629 ) %>%
sf::st_transform( 4326 ) %>% sf::st_coordinates() %>% data.table::as.data.table() ][]
#split by animal
L <- split( DT, by = "ID" )
#update to get closest rownumbers
lapply( L, function(x) {
lapply( L, function(y) {
#update x with the rowid of the nearest timestamp in y
x[, unique(y$ID) := y[x, x.rowid, roll = "nearest", on = .(datetime)] ]
})
})
#bind together again
DT <- data.table::rbindlist( L )
#melt to long format
DT.melt <- data.table::melt(DT,
measure.vars = patterns("^Animal[0-9]+"),
variable.name = "ID2",
variable.factor = FALSE,
value.name = "rowid2" )
#join in the coordinates of the ID2-animal
DT.melt[ DT, `:=`( lon2 = i.lon, lat2 = i.lat ), on = .(rowid2 = rowid) ][]
#calculate the distance between c(lon, lat) and c(lon2, lat2)
# I do no know the data.table approach here, so a small switch to the tidyverse
DT.melt <- DT.melt %>%
dplyr::mutate( distance = purrr::pmap(
list( a = lon,
b = lat,
x = lon2,
y = lat2 ),
~ round( geosphere::distHaversine( c(..1, ..2), c(..3, ..4) ) ) ) )
#now, cast to wide again
dcast( DT.melt, rowid + ID + GPS.E + GPS.S + Date + Time ~ ID2, value.var = "distance" )
#output
# rowid ID GPS.E GPS.S Date Time Animal1 Animal2 Animal3
# 1: 1 Animal1 417547 393907 2017-01-01 06:19 0 2403 1487
# 2: 2 Animal1 417769 395000 2017-01-01 16:34 0 1682 675
# 3: 3 Animal1 418418 394985 2017-01-02 08:18 0 2435 1474
# 4: 4 Animal1 419448 395405 2017-01-02 15:57 0 3499 1134
# 5: 5 Animal1 418249 396145 2017-01-03 07:24 0 2819 1885
# 6: 6 Animal1 417399 396238 2017-01-03 17:44 0 2175 4159
# 7: 7 Animal1 417320 396119 2017-01-04 06:33 0 1758 2772
# 8: 8 Animal1 417770 396080 2017-01-04 17:01 0 2257 1898
# 9: 9 Animal1 417232 396812 2017-01-05 08:43 0 2261 2360
# 10: 10 Animal1 417716 396745 2017-01-05 16:43 0 3232 2943
# 11: 11 Animal2 416571 396099 2017-01-01 06:24 2403 0 3013
# 12: 12 Animal2 416423 395996 2017-01-01 16:15 1682 0 2355
# 13: 13 Animal2 416184 395916 2017-01-02 08:28 2435 0 3849
# 14: 14 Animal2 416002 395858 2017-01-02 15:34 3499 0 4492
# 15: 15 Animal2 415454 395993 2017-01-03 07:14 2819 0 4321
# 16: 16 Animal2 415450 397175 2017-01-03 17:27 2175 0 6205
# 17: 17 Animal2 415781 396949 2017-01-04 06:12 1758 0 4316
# 18: 18 Animal2 415702 396949 2017-01-04 17:23 2257 0 4007
# 19: 19 Animal2 415017 397185 2017-01-05 08:12 2261 0 4617
# 20: 20 Animal2 414516 396990 2017-01-05 16:18 3232 0 6139
# 21: 21 Animal3 418971 394300 2017-01-01 05:59 1487 3013 0
# 22: 22 Animal3 418275 394558 2017-01-01 16:45 675 2355 0
# 23: 23 Animal3 419881 394940 2017-01-02 08:20 1474 3849 0
# 24: 24 Animal3 420304 394669 2017-01-02 15:25 1134 4492 0
# 25: 25 Animal3 419585 394825 2017-01-03 07:20 1885 4321 0
# 26: 26 Animal3 421528 396153 2017-01-03 17:03 4159 6205 0
# 27: 27 Animal3 420045 396510 2017-01-04 06:27 2772 4316 0
# 28: 28 Animal3 419636 396349 2017-01-04 17:17 1898 4007 0
# 29: 29 Animal3 419499 396212 2017-01-05 08:22 2360 4617 0
# 30: 30 Animal3 420515 395898 2017-01-05 16:14 2943 6139 0
# rowid ID GPS.E GPS.S Date Time Animal1 Animal2 Animal3