JSON转换为Pandas DataFrame


143

我想做的是沿着经纬度坐标指定的路径从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)

这是我想要的:

在此处输入图片说明

我不确定这是否可行,但主要是我想寻找的是一种将海拔,纬度和经度数据放到pandas数据框中的方式(不必具有花哨的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

结束具有经度,纬度,海拔列的数据框

在此处输入图片说明


您好朋友,您知道如何获取json吗?一些子部分?
M. Mariscal

Answers:


184

我找到了一个快速简便的解决方案,以解决我想要使用的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'])

这提供了一个很好的扁平化数据框架,其中包含我从Google Maps API获得的json数据。


12
这似乎不再起作用-我不得不pd.DataFrame.from_records()按此处所述使用stackoverflow.com/a/33020669/1137803
avv

4
如果json非常复杂,from_records有时也不起作用,您必须应用json.io.json.json_normalize来获得平面图。请查看stackoverflow.com/questions/39899005/…–
devssh,

27

检查此片段。

# 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数据和创建的字典得到相同的结果。似乎数据框中的每个元素都有其自己的字典。我尝试以一种不太吸引人的方式使用您的方法,同时遍历“数据”时为纬度,经度和海拔建立了单独的列表。
pbreach

@ user2593236:你好,我做了一个错误,同时复制/粘贴我的代码在SO:一德尔失踪(编辑答案)
拉斐尔布劳德

嗯。在头具有“结果”和“状态”作为标头的同时,其余json数据在每个单元格中作为字典显示。我认为解决此问题的方法是更改​​数据格式,以便不将其细分为“结果”和“状态”,然后数据框将使用“ lat”,“ lng”,“ elevation”,“分辨率”作为单独的标题。要么,要么我需要找到一种方法来将json数据加载到一个数据帧中,该数据帧将具有我在问题中提到的多级标头索引。
pbreach

您期望哪张决赛桌?编辑后得到的一个?
拉斐尔布劳德

我完成最后编辑后得到的文件基本上可以完成,基本上我所需要的只是以一种可以导出并使用的表格格式获取数据
pbreach 2014年

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

问题是您在数据框中有几列,其中包含较小的dict。有用的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(花式多行标题)”,如下所示:

df.columns = pd.MultiIndex.from_tuples([tuple(c.split('.')) for c in df.columns])
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.