2016-11-03 33 views
3

我正在寻找一些帮助,编写一些R代码遍历数据框中的行,并将每行中的值传递给一个函数,并将输出打印到一个excel文件,txt文件或只在控制台中。R代码迭代通过数据帧行谷歌地图距离查询

这样做的目的是自动一堆距离/时间查询(几百),谷歌使用在这个网站上找到的功能地图: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) 
} 

数据框将包含两列:原始邮政编码和目的地邮政编码(加拿大,eh?)。我是一名初学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 

我应该如何去遍历这两行返回来自距离和时间距离2点函数?

+2

我想'sapply'会做你想要什么,用功能你这里显示的是你在调用'sapply'时使用的函数。然而,当你没有提供可重复的例子时,很难更具体。如果你可以使用'dput'在问题中包含你的数据片段,那就可以了。 – ulfelder

+0

@ulfelder不知道这是否有帮助,但我创建了一个示例数据框来处理。因为我不确定如何使用sapply来解决我的问题,所以我不能添加更多。希望这可以帮助。 – macsmith

回答

3

这里有一种方法:使用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 

如果你宁愿做没有创建新的对象,你也可以写出计算时间和距离独立的功能 - 或单一功能与这些输出作为选项 - 然后使用sapplymutate在原始数据框中创建新列。以下是如何可能看起来使用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")) 

而且这里是你如何能与mutate做一个dplyr管:

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"))) 
+0

谢谢@ulfelder!好的解决方案我喜欢简单性以及它如何将结果返回到我可以轻松使用的数据框。我觉得我现在有一个工具可以在将来再次用于任何类似的项目。 – macsmith