JSON naar panda’s DataFrame

Wat ik probeer te doen, is als volgt hoogtegegevens extraheren uit een Google Maps API langs een pad dat wordt gespecificeerd door breedte- en lengtecoördinaten:

from urllib2 import Request, urlopen
import json
path1 = '42.974049,-81.205203|42.974298,-81.195755'
request=Request('http://maps.googleapis.com/maps/api/elevation/json?locations='+path1+'&sensor=false')
response = urlopen(request)
elevations = response.read()

Dit geeft me gegevens die er als volgt uitzien:

elevations.splitlines()
['{',
 '   "results" : [',
 '      {',
 '         "elevation" : 243.3462677001953,',
 '         "location" : {',
 '            "lat" : 42.974049,',
 '            "lng" : -81.205203',
 '         },',
 '         "resolution" : 19.08790397644043',
 '      },',
 '      {',
 '         "elevation" : 244.1318664550781,',
 '         "location" : {',
 '            "lat" : 42.974298,',
 '            "lng" : -81.19575500000001',
 '         },',
 '         "resolution" : 19.08790397644043',
 '      }',
 '   ],',
 '   "status" : "OK"',
 '}']

wanneer ik het als DataFrame invoer, krijg ik dit:

pd.read_json(elevations)

en dit is wat ik wil:

Ik weet niet zeker of dit mogelijk is, maar ik ben vooral op zoek naar een manier om de hoogte-, breedtegraad- en lengtegraadgegevens samen te voegen in een panda-dataframe (hoeft geen fancy mutiline-headers te hebben ).

Als iemand kan helpen of advies kan geven over het werken met deze gegevens, zou dat geweldig zijn! Als je niet kunt zien dat ik nog niet veel met json-gegevens heb gewerkt…

BEWERKEN:

Deze methode is niet zo aantrekkelijk, maar lijkt te werken:

data = json.loads(elevations)
lat,lng,el = [],[],[]
for result in data['results']:
    lat.append(result[u'location'][u'lat'])
    lng.append(result[u'location'][u'lng'])
    el.append(result[u'elevation'])
df = pd.DataFrame([lat,lng,el]).T

eindigt dataframe met kolommen breedtegraad, lengtegraad, hoogte


Antwoord 1, autoriteit 100%

Ik heb een snelle en gemakkelijke oplossing gevonden voor wat ik wilde met json_normalize()opgenomen in pandas 1.01.

from urllib2 import Request, urlopen
import json
import pandas as pd    
path1 = '42.974049,-81.205203|42.974298,-81.195755'
request=Request('http://maps.googleapis.com/maps/api/elevation/json?locations='+path1+'&sensor=false')
response = urlopen(request)
elevations = response.read()
data = json.loads(elevations)
df = pd.json_normalize(data['results'])

Dit geeft een mooi plat dataframe met de json-gegevens die ik heb gekregen van de Google Maps API.


Antwoord 2, autoriteit 14%

Bekijk dit fragment.

# reading the JSON data using json.load()
file = 'data.json'
with open(file) as train_file:
    dict_train = json.load(train_file)
# converting json dataset from dictionary to dataframe
train = pd.DataFrame.from_dict(dict_train, orient='index')
train.reset_index(level=0, inplace=True)

Hopelijk helpt het 🙂


Antwoord 3, autoriteit 8%

Optimalisatie van het geaccepteerde antwoord:

Het geaccepteerde antwoord heeft enkele werkingsproblemen, dus ik wil mijn code delen die niet afhankelijk is van urllib2:

import requests
from pandas import json_normalize
url = 'https://www.energidataservice.dk/proxy/api/datastore_search?resource_id=nordpoolmarket&limit=5'
response = requests.get(url)
dictr = response.json()
recs = dictr['result']['records']
df = json_normalize(recs)
print(df)

Uitvoer:

       _id                    HourUTC               HourDK  ... ElbasAveragePriceEUR  ElbasMaxPriceEUR  ElbasMinPriceEUR
