确定最靠近物体的气象站

时间:2017-02-14 01:41:58

标签: r

我在r中编写一个脚本来确定距离物体最近的气象站。除此之外,当运行我的代码时,它会自动返回气象站3(由Table Station中的Cam指示)最接近所有不是这种情况的对象。任何想法为什么会这样?如果可能的话,我也想获得电台名称,而不仅仅是索引。

代码:

 earth.dist <- function (long1, lat1, long2, lat2)
 {
 rad <- pi/180
 a1 <- lat1 * rad
 a2 <- long1 * rad
 b1 <- lat2 * rad
 b2 <- long2 * rad
 dlon <- b2 - a2
 dlat <- b1 - a1
 a <- (sin(dlat/2))^2 + cos(a1) * cos(b1) * (sin(dlon/2))^2
 c <- 2 * atan2(sqrt(a), sqrt(1 - a))
 R <- 6378.145
 d <- R * c
 return(d)
 }


 for (i in 1:length(Object$Lat))
 {
     for (j in 1:length(Station$Lat))
     {
         a[j] <- earth.dist(Station$Lon[j], Station$Lat[j], Object$Lon[i], Object$Lat[i])
     }
     index <- which(min(a) %in% a)
     Object$Station[i] = Station$Station[index]
 }

站台:

Station Lat Lon
SF  37.7749 -122.4194
CH  41.8781 -87.6298
Cam 52.2053 -0.1218

对象表:

Object  Lat Lon
1   38.983  -123.092
2   36.941  -121.767
3   36.121  -121.084
4   38.415  -121.787
5   36.854  -121.362
6   38.651  -121.218
7   37.314  -120.386
8   36.158  -119.8514
9   38.599  -121.54
10  35.335  -120.734
11  34.841  -120.212
12  38.004  -122.02
13  37.599  -122.052
14  38.0903 -122.5267
15  37.664  -121.885
16  51.50853    -0.076132

2 个答案:

答案 0 :(得分:1)

我们不需要重新发明带有r / t地球距离计算的车轮。

数据:

read.table(text="Station Lat Lon
SF  37.7749 -122.4194
CH  41.8781 -87.6298
Cam 52.2053 -0.1218", stringsAsFactors=FALSE, header=TRUE) -> stations

read.table(text="Object  Lat Lon
1   38.983  -123.092
2   36.941  -121.767
3   36.121  -121.084
4   38.415  -121.787
5   36.854  -121.362
6   38.651  -121.218
7   37.314  -120.386
8   36.158  -119.8514
9   38.599  -121.54
10  35.335  -120.734
11  34.841  -120.212
12  38.004  -122.02
13  37.599  -122.052
14  38.0903 -122.5267
15  37.664  -121.885
16  51.50853    -0.076132", stringsAsFactors=FALSE, header=TRUE) -> objs

代码:

library(geosphere)
library(tidyverse)

find_closest_station <- function(lon, lat) {

  mutate(stations, dist=map2_dbl(Lon, Lat, ~distHaversine(c(lon, lat), c(.x, .y)))) %>%
    top_n(-1, wt=dist) %>%
    .$Station

}

mutate(objs, wx_st=map2_chr(Lon, Lat, find_closest_station))
##    Object      Lat         Lon wx_st
## 1       1 38.98300 -123.092000    SF
## 2       2 36.94100 -121.767000    SF
## 3       3 36.12100 -121.084000    SF
## 4       4 38.41500 -121.787000    SF
## 5       5 36.85400 -121.362000    SF
## 6       6 38.65100 -121.218000    SF
## 7       7 37.31400 -120.386000    SF
## 8       8 36.15800 -119.851400    SF
## 9       9 38.59900 -121.540000    SF
## 10     10 35.33500 -120.734000    SF
## 11     11 34.84100 -120.212000    SF
## 12     12 38.00400 -122.020000    SF
## 13     13 37.59900 -122.052000    SF
## 14     14 38.09030 -122.526700    SF
## 15     15 37.66400 -121.885000    SF
## 16     16 51.50853   -0.076132   Cam

答案 1 :(得分:0)

基本上,你的which()逻辑有点偏差。为了说明,下面始终返回TRUE,因此which()返回1.

which("R" %in% LETTERS)
# [1] 1

但是,在第18个字母下面只有TRUE

which(LETTERS == "R")
# [1] 18

所以简单地替换

index <- which(min(a) %in% a)

使用:

index <- which(a == min(a))

此外,考虑应用解决方案,以防您需要保留在基础R中,因为您可以将嵌套for替换为sapply(传入两个向量),并使用apply生成索引:

dist.matrix <- sapply(seq(nrow(Station)), function(x, y) 
                           earth.dist(Station$Lon[x], Station$Lat[x],
                                      Object$Lon[y], Object$Lat[y]), 
                      seq(nrow(Object)))

Object$Station <- apply(dist.matrix, 1, function(i) Station$Station[which(i == min(i))])

Object
#    Object      Lat         Lon       Station
# 1       1 38.98300 -123.092000            SF
# 2       2 36.94100 -121.767000            SF
# 3       3 36.12100 -121.084000            SF
# 4       4 38.41500 -121.787000            SF
# 5       5 36.85400 -121.362000            SF
# 6       6 38.65100 -121.218000            SF
# 7       7 37.31400 -120.386000            SF
# 8       8 36.15800 -119.851400            SF
# 9       9 38.59900 -121.540000            SF
# 10     10 35.33500 -120.734000            SF
# 11     11 34.84100 -120.212000            SF
# 12     12 38.00400 -122.020000            SF
# 13     13 37.59900 -122.052000            SF
# 14     14 38.09030 -122.526700            SF
# 15     15 37.66400 -121.885000            SF
# 16     16 51.50853   -0.076132           Cam

甚至基本R的outer也可以使用转置的 dist.matrix 与上面的sapply输出相比较,因此后者apply按列边距运行:

dist.mat <- outer(seq(nrow(Station)), seq(nrow(Object)),
                function(x, y) earth.dist(Station$Lon[x], Station$Lat[x],
                                          Object$Lon[y], Object$Lat[y]))

Object$Station <- apply(dist.mat, 2, function(i) Station$Station[which(i == min(i))])