2014-07-20 6 views
5

Próbuję odczytać ciąg znaków Openstreetmaps API wyjściowy JSON, który jest poprawny."Oczekiwany ciąg znaków lub kod Unicode" podczas odczytu JSON z Pandami

używam następujący kod:

import pandas as pd 
import requests 

# Links unten 
minLat = 50.9549 
minLon = 13.55232 

# Rechts oben 
maxLat = 51.1390 
maxLon = 13.89873 

osmrequest = {'data': '[out:json][timeout:25];(node["highway"="bus_stop"](%s,%s,%s,%s););out body;>;out skel qt;' % (minLat, minLon, maxLat, maxLon)} 
osmurl = 'http://overpass-api.de/api/interpreter' 
osm = requests.get(osmurl, params=osmrequest) 

osmdata = osm.json() 

osmdataframe = pd.read_json(osmdata) 

który rzuca następujący błąd:

--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
<ipython-input-66-304b7fbfb645> in <module>() 
----> 1 osmdataframe = pd.read_json(osmdata) 

/Users/paul/anaconda/lib/python2.7/site-packages/pandas/io/json.pyc in read_json(path_or_buf, orient, typ, dtype, convert_axes, convert_dates, keep_default_dates, numpy, precise_float, date_unit) 
    196   obj = FrameParser(json, orient, dtype, convert_axes, convert_dates, 
    197       keep_default_dates, numpy, precise_float, 
--> 198       date_unit).parse() 
    199 
    200  if typ == 'series' or obj is None: 

/Users/paul/anaconda/lib/python2.7/site-packages/pandas/io/json.pyc in parse(self) 
    264 
    265   else: 
--> 266    self._parse_no_numpy() 
    267 
    268   if self.obj is None: 

/Users/paul/anaconda/lib/python2.7/site-packages/pandas/io/json.pyc in _parse_no_numpy(self) 
    481   if orient == "columns": 
    482    self.obj = DataFrame(
--> 483     loads(json, precise_float=self.precise_float), dtype=None) 
    484   elif orient == "split": 
    485    decoded = dict((str(k), v) 

TypeError: Expected String or Unicode 

Jak zmodyfikować wniosek lub Pandy read_json, aby uniknąć błędu? A propos, w czym problem?

Odpowiedz

11

przypadku drukowania ciąg json do pliku,

content = osm.read() 
with open('/tmp/out', 'w') as f: 
    f.write(content) 

zobaczysz coś takiego:

{ 
    "version": 0.6, 
    "generator": "Overpass API", 
    "osm3s": { 
    "timestamp_osm_base": "2014-07-20T07:52:02Z", 
    "copyright": "The data included in this document is from www.openstreetmap.org. The data is made available under ODbL." 
    }, 
    "elements": [ 

{ 
    "type": "node", 
    "id": 536694, 
    "lat": 50.9849256, 
    "lon": 13.6821776, 
    "tags": { 
    "highway": "bus_stop", 
    "name": "Niederhäslich Bergmannsweg" 
    } 
}, 
...]} 

Jeśli łańcuch JSON miały być przekształcony w obiekt Pythona, to byłby dyktorem, którego kluczem jest lista dyktów. Ogromna większość danych znajduje się na tej liście dyktatur.

Ten ciąg JSON nie można bezpośrednio przekształcić w obiekt Pandy. Jaki byłby indeks i jakie byłyby kolumny? Z pewnością nie chcesz, aby [u'elements', u'version', u'osm3s', u'generator'] były kolumnami, ponieważ prawie wszystkie informacje znajdują się na liście dyktatur elements.

Ale jeśli chcesz, aby DataFrame zawierała dane tylko z listy dyktatur elements, musisz to określić, ponieważ Pandas nie może przyjąć takiego założenia.

Kolejnym komplikowaniem jest to, że każdy dyktat w elements jest zagnieżdżonym dictem. Rozważmy pierwszy dict w elements:

{ 
    "type": "node", 
    "id": 536694, 
    "lat": 50.9849256, 
    "lon": 13.6821776, 
    "tags": { 
    "highway": "bus_stop", 
    "name": "Niederhäslich Bergmannsweg" 
    } 
} 

Jeżeli ['lat', 'lon', 'type', 'id', 'tags'] być kolumny? To wydaje się prawdopodobne, z wyjątkiem tego, że kolumna tags stanie się kolumną dyktującą. Zwykle nie jest to zbyt przydatne. Byłoby przyjemniej, gdyby klucze wewnątrz dyktatury tags zostały wykonane w kolumny. Możemy to zrobić, ale znowu musimy to zakodować, ponieważ Pandas nie ma możliwości dowiedzenia się, że tego chcemy.


import pandas as pd 
import requests 
# Links unten 
minLat = 50.9549 
minLon = 13.55232 

# Rechts oben 
maxLat = 51.1390 
maxLon = 13.89873 

osmrequest = {'data': '[out:json][timeout:25];(node["highway"="bus_stop"](%s,%s,%s,%s););out body;>;out skel qt;' % (minLat, minLon, maxLat, maxLon)} 
osmurl = 'http://overpass-api.de/api/interpreter' 
osm = requests.get(osmurl, params=osmrequest) 

osmdata = osm.json() 
osmdata = osmdata['elements'] 
for dct in osmdata: 
    for key, val in dct['tags'].iteritems(): 
     dct[key] = val 
    del dct['tags'] 

osmdataframe = pd.DataFrame(osmdata) 
print(osmdataframe[['lat', 'lon', 'name']].head()) 

plony

  lat  lon      name 
0 50.984926 13.682178 Niederhäslich Bergmannsweg 
1 51.123623 13.782789    Sagarder Weg 
2 51.065752 13.895734  Weißig, Einkaufszentrum 
3 51.007140 13.698498   Stuttgarter Straße 
4 51.010199 13.701411   Heilbronner Straße 
+1

Wielki wyjaśnienie !! Rozumiem to doskonale, ale nie mogłem rozwiązać mojej zagadki. Dzięki! W wierszu 'osmdata = json.loads (osm.read())' może być coś niepoprawnego, ponieważ dostaję: 'AttributeError: 'Obiekt odpowiedzi' nie ma atrybutu 'read'' – Balzer82

+0

To musi być' osmdata = json.loads (osm.content) ' – Balzer82

+0

@ Balzer82: Moja wersja żądań była za stara; API zmieniło się od tego czasu. Zaktualizowałem przez 'requests' i edytuję powyższy kod. – unutbu

Powiązane problemy