【问题标题】:Convert Pandas DataFrame to JSON as element of larger data structure将 Pandas DataFrame 转换为 JSON 作为更大数据结构的元素
【发布时间】:2014-12-02 08:54:15
【问题描述】:

我一直在我的服务器中使用 pandas DataFrame 对象,将它们转换为 CSV 以传输到浏览器,在浏览器中使用 d3 绘制表格值。虽然 CSV 是文件,但我真的需要的不仅仅是 2D 数据表。如果不出意外,我想返回一些关于数据的元数据。

所以我开始使用 JSON 来解决问题,以为我可以用一些元信息和我的 DataFrame 构建一个字典。例如,就像一个荒谬的简单示例:

>>> z = numpy.zeros(10)
>>> df = pandas.DataFrame(z)
>>> df
   0
0  0
1  0
2  0
3  0
4  0
5  0
6  0
7  0
8  0
9  0
>>> result = {
...   "name": "Simple Example",
...   "data": df,
... }

毫不奇怪,这不能使用 json 模块直接序列化。我找到了 jsonext 模块并尝试了它。它“有效”,但产生的结果不完整:

>>> jsonext.dumps(result)
'{"data": ["0"], "name": "Simple Example"}'

查看 DataFrame 本身为这类事情提供的方法,我发现了 to_dict() 和 to_json()。前者产生字典的字典:

>>> df.to_dict()
{0: {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0, 5: 0.0, 6: 0.0, 7: 0.0, 8: 0.0, 9: 0.0}}

但正如您所见,它们无法序列化为 JSON,因为键不是字符串。

df.to_json() 看起来它可能会起作用,尽管我最终会在另一个 JSON 字符串中嵌入一个 JSON 字符串。像这样的:

json.dumps({"name": "简单示例", "data": df.to_json()}) '{"数据": "{\"0\":{\"0\":0.0,\"1\":0.0,\"2\":0.0,\"3\":0.0,\"4 \":0.0,\"5\":0.0,\"6\":0.0,\"7\":0.0,\"8\":0.0,\"9\":0.0}}", "名称": "简单例子"}'

换句话说,有点乱。

关于如何处理这种嵌套结构,其中某些元素无法直接序列化,有什么建议吗?我想我也许可以让 jsonext 工作,但它的 Dict mixin 期望找到一个合适的(在它的脑海中) to_dict() 方法。 DataFrame.to_dict() 似乎没有返回正确的东西。 (虽然我会继续玩它。)

我想这一定是一只已经被剥皮的猫。我只是还没有找到它。我现在很高兴没有比我的示例更分层的东西(尽管有更多的键/值对),但我不会对更通用的解决方案嗤之以鼻。

【问题讨论】:

    标签: python json pandas


    【解决方案1】:

    The default function(提供给json.dumps)会为默认情况下无法序列化的所有对象调用。它可以返回默认编码器可以序列化的任何对象,例如dict。

    df.to_json() 返回一个字符串。 json.loads(df.to_json) 返回一个字典 键是字符串。因此,如果我们设置default=lambda df: json.loads(df.to_json()),那么 DataFrame 将被序列化,就好像它是一个字典一样。

    import json
    import numpy as np
    import pandas as pd
    
    z = np.zeros(10)
    df = pd.DataFrame(z)
    result = {"name": "Simple Example",
              "data": df, }
    
    jstr = json.dumps(result,
                       default=lambda df: json.loads(df.to_json()))
    newresult = json.loads(jstr)
    print(newresult)
    # {u'data': {u'0': {u'0': 0.0,
    #    u'1': 0.0,
    #    u'2': 0.0,
    #    u'3': 0.0,
    #    u'4': 0.0,
    #    u'5': 0.0,
    #    u'6': 0.0,
    #    u'7': 0.0,
    #    u'8': 0.0,
    #    u'9': 0.0}},
    #  u'name': u'Simple Example'}
    
    
    print(pd.DataFrame(newresult['data']))
    

    产量

       0
    0  0
    1  0
    2  0
    3  0
    4  0
    5  0
    6  0
    7  0
    8  0
    9  0
    

    【讨论】:

    • 你也可以只做json.dumps(df, default=DataFrame.to_dict)
    • @flyingsheep:谢谢你的建议。起初它看起来像是一个很大的改进,但不幸的是,如果df 有一个日期时间索引,那么default=lambda df: json.loads(df.to_json() rigmarole 可以工作,但default=pd.DataFrame.to_dict 将提高TypeError: keys must be a string
    【解决方案2】:

    我认为对 jsonext 文档进行更多阅读是有必要的。看起来我可以创建自己的 mixin,它知道如何正确编码我的 DataFrame 对象,然后调用 jsonext.dumps(result)。我被 DataFrame 对象的现有 to_dict() 和 to_json() 方法所吸引,这并不能真正解决问题。

    【讨论】:

      【解决方案3】:

      一种方法是将索引/列转换为字符串,如下所示:

      In [355]: df.index = df.index.astype(str)
      In [356]: df.columns = df.columns.astype(str)
      

      然后你可以构建字典并传递给json.dump

      In [357]: result = {
           ...: ...   "name": "Simple Example",
           ...: ...   "data": df.to_dict(),
           ...: ... }
      
      In [359]: print json.dumps(result, indent=4)
      {
          "data": {
              "0": {
                  "1": 0.0, 
                  "0": 0.0, 
                  "3": 0.0, 
                  "2": 0.0, 
                  "5": 0.0, 
                  "4": 0.0, 
                  "7": 0.0, 
                  "6": 0.0, 
                  "9": 0.0, 
                  "8": 0.0
              }
          }, 
          "name": "Simple Example"
      }
      

      【讨论】:

        猜你喜欢
        • 2023-03-31
        • 2018-10-15
        • 2017-07-20
        • 2021-05-17
        • 2020-12-21
        • 2017-04-13
        • 2021-03-29
        • 1970-01-01
        相关资源
        最近更新 更多