0    264028  2019-01-01T00:00:00+00:00  2019-01-01T01:00:00  ...                  NaN               NaN               NaN
1    138428  2017-09-03T15:00:00+00:00  2017-09-03T17:00:00  ...                33.28              33.4              32.0
2    138429  2017-09-03T16:00:00+00:00  2017-09-03T18:00:00  ...                35.20              35.7              34.9
3    138430  2017-09-03T17:00:00+00:00  2017-09-03T19:00:00  ...                37.50              37.8              37.3
4    138431  2017-09-03T18:00:00+00:00  2017-09-03T20:00:00  ...                39.65              42.9              35.3
..      ...                        ...                  ...  ...                  ...               ...               ...
995  139290  2017-10-09T13:00:00+00:00  2017-10-09T15:00:00  ...                38.40              38.4              38.4
996  139291  2017-10-09T14:00:00+00:00  2017-10-09T16:00:00  ...                41.90              44.3              33.9
997  139292  2017-10-09T15:00:00+00:00  2017-10-09T17:00:00  ...                46.26              49.5              41.4
998  139293  2017-10-09T16:00:00+00:00  2017-10-09T18:00:00  ...                56.22              58.5              49.1
999  139294  2017-10-09T17:00:00+00:00  2017-10-09T19:00:00  ...                56.71              65.4              42.2 

PS: API is voor de Deense elektriciteitsprijzen


Antwoord 4, Autoriteit 6%

U kunt eerst uw JSON-gegevens in een Python-dictionnary importeren:

data = json.loads(elevations)

Wijzig vervolgens gegevens over de vlieg:

for result in data['results']:
    result[u'lat']=result[u'location'][u'lat']
    result[u'lng']=result[u'location'][u'lng']
    del result[u'location']

REBUILD JSON String:

elevations = json.dumps(data)

Eindelijk:

pd.read_json(elevations)

U kunt, ook, waarschijnlijk vermijden om gegevens terug te dumpen naar een string, ik neem aan dat Panda rechtstreeks een dataframe van een dictionnary kan maken (ik heb het sinds een lange tijd niet gebruikt: P)


Antwoord 5, Autoriteit 6%

Gewoon een nieuwe versie van het geaccepteerde antwoord, als python3.xondersteunt niet urllib2

from requests import request
import json
from pandas.io.json import json_normalize
path1 = '42.974049,-81.205203|42.974298,-81.195755'
response=request(url='http://maps.googleapis.com/maps/api/elevation/json?locations='+path1+'&sensor=false', method='get')
elevations = response.json()
elevations
data = json.loads(elevations)
json_normalize(data['results'])

Antwoord 6, Autoriteit 3%

Hier is een kleine hulpprogramma die JSON converteert naar dataframe en terug: hoop dat u dit nuttig vindt.

# -*- coding: utf-8 -*-
from pandas.io.json import json_normalize
class DFConverter:
    #Converts the input JSON to a DataFrame
    def convertToDF(self,dfJSON):
        return(json_normalize(dfJSON))
    #Converts the input DataFrame to JSON 
    def convertToJSON(self, df):
        resultJSON = df.to_json(orient='records')
        return(resultJSON)

Antwoord 7, Autoriteit 2%

Het probleem is dat u verschillende kolommen in het gegevensframe hebt dat dicts bevat met kleinere diekenten in deze. Nuttige JSON is vaak zwaar genest. Ik heb kleine functies geschreven die de info trillen die ik wil in een nieuwe kolom. Op die manier heb ik het in het formaat dat ik wil gebruiken.

for row in range(len(data)):
    #First I load the dict (one at a time)
    n = data.loc[row,'dict_column']
    #Now I make a new column that pulls out the data that I want.
    data.loc[row,'new_column'] = n.get('key')

Antwoord 8

Gebruik JSON om het bestand te laden en deze converteren naar een Pandas-dataframe met behulp van dataframe.from_dict-functie

import json
import pandas as pd
json_string = '{ "name":"John", "age":30, "car":"None" }'
a_json = json.loads(json_string)
print(a_json)
dataframe = pd.DataFrame.from_dict(a_json)

Antwoord 9

De oplossing van Billmanh heeft me geholpen, maar werkte niet totdat ik van:

n = data.loc[row,'json_column']

naar:

n = data.iloc[[row]]['json_column']

hier is de rest, converteren naar een woordenboek is handig voor het werken met json-gegevens.

import json
for row in range(len(data)):
    n = data.iloc[[row]]['json_column'].item()
    jsonDict = json.loads(n)
    if ('mykey' in jsonDict):
        display(jsonDict['mykey'])

Antwoord 10

