【问题标题】:R code to iterate through dataframe rows for google maps distance queriesR代码迭代谷歌地图距离查询的数据框行
【发布时间】:2016-11-03 16:35:03
【问题描述】:

我正在寻找一些帮助来编写一些 R 代码来遍历数据帧中的行并将每行中的值传递给函数并将输出打印到 excel 文件、txt 文件或仅在控制台中。

这样做的目的是使用此网站上的功能自动执行一堆距离/时间查询(数百个)到谷歌地图:http://www.nfactorialanalytics.com/r-vignette-for-the-week-finding-time-distance-between-two-places/

该网站的功能如下:

library(XML)
library(RCurl)
distance2Points <- function(origin,destination){
 results <- list();
 xml.url <- paste0('http://maps.googleapis.com/maps/api/distancematrix/xml?origins=',origin,'&destinations=',destination,'&mode=driving&sensor=false')
 xmlfile <- xmlParse(getURL(xml.url))
 dist <- xmlValue(xmlChildren(xpathApply(xmlfile,"//distance")[[1]])$value)
 time <- xmlValue(xmlChildren(xpathApply(xmlfile,"//duration")[[1]])$value)
 distance <- as.numeric(sub(" km","",dist))
 time <- as.numeric(time)/60
 distance <- distance/1000
 results[['time']] <- time
 results[['dist']] <- distance
 return(results)
}

数据框将包含两列:原始邮政编码和目的地邮政编码(加拿大,嗯?)。我是初学者 R 程序员,所以我知道如何使用 read.table 将 txt 文件加载到数据框中。我只是不确定如何迭代数据帧,每次将值传递给 distance2Points 函数并执行。我认为这可以使用 for 循环或应用调用之一来完成?

感谢您的帮助!

编辑:

为了简单起见,假设我想将这两个向量转换成一个数据框

> a <- c("L5B4P2","L5B4P2")
> b <- c("M5E1E5", "A2N1T3")
> postcodetest <- data.frame(a,b)
> postcodetest
       a      b
1 L5B4P2 M5E1E5
2 L5B4P2 A2N1T3

我应该如何遍历这两行以从 distance2Points 函数返回距离和时间?

【问题讨论】:

  • 我认为sapply 会做你想做的事,这里显示的函数就是你在调用sapply 时使用的函数。但是,当您没有提供可重现的示例时,很难更具体。如果您可以使用 dput 在问题中包含您的数据的 sn-p,那就可以了。
  • @ulfelder 不确定这是否有帮助,但我已经创建了一个示例数据框作为可以使用的东西。我不能添加更多,因为我不确定如何使用 sapply 来解决我的问题。希望这会有所帮助。

标签: r loops dataframe google-distancematrix-api


【解决方案1】:

这是一种方法,使用lapply 生成一个列表,其中包含数据中每一行的结果,并使用Reduce(rbind, [yourlist]) 将该列表连接到一个数据框中,其行对应于原始数据中的行。为了完成这项工作,我们还必须调整原始函数中的代码以返回单行数据框,所以我在这里完成了。

distance2Points <- function(origin,destination){

  require(XML)
  require(RCurl)

  xml.url <- paste0('http://maps.googleapis.com/maps/api/distancematrix/xml?origins=',origin,'&destinations=',destination,'&mode=driving&sensor=false')
  xmlfile <- xmlParse(getURL(xml.url))
  dist <- xmlValue(xmlChildren(xpathApply(xmlfile,"//distance")[[1]])$value)
  time <- xmlValue(xmlChildren(xpathApply(xmlfile,"//duration")[[1]])$value)
  distance <- as.numeric(sub(" km","",dist))
  time <- as.numeric(time)/60
  distance <- distance/1000
  # this gives you a one-row data frame instead of a list, b/c it's easy to rbind
  results <- data.frame(time = time, distance = distance)
  return(results)
}

# now apply that function rowwise to your data, using lapply, and roll the results
# into a single data frame using Reduce(rbind)
results <- Reduce(rbind, lapply(seq(nrow(postcodetest)), function(i)
  distance2Points(postcodetest$a[i], postcodetest$b[i])))

应用于您的示例数据时的结果:

> results
        time distance
1   27.06667   27.062
2 1797.80000 2369.311

如果您希望在不创建新对象的情况下执行此操作,您还可以编写单独的函数来计算时间和距离——或者将这些输出作为选项的单个函数——然后使用 sapply 或仅使用 @987654326 @ 在原始数据框中创建新列。以下是使用sapply 时的样子:

distance2Points <- function(origin, destination, output){

  require(XML)
  require(RCurl)

  xml.url <- paste0('http://maps.googleapis.com/maps/api/distancematrix/xml?origins=',
                    origin, '&destinations=', destination, '&mode=driving&sensor=false')

  xmlfile <- xmlParse(getURL(xml.url))

  if(output == "distance") {

    y <- xmlValue(xmlChildren(xpathApply(xmlfile,"//distance")[[1]])$value)
    y <- as.numeric(sub(" km", "", y))/1000

  } else if(output == "time") {

    y <- xmlValue(xmlChildren(xpathApply(xmlfile,"//duration")[[1]])$value)
    y <- as.numeric(y)/60

  } else {

    y <- NA    

  }

  return(y)

}

postcodetest$distance <- sapply(seq(nrow(postcodetest)), function(i)
  distance2Points(postcodetest$a[i], postcodetest$b[i], "distance"))

postcodetest$time <- sapply(seq(nrow(postcodetest)), function(i)
  distance2Points(postcodetest$a[i], postcodetest$b[i], "time"))

下面是你可以在dplyr 管道中使用mutate 的方法:

library(dplyr)

postcodetest <- postcodetest %>%
  mutate(distance = sapply(seq(nrow(postcodetest)), function(i)
           distance2Points(a[i], b[i], "distance")),
         time = sapply(seq(nrow(postcodetest)), function(i)
           distance2Points(a[i], b[i], "time")))

【讨论】:

  • 谢谢@ulfelder!很好的解决方案!我喜欢它的简单性以及它如何将结果返回到我可以轻松使用的数据框。我觉得我现在有了一个工具,将来可以再次用于任何类似的项目。
猜你喜欢
  • 2016-04-23
  • 1970-01-01
  • 1970-01-01
  • 2014-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
相关资源
最近更新 更多