JSON ke pandas DataFrame

158

Apa yang saya coba lakukan adalah mengekstrak data ketinggian dari Google maps API di sepanjang jalur yang ditentukan oleh koordinat lintang dan bujur sebagai berikut:

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

Ini memberi saya data yang terlihat seperti ini:

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

ketika dimasukkan ke dalam sebagai DataFrame, inilah yang saya dapatkan:

masukkan deskripsi gambar di sini

pd.read_json(elevations)

dan inilah yang saya inginkan:

masukkan deskripsi gambar di sini

Saya tidak yakin apakah ini mungkin, tetapi yang terutama saya cari adalah cara untuk dapat menggabungkan data ketinggian, lintang dan bujur dalam bingkai data panda (tidak harus memiliki tajuk mutiline yang mewah).

Jika ada yang bisa membantu atau memberikan beberapa saran tentang bekerja dengan data ini, itu akan sangat bagus! Jika Anda tidak tahu bahwa saya belum banyak bekerja dengan data json sebelumnya ...

EDIT:

Metode ini tidak terlalu menarik tetapi tampaknya berhasil:

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

Akhirnya kerangka data memiliki kolom lintang, bujur, ketinggian

masukkan deskripsi gambar di sini

pbreach
sumber
Halo teman, apakah Anda tahu cara mendapatkan sepotong json? beberapa bagian?
M. Mariscal

Jawaban:

194

Saya menemukan solusi cepat dan mudah untuk apa yang ingin saya gunakan json_normalize()termasuk di dalamnya 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'])

Ini memberikan kerangka data yang rata dengan data json yang saya dapatkan dari Google Maps API.

pbreach
sumber
16
Ini sepertinya tidak lagi berfungsi - Saya harus menggunakan pd.DataFrame.from_records()seperti yang dijelaskan di sini stackoverflow.com/a/33020669/1137803
avv
4
from_records juga terkadang tidak berfungsi jika json cukup rumit, Anda harus menerapkan json.io.json.json_normalize untuk mendapatkan peta datar. Periksa stackoverflow.com/questions/39899005/…
devssh
28

Lihat snip out ini.

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

Semoga membantu :)

Rishu
sumber
1
Kesalahan. Anda harus meneruskan konten file (yaitu string) ke json.loads (), bukan objek file itu sendiri - json.load (train_file.read ())
Vasin Yuriy
13

Anda dapat mengimpor data json terlebih dahulu di kamus Python:

data = json.loads(elevations)

Kemudian ubah data dengan cepat:

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

Buat kembali string json:

elevations = json.dumps(data)

Akhirnya:

pd.read_json(elevations)

Anda juga dapat, mungkin menghindari untuk membuang data kembali ke string, saya berasumsi Panda dapat langsung membuat DataFrame dari kamus (saya sudah tidak menggunakannya sejak lama: p)

Raphaël Braud
sumber
Saya masih mendapatkan hasil yang sama menggunakan data json dan kamus yang telah dibuat. Sepertinya setiap elemen dalam dataframe memiliki perintahnya sendiri. Saya mencoba menggunakan pendekatan Anda dengan cara yang kurang menarik dengan membuat daftar terpisah untuk lat, lng, dan elevasi sambil mengulang melalui 'data'.
pbreach
@ user2593236: Halo, saya melakukan kesalahan saat menyalin / menempel kode saya di SO: del hilang (jawaban diedit)
Raphaël Braud
Hmm .. Masih sama di mana ia memiliki 'hasil' dan 'status' sebagai tajuk sedangkan data json lainnya muncul sebagai dicts di setiap sel. Menurut saya solusi untuk masalah ini adalah dengan mengubah format data agar tidak terbagi lagi menjadi 'results' dan 'status' maka data frame akan menggunakan 'lat', 'lng', 'elevation', ' resolusi 'sebagai tajuk terpisah. Entah itu, atau saya perlu menemukan cara untuk memuat data json ke dalam kerangka data yang akan memiliki indeks tajuk bertingkat seperti yang saya sebutkan dalam pertanyaan.
pbreach
Tabel terakhir mana yang Anda harapkan? Yang Anda dapatkan setelah hasil edit Anda?
Raphaël Braud
Yang saya dapatkan setelah pengeditan terakhir saya melakukan pekerjaan itu, pada dasarnya yang saya butuhkan hanyalah mendapatkan data dalam format tabel yang dapat saya ekspor dan kerjakan
pbreach
11

Hanya versi baru dari jawaban yang diterima, seperti python3.xtidak mendukungurllib2

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'])
AB Abhi
sumber
8

Optimalisasi jawaban yang diterima:

Jawaban yang diterima memiliki beberapa masalah yang berfungsi, jadi saya ingin membagikan kode saya yang tidak bergantung pada 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)

Keluaran:

        _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 untuk harga listrik Denmark

DisabledWhale
sumber
solusi ini lebih baik karena Anda hanya dapat fokus pada pandaspaket tanpa mengimpor paket lain
KY Lu
4

Masalahnya adalah Anda memiliki beberapa kolom dalam bingkai data yang berisi dicts dengan dicts yang lebih kecil di dalamnya. Json yang berguna sering kali banyak bersarang. Saya telah menulis fungsi kecil yang menarik info yang saya inginkan ke kolom baru. Dengan cara itu saya memilikinya dalam format yang ingin saya gunakan.

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')
billmanH
sumber
4

Berikut adalah kelas utilitas kecil yang mengubah JSON menjadi DataFrame dan sebaliknya: Semoga ini berguna bagi Anda.

# -*- 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)
Siva
sumber
1

Solusi billmanH membantu saya tetapi tidak berfungsi sampai saya beralih dari:

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

untuk:

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

inilah sisanya, mengonversi ke kamus sangat membantu untuk bekerja dengan data json.

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'])
niltoid
sumber
1
#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}]}


MIKHIL NAGARALE
sumber
1

Setelah mendapatkan rata-rata yang DataFramediperoleh dari jawaban yang diterima, Anda dapat membuat kolom menjadi MultiIndex("tajuk multiline mewah") seperti ini:

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

Saya lebih suka metode yang lebih umum di mana mungkin pengguna tidak lebih suka memberikan 'hasil' kunci. Anda masih dapat meratakannya dengan menggunakan pendekatan rekursif untuk menemukan kunci yang memiliki data bertingkat atau jika Anda memiliki kunci tetapi JSON Anda sangat bersarang. Itu seperti:

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)
MD Rijwan
sumber