2016-04-10 11 views
0

Ich arbeite an der Gowalla dataset, die etwa 6,44 Millionen Checkins hat. Einzigartige Orte auf diesen Checkins sind 1,28 Millionen. Aber Gowalla gibt nur Breiten und Längen. Also muss ich Stadt, Staat und Land auf jedem dieser Lats und Longs finden. Hilfe von einem anderen Beitrag auf Stackoverflow verwenden Ich konnte die R-Abfrage unten erstellen, die die offenen Straßenkarten abfragt und die relevanten Details findet, die ich will.Schnellere Verarbeitung von JSON-Abfragen in 1,2 Millionen Zeilen in einem Datenrahmen in R

Leider dauert es etwa 1 Minute, um 125 Zeilen zu verarbeiten, was bedeutet, dass 1,28 Millionen Zeilen ein paar Tage dauern würden. Gibt es einen schnelleren Weg, diese Details zu finden? Mag sein, dass es ein Paket mit eingebauten Lats und Longs von Städten der Welt gibt, um den Namen der Stadt für den gegebenen Lat und Long zu finden, so dass ich keine Online-Abfrage durchführen muss.

Venue-Tabelle ist ein Datenrahmen mit 3 Spalten. 1. vid (venueId) 2. lat (Breitengrad) 3. lang (Länge)

for(i in 1:nrow(venueTable)){ 
#this is just an indicator to display current value of i on screen 
cat(paste(".",i,".")) 

#Below code composes the url query 
url<-paste("http://nominatim.openstreetmap.org/reverse.php? format=json&lat=" 
,venueTableTest3$lat[i] 
,"&lon=" 
,venueTableTest3$long[i] 
) 
url<-gsub(' ','',url) 
url<-paste(url) 
x<-fromJSON(url) 
venueTableTest3$display_name[i]<-x$display_name 
venueTableTest3$country[i]<-x$address$country 
} 

Ich bin mit dem jsonlite Paket in R, die x macht, die das Ergebnis der JSON Abfrage als Datenrahmen ist welche verschiedene zurückgegebene Ergebnisse speichert. So benutze ich x$display_name oder mein Pflichtfeld.

Mein Laptop ist Core i5 3230M mit 8 GB RAM und 120 GB SSD mit Windows 8.

+0

Nicht sicher, wie das in R zu tun, aber ich denke, dass Ihr Code synchron ist, was bedeutet, dass nur 1 HTTP-Anfrage zu einer Zeit gesendet wird. Wenn Sie in der Lage wären, 10 gleichzeitig zu senden, könnten Sie ~ 5x höhere Geschwindigkeiten erreichen. – Dodekeract

Antwort

2

Sie werden Probleme haben, selbst wenn Sie mit der Zeit beharren. Der von Ihnen abgefragte Dienst ermöglicht "ein absolutes Maximum von einer Anfrage pro Sekunde", die Sie bereits verletzen. Es ist wahrscheinlich, dass sie Ihre Anfragen drosseln, bevor Sie Anfragen von 1,2 Millionen erreichen. Ihre Website stellt fest, dass ähnliche APIs für größere Verwendungen nur etwa 15.000 kostenlose tägliche Anfragen haben.

Es wäre viel besser für Sie, eine Offline-Option zu verwenden. Eine schnelle Suche zeigt, dass es viele frei verfügbare Datensätze von besiedelten Orten gibt, zusammen mit ihren Längen- und Breitengraden. Hier ist, was wir verwenden werden: http://simplemaps.com/resources/world-cities-data

> library(dplyr) 

> cities.data <- read.csv("world_cities.csv") %>% tbl_df 
> print(cities.data) 

Source: local data frame [7,322 x 9] 

      city  city_ascii  lat  lng pop  country iso2 iso3 province 
      (fctr)   (fctr) (dbl) (dbl) (dbl)  (fctr) (fctr) (fctr) (fctr) 
1 Qal eh-ye Now  Qal eh-ye 34.9830 63.1333 2997 Afghanistan  AF AFG Badghis 
2  Chaghcharan Chaghcharan 34.5167 65.2500 15000 Afghanistan  AF AFG  Ghor 
3  Lashkar Gah Lashkar Gah 31.5830 64.3600 201546 Afghanistan  AF AFG Hilmand 
4   Zaranj   Zaranj 31.1120 61.8870 49851 Afghanistan  AF AFG Nimroz 
5  Tarin Kowt  Tarin Kowt 32.6333 65.8667 10000 Afghanistan  AF AFG Uruzgan 
6 Zareh Sharan Zareh Sharan 32.8500 68.4167 13737 Afghanistan  AF AFG Paktika 
7  Asadabad  Asadabad 34.8660 71.1500 48400 Afghanistan  AF AFG Kunar 
8   Taloqan  Taloqan 36.7300 69.5400 64256 Afghanistan  AF AFG Takhar 
9 Mahmud-E Eraqi Mahmud-E Eraqi 35.0167 69.3333 7407 Afghanistan  AF AFG Kapisa 
10  Mehtar Lam  Mehtar Lam 34.6500 70.1667 17345 Afghanistan  AF AFG Laghman 
..   ...   ...  ...  ... ...   ... ... ...  ... 

