JSON เป็นแพนด้า DataFrame


144

สิ่งที่ฉันพยายามจะทำคือดึงข้อมูลระดับความสูงจาก google maps API ไปตามเส้นทางที่ระบุโดยพิกัดละติจูดและลองจิจูดดังนี้:

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

สิ่งนี้ทำให้ฉันมีข้อมูลที่มีลักษณะเช่นนี้:

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

เมื่อใส่ DataFrame นี่คือสิ่งที่ฉันได้รับ:

ป้อนคำอธิบายรูปภาพที่นี่

pd.read_json(elevations)

และนี่คือสิ่งที่ฉันต้องการ:

ป้อนคำอธิบายรูปภาพที่นี่

ฉันไม่แน่ใจว่าเป็นไปได้หรือไม่ แต่ส่วนใหญ่สิ่งที่ฉันกำลังมองหาคือวิธีที่จะสามารถใส่ข้อมูลระดับความสูงละติจูดและลองจิจูดเข้าด้วยกันใน dataframe แพนด้า (ไม่ต้องมีส่วนหัว mutiline แฟนซี)

หากมีใครสามารถช่วยหรือให้คำแนะนำในการทำงานกับข้อมูลนี้จะดีมาก! หากคุณไม่สามารถบอกได้ว่าฉันไม่ได้ทำงานกับข้อมูล json มากก่อนหน้านี้ ...

แก้ไข:

วิธีนี้ไม่ได้น่าสนใจเท่าที่ควร แต่ดูเหมือนว่าจะใช้ได้:

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

จบลงด้วย dataframe ที่มีคอลัมน์ละติจูด, ลองจิจูด, ระดับความสูง

ป้อนคำอธิบายรูปภาพที่นี่


สวัสดีเพื่อนคุณรู้วิธีรับชิ้นส่วนของ json หรือไม่? บางส่วนย่อย?
M. Mariscal

คำตอบ:


185

ผมพบว่าเป็นทางออกที่ง่ายและรวดเร็วในสิ่งที่ฉันต้องการใช้รวมอยู่ในjson_normalize()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'])

สิ่งนี้จะให้ dataframe ที่ดีกับข้อมูล json ที่ฉันได้รับจาก Google Maps API


13
ดูเหมือนว่าจะใช้งานไม่ได้อีกต่อไป - ฉันต้องใช้pd.DataFrame.from_records()ตามที่อธิบายไว้ที่นี่stackoverflow.com/a/33020669/1137803
avv

4
from_records ยังใช้งานไม่ได้ในบางครั้งหาก json ซับซ้อนเพียงพอคุณต้องใช้ json.io.json.json_normalize เพื่อรับ flatmap ลองดูstackoverflow.com/questions/39899005/…
devssh

27

ตรวจสอบ snip นี้

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

หวังว่าจะช่วย :)


1
ความผิดพลาด คุณควรส่งเนื้อหาไฟล์ (เช่นสตริง) ไปยัง json.loads () ไม่ใช่วัตถุไฟล์เอง - json.load (train_file.read ())
Vasin Yuriy

13

คุณสามารถนำเข้าข้อมูล json ของคุณในพจนานุกรม Python:

data = json.loads(elevations)

จากนั้นแก้ไขข้อมูลได้ทันที:

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

สร้างสตริง json:

elevations = json.dumps(data)

ในที่สุด:

pd.read_json(elevations)

คุณสามารถหลีกเลี่ยงการถ่ายโอนข้อมูลกลับไปยังสตริงได้ฉันคิดว่า Panda สามารถสร้าง DataFrame จากพจนานุกรมโดยตรง (ฉันไม่ได้ใช้มันมานานแล้ว: p)


ฉันยังคงผลลัพธ์ที่เหมือนกันโดยใช้ข้อมูล json และพจนานุกรมที่สร้างขึ้น ดูเหมือนว่าแต่ละองค์ประกอบใน dataframe จะมี dict ของตัวเอง ฉันลองใช้วิธีการของคุณในวิธีที่น่าดึงดูดน้อยกว่าในการสร้างรายการแยกต่างหากสำหรับ lat, lng และระดับความสูงในขณะที่วนซ้ำผ่าน 'data'
pbreach

