【问题标题】:JSON to pandas DataFrameJSON到熊猫数据框
【发布时间】:2014-02-01 23:37:07
【问题描述】:

我想要做的是沿着由纬度和经度坐标指定的路径从谷歌地图 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)

这就是我想要的:

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

如果有人可以就如何处理这些数据提供帮助或提供一些建议,那就太好了!如果你看不出我之前没有太多处理过 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吗?一些子部分?

标签: python json google-maps pandas


【解决方案1】:

我使用包含在pandas 1.01 中的json_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 数据。

【讨论】:

【解决方案2】:

查看此片段。

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

希望对你有帮助:)

【讨论】:

  • 错误。您应该将文件内容(即字符串)传递给 json.loads(),而不是文件对象本身 - json.load(train_file.read())
【解决方案3】:

接受答案的优化:

接受的答案有一些功能问题,所以我想分享我不依赖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 是针对丹麦电价的

【讨论】:

  • 这个解决方案更好,因为你可以只关注pandas包而不导入其他包
【解决方案4】:

您可以先将 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 数据和创建的字典得到相同的结果。似乎数据框中的每个元素都有自己的字典。我尝试以不那么吸引人的方式使用您的方法,在遍历“数据”时为纬度、经度和海拔建立单独的列表。
  • @user2593236:您好,我在 SO 中复制/粘贴代码时出错:缺少一个 del(答案已编辑)
  • Hmm.. 仍然是相同的,它具有“结果”和“状态”作为标题,而其余的 json 数据在每个单元格中显示为 dicts。我认为解决这个问题的方法是改变数据的格式,使其不细分为“结果”和“状态”,然后数据框将使用“纬度”、“经纬度”、“海拔”、“分辨率'作为单独的标题。要么这样,要么我需要找到一种方法将 json 数据加载到数据帧中,该数据帧将具有我在问题中提到的多级标头索引。
  • 你期待哪个决赛桌?编辑后得到的那个?
  • 我在最终编辑后得到的那个可以完成这项工作,基本上我所需要的就是以表格格式获取数据,以便我可以导出和使用
【解决方案5】:

只是接受答案的新版本,因为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'])

【讨论】:

    【解决方案6】:

    这是一个将 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)
    

    【讨论】:

      【解决方案7】:

      问题是数据框中有几列包含其中包含较小字典的字典。有用的 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')
      

      【讨论】:

      • Per @niltoid 我在 2014 年写这篇文章时可能使用了旧版本的 Pandas。Pandas 改变了 .loc.iloc 的方式,你可能需要调整。请参阅下面的调整。
      【解决方案8】:

      使用 Json 加载文件并使用 DataFrame.from_dict 函数将其转换为 pandas 数据帧

      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)
      

      【讨论】:

        【解决方案9】:

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

        【讨论】:

          【解决方案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}]}
          
          
          

          【讨论】:

            【解决方案11】:

            一旦您通过接受的答案获得了扁平化的DataFrame,您可以像这样将列设置为MultiIndex(“花式多行标题”):

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

            【讨论】:

              【解决方案12】:

              我更喜欢一种更通用的方法,在这种方法中,用户可能不喜欢给出关键的“结果”。您仍然可以使用递归方法查找具有嵌套数据的键,或者如果您有键但您的 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)
              

              【讨论】:

                【解决方案13】:

                Rumble 通过 JSONiq 原生支持 JSON 并在 Spark 上运行,在内部管理 DataFrame,因此您不需要 - 即使数据不是完全结构化的:

                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,然后以任何其他宿主语言作为 DataFrame 重新打开。

                【讨论】:

                  【解决方案14】:

                  参考MongoDB documentation,我得到如下代码:

                  from pandas import DataFrame
                  df = DataFrame('Your json string')
                  

                  【讨论】:

                    猜你喜欢
                    • 2017-11-28
                    • 2013-02-23
                    • 1970-01-01
                    • 2020-06-03
                    • 1970-01-01
                    • 2017-08-25
                    • 2017-10-18
                    相关资源
                    最近更新 更多