#Use the small trick to make the data json interpret-able
#Since your data is not directly interpreted by json.loads()
>>> import json
>>> f=open("sampledata.txt","r+")
>>> data = f.read()
>>> for x in data.split("\n"):
...     strlist = "["+x+"]"
...     datalist=json.loads(strlist)
...     for y in datalist:
...             print(type(y))
...             print(y)
...
...
<type 'dict'>
{u'0': [[10.8, 36.0], {u'10': 0, u'1': 0, u'0': 0, u'3': 0, u'2': 0, u'5': 0, u'4': 0, u'7': 0, u'6': 0, u'9': 0, u'8': 0}]}
<type 'dict'>
{u'1': [[10.8, 36.1], {u'10': 0, u'1': 0, u'0': 0, u'3': 0, u'2': 0, u'5': 0, u'4': 0, u'7': 0, u'6': 0, u'9': 0, u'8': 0}]}
<type 'dict'>
{u'2': [[10.8, 36.2], {u'10': 0, u'1': 0, u'0': 0, u'3': 0, u'2': 0, u'5': 0, u'4': 0, u'7': 0, u'6': 0, u'9': 0, u'8': 0}]}
<type 'dict'>
{u'3': [[10.8, 36.300000000000004], {u'10': 0, u'1': 0, u'0': 0, u'3': 0, u'2': 0, u'5': 0, u'4': 0, u'7': 0, u'6': 0, u'9': 0, u'8': 0}]}
<type 'dict'>
{u'4': [[10.8, 36.4], {u'10': 0, u'1': 0, u'0': 0, u'3': 0, u'2': 0, u'5': 0, u'4': 0, u'7': 0, u'6': 0, u'9': 0, u'8': 0}]}
<type 'dict'>
{u'5': [[10.8, 36.5], {u'10': 0, u'1': 0, u'0': 0, u'3': 0, u'2': 0, u'5': 0, u'4': 0, u'7': 0, u'6': 0, u'9': 0, u'8': 0}]}
<type 'dict'>
{u'6': [[10.8, 36.6], {u'10': 0, u'1': 0, u'0': 0, u'3': 0, u'2': 0, u'5': 0, u'4': 0, u'7': 0, u'6': 0, u'9': 0, u'8': 0}]}
<type 'dict'>
{u'7': [[10.8, 36.7], {u'10': 0, u'1': 0, u'0': 0, u'3': 0, u'2': 0, u'5': 0, u'4': 0, u'7': 0, u'6': 0, u'9': 0, u'8': 0}]}
<type 'dict'>
{u'8': [[10.8, 36.800000000000004], {u'1': 0, u'0': 0, u'3': 0, u'2': 0, u'5': 0, u'4': 0, u'7': 0, u'6': 0, u'9': 0, u'8': 0}]}
<type 'dict'>
{u'9': [[10.8, 36.9], {u'1': 0, u'0': 0, u'3': 0, u'2': 0, u'5': 0, u'4': 0, u'7': 0, u'6': 0, u'9': 0, u'8': 0}]}

Antwoord 11

Nadat u de afgeplatte DataFramehebt verkregen door het geaccepteerde antwoord, kunt u de kolommen een MultiIndex(“Fancy Multiline Header”) als deze maken:

df.columns = pd.MultiIndex.from_tuples([tuple(c.split('.')) for c in df.columns])

Antwoord 12

Ik geef de voorkeur aan een meer generieke methode waarin de gebruiker misschien liever de liever ‘resultaten’ geeft. Je kunt het nog steeds plat maken met een recursieve benadering van het vinden van sleutel met geneste gegevens of als je een sleutel hebt, maar je JSON is erg genest. Het is zoiets als:

from pandas import json_normalize
def findnestedlist(js):
    for i in js.keys():
        if isinstance(js[i],list):
            return js[i]
    for v in js.values():
        if isinstance(v,dict):
            return check_list(v)
def recursive_lookup(k, d):
    if k in d:
        return d[k]
    for v in d.values():
        if isinstance(v, dict):
            return recursive_lookup(k, v)
    return None
def flat_json(content,key):
    nested_list = []
    js = json.loads(content)
    if key is None or key == '':
        nested_list = findnestedlist(js)
    else:
        nested_list = recursive_lookup(key, js)
    return json_normalize(nested_list,sep="_")
key = "results" # If you don't have it, give it None
csv_data = flat_json(your_json_string,root_key)
print(csv_data)

Antwoord 13

Rumbleondersteunt JSON native met JSONiq en draait op Spark, waarbij DataFrames intern worden beheerd, zodat u dat niet hoeft te doen — zelfs als de gegevens niet volledig gestructureerd zijn:

let $coords := "42.974049,-81.205203%7C42.974298,-81.195755"
let $request := json-doc("http://maps.googleapis.com/maps/api/elevation/json?locations="||$coords||"&sensor=false")
for $obj in $request.results[]
return {
  "latitude" : $obj.location.lat,
  "longitude" : $obj.location.lng,
  "elevation" : $obj.elevation
}

De resultaten kunnen worden geëxporteerd naar CSV en vervolgens opnieuw worden geopend in een andere hosttaal als DataFrame.

Other episodes