@ user2593236: สวัสดีฉันทำข้อผิดพลาดในขณะที่คัดลอก / วางรหัสของฉันใน SO: เดลหายไป (ตอบแก้ไข)
Raphaël Braud

อืม .. ยังเป็นสิ่งเดียวกันกับที่มี 'ผลลัพธ์' และ 'สถานะ' เป็นส่วนหัวในขณะที่ข้อมูลส่วนที่เหลือของ json ปรากฏเป็น dicts ในแต่ละเซลล์ ฉันคิดว่าวิธีแก้ปัญหานี้คือการเปลี่ยนรูปแบบของข้อมูลเพื่อไม่ให้แบ่งเป็น 'ผลลัพธ์' และ 'สถานะ' จากนั้นกรอบข้อมูลจะใช้ 'lat', 'lng', 'ระดับความสูง', ' ความละเอียด 'เป็นส่วนหัวแยก ไม่ว่าจะเป็นหรือฉันจะต้องหาวิธีในการโหลดข้อมูล json ลงใน dataframe ที่จะมีดัชนีส่วนหัวหลายระดับตามที่ฉันกล่าวถึงในคำถาม
pbreach

ตารางสุดท้ายที่คุณคาดหวังคืออะไร สิ่งที่คุณได้รับหลังจากการแก้ไขของคุณ?
Raphaël Braud

สิ่งที่ฉันได้รับหลังจากการแก้ไขครั้งสุดท้ายของฉันทำงานได้โดยทั่วไปสิ่งที่ฉันต้องการคือการรับข้อมูลในรูปแบบตารางที่ฉันสามารถส่งออกและทำงานร่วมกับ
pbreach

9

เป็นรุ่นใหม่ของคำตอบที่ยอมรับได้เนื่องจากpython3.xไม่รองรับ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'])

4

ปัญหาคือคุณมีหลายคอลัมน์ใน data frame ที่มี dicts ที่มี dicts ที่เล็กกว่าอยู่ภายใน มีประโยชน์ Json มักจะซ้อนกันอย่างหนัก ฉันกำลังเขียนฟังก์ชั่นเล็ก ๆ ที่ดึงข้อมูลที่ฉันต้องการลงในคอลัมน์ใหม่ ด้วยวิธีนี้ฉันมีในรูปแบบที่ฉันต้องการใช้

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

4

การเพิ่มประสิทธิภาพของคำตอบที่ยอมรับได้:

คำตอบที่ยอมรับมีปัญหาในการทำงานดังนั้นฉันต้องการแบ่งปันรหัสของฉันที่ไม่พึ่งพา urllib2:

import requests
from pandas.io.json import json_normalize
url = 'https://www.energidataservice.dk/proxy/api/datastore_search?resource_id=nordpoolmarket&limit=5'

r = requests.get(url)
dictr = r.json()
recs = dictr['result']['records']
df = json_normalize(recs)
print(df)

เอาท์พุท:

        _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 สำหรับราคาค่าไฟฟ้าของเดนมาร์ก


3

นี่คือคลาสยูทิลิตี้ขนาดเล็กที่แปลง JSON เป็น DataFrame และย้อนกลับ: หวังว่าคุณจะพบว่ามีประโยชน์

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

1

วิธีแก้ปัญหาของ billmanH ช่วยฉัน แต่ไม่ได้ผลจนกว่าฉันจะเปลี่ยนจาก:

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

ถึง:

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

นี่คือส่วนที่เหลือของมันการแปลงเป็นพจนานุกรมมีประโยชน์สำหรับการทำงานกับข้อมูล 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'])

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


1

เมื่อคุณได้DataFrameรับแบนโดยคำตอบที่ยอมรับคุณสามารถทำให้คอลัมน์เป็นMultiIndex("ส่วนหัว multiline แฟนซี") เช่นนี้:

df.columns = pd.MultiIndex.from_tuples([tuple(c.split('.')) for c in df.columns])
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.