2014-07-20 27 views
5

ile JSON okurken beklenen 'String ya da Unicode', geçerli olan Openstreetmaps API çıkış JSON dizgisini okumayı deniyorum.Pandalar

--------------------------------------------------------------------------- 
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 

Nasıl bir hata önlemek için isteği veya pandalar read_json, değiştirmek için: hata

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) 

aşağıdaki atar:

Aşağıdaki kodu kullanıyorum? Bu arada, sorun ne? JSON dize bir Python nesnesine dönüştürülmesi olsaydı, bunu

{ 
    "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" 
    } 
}, 
...]} 

: böyle bir şey göreceksiniz

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

bir dosyaya json dize yazdırırsanız

cevap

11

, elements anahtarı bir dicts listesi olan bir dict olur. Verilerin büyük çoğunluğu bu listede yer almaktadır.

Bu JSON dizesi bir Pandas nesnesine doğrudan dönüştürülemiyor. İndeks ne olurdu ve sütunlar ne olurdu? Şüphesiz [u'elements', u'version', u'osm3s', u'generator'] sütunları olmasını istemezsiniz, çünkü neredeyse tüm bilgiler elements liste listesindedir.

Ancak DataFrame'in yalnızca elements liste listesindeki verilerden oluşmasını istiyorsanız, bunu belirtmeniz gerekir, çünkü Pandalar sizin için bu varsayımı yapamaz.

Daha da karmaşık olan şeyler, elements'daki her bir dict'ın iç içe geçmiş bir dict olmasıdır.

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

Olmalı ['lat', 'lon', 'type', 'id', 'tags'] sütunlar be: elements ilk dicti düşünün? tags sütununun bir dikte kolonu olması dışında, bu mantıklı gözüküyor. Bu genellikle çok kullanışlı değil. tags dict içindeki tuşların sütunlara dönüştürülmesi daha hoş olurdu. Bunu yapabiliriz, ancak Pandas'ın istediğimizin ne olduğunu bilmesinin bir yolu olmadığı için bunu kendimiz de kodlamalıyız.


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()) 

verimleri

  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

Büyük açıklama !! Bunu mükemmel anlıyorum ama bilmeceyi kendi başıma çözemedim. Teşekkürler! "osmdata = json.loads (osm.read())" satırında doğru olmayan bir şey olabilir, çünkü şunu elde ederim: 'AttributeError: 'Response' nesnesinin 'read' özelliği yoktur – Balzer82

+0

osmdata olmalı = json.loads (osm.content) ' – Balzer82

+0

@ Balzer82: İstekler sürümüm çok eskiydi; API o zamandan beri değişti. İstekler tarafından güncelledim ve yukarıdaki kodu düzenleyeceğim. – unutbu