2016-11-03 32 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