【问题标题】:rewriting a for loop into to a -apply formular in R for georoute将 for 循环重写为 R 中用于 georoute 的 -apply 公式
【发布时间】:2017-01-14 15:54:21
【问题描述】:

我有一个包含起点和终点(纬度和经度)的大量 data.frame,并且我正在使用 taRifx.geo 包中的 georoute 函数来了解开车需要多远和多长时间A 到 B。

数据看起来像这样(latlonlatlon_end 都是 characters 的类:

> LL[1:10,14:15]
         latlon            latlon_end
1  52.481466 13.317647   52.518811 13.413034
2  52.518811 13.413034   52.504182 13.318051
3  52.504182 13.318051   52.502236 13.305396
4  52.502236 13.305396   52.548096 13.355104
5  52.548096 13.355104   52.569865 13.410967
6  52.569865 13.410967   52.54505 13.419071
7  52.54505 13.419071    52.527736 13.378182
8  52.527736 13.378182   52.495678 13.343019
9  52.495678 13.343019   52.496712 13.341767
10 52.496712 13.341767   52.458631 13.32529

这是我为此目的编写的for 循环:

for(i in 38753:100000){
  DT[i,]=tryCatch(t(as.matrix(unlist(georoute( c(as.character(LL$latlon[i]),
                                                  as.character(LL$latlon_end[i])),
                                                verbose=TRUE, returntype=c("time", "distance"))),
                               nrow = 1, ncol = 2)),
                   error=function(a) {"."} )

}

这里的基本函数,georoute 基本上给出了两个元素的列表,timedistance,这就是为什么我必须在将它们全部绑定到数据框之前先取消列出它们。对于trycatch 函数,这是为了处理georoute 的偶发错误,我不知道我该怎么做..

我确实尝试了很多方法,但似乎只有这个对我有用,因为不知何故 这个georoute 函数似乎一次只需要一对 latlon 和 latlon_end所以我必须逐行做这件事。然而,由于有几十万个条目,我需要几天甚至几周的时间来处理所有这些数据。我知道我应该加入package and understand the codes behind(link inserted),这样我就知道什么更适合这个目的,但是脚本对于我的水平来说太高级了,我什至不知道我要在脚本中寻找什么精确的。我想我可以为此使用 lapply 函数,但我无法让它工作。

任何帮助或提示或想法将非常非常非常非常感谢!

ps。更新原始georoute 返回

> georoute(c(as.character(LL$latlon[1]), as.character(LL$latlon_end[1])), verbose = FALSE, returntype = c("time","distance"))
  distance time
1     9.03 1338
> georoute(c(as.character(LL$latlon[1:3]), as.character(LL$latlon_end[1:3])), verbose = FALSE, returntype = c("time","distance"))
  distance time
1   35.599 5275
> class(georoute(c(as.character(LL$latlon[1]), as.character(LL$latlon_end[1])), verbose = FALSE, returntype = c("time","distance")))
[1] "data.frame"

我认为返回的 distancetime 是数字,因为它的摘要显示了 4 个分位数、平均值、中位数等。

【问题讨论】:

  • 我无法想象 for 循环是这里的瓶颈。我不熟悉 georoute 但实际上它必须花费很长时间才能找到两点之间的路线。如果允许的话,并行版本可能是唯一的解决方案。

标签: r lapply


【解决方案1】:

考虑绕过包并使用其数据源,即 Bing 的 Calculate a Route API,它与 http://dev.virtualearth.net 接口,用于每个参数的 json 提要。仔细阅读,GitHub 源代码看起来很重,向量和矩阵操作证明处理繁重。只需为 distancetime 数据点解析一个 json 提要。

下面使用jsonlite 库发送与包相同的参数,以迭代地构建url,每对纬度/经度作为航点。导入 json 提要后,所需的数据帧将被提取到列表中。请注意:必应地图 API 密钥是必需的,这应该是每个包的要求。

library(jsonlite)

BingMapsAPIkey <- "*****"

dfList <- lapply(seq(38753:100000), function(i) {

  url <- paste0("http://dev.virtualearth.net/REST/v1/Routes?wayPoint.1=", 
                gsub(" ", ",", LL$latlon[i]) , "&wayPoint.2=", gsub(" ", ",", LL$latlon_end[i]),
                "&maxSolutions=1&optimize=time&routePathOutput=Points&distanceUnit=km&travelMode=Driving",
                "&key=", BingMapsAPIkey)      
  tryCatch({
    jsondata <- fromJSON(url)
    return(jsondata$resourceSets$resources[[1]]$routeLegs[[1]]$routeSubLegs[[1]][c("travelDistance", "travelDuration")])
  }, error=function(e) return(data.frame(travelDistance=NA, travelDuration=NA)))

})

# ROW BIND DATAFRAME ELEMENTS IN LIST
geodf <- do.call(rbind, dfList)

# COLUMN BIND TO ORIGINAL DATAFRAME
df <- cbind(LL[38753:100000,], geodf)

输出 (使用上面发布的纬度/经度数据)

#                 latlon          latlon_end travelDistance travelDuration
# 1  52.481466 13.317647 52.518811 13.413034          9.030           1338
# 2  52.518811 13.413034 52.504182 13.318051          8.148           1269
# 3  52.504182 13.318051 52.502236 13.305396          1.694            254
# 4  52.502236 13.305396 52.548096 13.355104         11.700            820
# 5  52.548096 13.355104 52.569865 13.410967          5.966            919
# 6  52.569865 13.410967  52.54505 13.419071          3.110            576
# 7   52.54505 13.419071 52.527736 13.378182          3.851            728
# 8  52.527736 13.378182 52.495678 13.343019          6.196           1051
# 9  52.495678 13.343019 52.496712 13.341767          0.986            277
# 10 52.496712 13.341767  52.458631 13.32529          6.129            947

【讨论】:

  • 我刚刚尝试了代码,但显然结果被全部粘贴到同一行。所以我在尝试处理 5 行时收到以下消息:Warning message: In [(*tmp*, c("time", "distance"), value = list( : provided 10 variables to replace 2 variables。你知道有什么方法可以让 R 逐行粘贴每一对的结果吗?
  • 我收到的警告是针对 sapply 代码的。当我尝试使用vapply 时,我在所有其他行中都粘贴了相同的结果.. 任何想法:/ 仍然感谢!你真好,甚至去看看源代码:(
  • 您确定georoute() 返回一个包含两个元素的列表吗?你能发布几个这个函数的返回值吗?从矩阵转换之前的for 循环中,打印以筛选此方法的输出并进行有问题的编辑。
  • 查看更新,现在仅使用 lapply() 从迭代的 georoute() 调用中检索数据帧列表。从那里将 dfs 行绑定在一起,然后 cbind 到LL
  • 我只尝试了lapply 部分,但似乎它实际上比 for 循环慢,这很奇怪
猜你喜欢
  • 1970-01-01
  • 2020-04-26
  • 2022-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多