Es ist schwer, ohne tatsächliche Daten Beispiele zu demonstrieren (hilfreich zur Verfügung zu stellen!), Aber wir können einige Spielzeug Daten bilden.

# make up toy data 
> candidate.longlat <- data.frame(vid = 1:3, 
           lat = c(12.53, -16.31, 42.87), 
           long = c(-70.03, -48.95, 74.59)) 

Mit der distm Funktion in geosphere, können wir die Abstände zwischen alle Daten und alle Stadtlagen auf einmal berechnen. Für Sie wird dies eine matrix machen, die ~ 8.400.000.000 Nummern enthält, so dass es eine Weile dauern kann (kann die Parallelisierung untersuchen) und kann sehr speicherintensiv sein.

> install.packages("geosphere") 
> library(geosphere) 

# compute distance matrix using geosphere 
> distance.matrix <- distm(x = candidate.longlat[,c("long", "lat")], 
         y = cities.data[,c("lng", "lat")]) 

Es ist dann einfach, die nächstgelegene Stadt zu jedem Ihrer Datenpunkte zu finden, und cbind es zu Ihrem data.frame.

# work out which index in the matrix is closest to the data 
> closest.index <- apply(distance.matrix, 1, which.min) 

# rbind city and country of match with original query 
> candidate.longlat <- cbind(candidate.longlat, cities.data[closest.index, c("city", "country")]) 
> print(candidate.longlat) 

    vid lat long  city country 
1 1 12.53 -70.03 Oranjestad  Aruba 
2 2 -16.31 -48.95 Anapolis  Brazil 
3 3 42.87 74.59 Bishkek Kyrgyzstan 
+0

Das ist eine Erklärung! Vielen Dank für die ausführliche Antwort. –

+0

Ja, tat es! Danke vielmals. –

+0

Welche Entfernungsfunktion wird 'distm' standardmäßig verwenden, wenn keine Entfernungsfunktion angegeben wurde? –

1

Hier ist eine alternative Art und Weise Fähigkeiten inhärente räumliche Verarbeitung unter Verwendung von R:

library(sp) 
library(rgeos) 
library(rgdal) 

# world places shapefile 
URL1 <- "http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_populated_places.zip" 
fil1 <- basename(URL1) 
if (!file.exists(fil1)) download.file(URL1, fil1) 
unzip(fil1) 

places <- readOGR("ne_10m_populated_places.shp", "ne_10m_populated_places", 
        stringsAsFactors=FALSE) 

# some data from the other answer since you didn't provide any 
URL2 <- "http://simplemaps.com/resources/files/world/world_cities.csv" 
fil2 <- basename(URL2) 
if (!file.exists(fil2)) download.file(URL2, fil2) 

# we need the points from said dat 
dat <- read.csv(fil2, stringsAsFactors=FALSE) 
pts <- SpatialPoints(dat[,c("lng", "lat")], CRS(proj4string(places))) 

# this is not necessary 
# I just don't like the warning about longlat not being a real projection 
robin <- "+proj=robin +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs" 
pts <- spTransform(pts, robin) 
places <- spTransform(places, robin) 

# compute the distance (makes a pretty big matrix so you should do this 
# in chunks unless you have a ton of memory or do it row-by-row 
far <- gDistance(pts, places, byid=TRUE) 

# find the closest one 
closest <- apply(far, 1, which.min) 

# map to the fields (you may want to map to other fields) 
locs <- [email protected][closest, c("NAME", "ADM1NAME", "ISO_A2")] 

locs[sample(nrow(locs), 10),] 

##    NAME  ADM1NAME ISO_A2 
## 3274  Szczecin West Pomeranian  PL 
## 1039  Balakhna  Nizhegorod  RU 
## 1012  Chitre   Herrera  PA 
## 3382  L'Aquila   Abruzzo  IT 
## 1982  Dothan   Alabama  US 
## 5159 Bayankhongor  Bayanhongor  MN 
## 620  Deming  New Mexico  US 
## 1907 Fort Smith  Arkansas  US 
## 481  Dedougou  Mou Houn  BF 
## 7169  Prague   Prague  CZ 

Es geht um eine Minute (auf meinem System) für ~ 7500, so dass Sie in ein paar Stunden suchen vs einem Tag oder Mehr. Sie können dies parallel tun und es in weniger als einer Stunde erledigen.

Für eine bessere Ortsauflösung können Sie ein sehr leichtes Shapefile von Land- oder Admin 1-Polygonen verwenden und dann einen zweiten Prozess verwenden, um die Entfernung von besseren Auflösungspunkten für diese geografischen Standorte zu erzielen.

Verwandte Themen