Python JSON到数据帧

Python JSON到数据帧,python,json,google-maps,pandas,Python,Json,Google Maps,Pandas,我试图做的是从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

我试图做的是从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"',
 '}']
当放入as DataFrame时,我得到的是:

pd.read_json(elevations)

这就是我想要的:

我不确定这是否可行,但我主要寻找的是一种能够将高程、纬度和经度数据放在一个pandas数据框中的方法(不必有花哨的多行标题)

如果有人能在处理这些数据方面提供帮助或建议,那就太好了!如果你说不出我以前没有对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
结束数据帧,其中包含列纬度、经度和高程


您可以首先在Python词典中导入json数据:

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可以直接从一个字典创建一个数据帧(我很久没有使用它了:p)

我使用
pandas 1.01
中包含的
json\u normalize()
找到了一个快速简便的解决方案

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数据。

问题是,数据框中有几个列包含dict,其中包含较小的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')
看看这个剪子

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

希望有帮助:)

billmanH的解决方案对我有所帮助,但直到我从以下位置切换到以下位置后才起作用:

n = data.loc[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'])

只是接受答案的新版本,因为
python3.x
不支持
urlib2

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'])
#使用小技巧使数据json可解释
#因为您的数据不是由json.loads()直接解释的
>>>导入json
>>>f=打开(“sampledata.txt”、“r+”)
>>>data=f.read()
>>>对于数据中的x。拆分(“\n”):
...     strlist=“[”+x+“]”
...     datalist=json.loads(strlist)
...     对于数据列表中的y:
...             打印(类型(y))
...             打印(y)
...
...
{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}
{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}
{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}
{u'3':[[10.8,36.30000000004],{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}]
{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}
{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}
{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}
{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}
{u'8':[[10.8,36.8000000000004],{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}]
{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}

这里有一个将JSON转换为数据帧并返回的小实用程序类:希望您觉得这很有帮助

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

一旦通过接受的答案获得了平坦的
数据帧
,就可以将列设置为
多索引
(“奇特的多行标题”),如下所示:

df.columns = pd.MultiIndex.from_tuples([tuple(c.split('.')) for c in df.columns])
已接受答案的优化:

已接受的答案存在一些功能问题,因此我想与大家分享我不依赖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)
输出:

        _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是针对丹麦电价的

我更喜欢一种更通用的方法,用户可能不喜欢给出关键的“结果”。您仍然可以通过使用递归方法查找具有嵌套数据的键,或者如果您有键,但JSON非常嵌套,则可以将其展平。有点像:

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)
通过JSONiq以本机方式支持JSON,并在Spark上运行,在内部管理数据帧,因此即使数据不是完全结构化的,也不需要这样做:

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
}

结果可以导出到CSV,然后以任何其他主机语言作为数据帧重新打开。

我仍然使用json数据和创建的字典得到相同的结果。看起来数据帧中的每个元素都有自己的dict。我尝试以一种不太吸引人的方式使用您的方法,在迭代“数据”时为纬度、液化天然气和海拔建立一个单独的列表。@user2593236:您好,我在复制/粘贴代码时出错,所以:缺少一个del(答案编辑过)嗯。。同样的事情,它以“results”和“status”作为标题,而其余的json数据在每个单元格中显示为dict。我认为解决这个问题的办法是改变数据的格式,使其不被细分为“结果”和“状态”,然后数据框将使用“lat”、“lng”、“高程”、“分辨率”作为单独的标题。或者,我需要找到一种方法,将json数据加载到一个数据帧中,该数据帧将具有一个多级头索引,正如我在问题中提到的那样。您希望最后的表是哪一个?你在编辑后得到的那一个?我在最后一次编辑后得到的那一个完成了工作,基本上我所需要的就是以表格格式获取数据,我可以导出并使用它。这似乎不再有效-我必须使用
pd.DataFrame.from_records()
,如这里所述
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)
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
}