【问题标题】:Python3: Convert List of Complex Objects to CSVPython3:将复杂对象列表转换为 CSV
【发布时间】:2021-11-06 12:04:56
【问题描述】:

TL;DR:如何在 python3 中将复杂对象转换为 CSV?

加长版:

我正在使用 python3.6 转储供应商的数据库(因此我无法控制收到的内容)。我可以将 JSON 提取到字典列表中。 dict有多种值数据类型,包括string、int、sub-list和sub-dict。

如何将其转换为 CSV?

示例数据(pKey = 父密钥,dKey = 子密钥):

[ { "pKey1" : 1, "pKey2" : [ 'a', 'b', 'c' ], "pKey3" : { "dKey1" : "val1", "dKey2" : "val2" } },
  { "pKey1" : 2, "pKey2" : [ 'd' ],           "pKey3" : { "dKey1" : "val3", "dKey2" : "val4" } } 
]

如何将其转换为 CSV?我读到有一种pythonic方式可以在python脚本之间共享复杂的数据结构(我认为是miltiprocess.manage或类似的东西),但是脚本是从BASH启动的,它们彼此一无所知,我需要时刻以 CSV 格式捕获服务器的输出,以便能够读取 Excel 或记事本 (my-machine:~ /home/myuser$ python3 script1.py | tee file.csv | python3 script2.py) 中的数据。

我尝试通过模块 csv 简单地转储表格,但输出很尴尬:

pKey1,pKey2,pKey3
1,"['a', 'b', 'c']","{'dKey1': 'val1', 'dKey2': 'val2'}"
2,"['d']","{'dKey1': 'val3', 'dKey2': 'val4'}"

我尝试过 pandas,但这并没有使所有内容都变平,这仍然很尴尬,而且 dict 变得很奇怪,这使得它有两种尴尬:

pKey1,pKey2,pKey3.dKey1,pKey3.dKey2
1,"['a', 'b', 'c']",val1,val2
2,"['d']",val3,val4

我可以通过丑陋的代码,丑陋的阅读,或两者兼而有之,使这些都适用于今天。但是,我担心未来的代码维护人员会在代码方面遇到困难(我在网络商店工作,而不是软件商店,所以我需要最小的复杂性),我担心未来的工作是阅读 CSV 并尝试重新创建供应商的原始数据结构将很难使用。

我知道 Excel 能够使用合并单元格功能可视化数据的“一种”方式,但我不知道如何在 CSV 中对其进行编码:

我想我可以编写自己的例程来展平对象,但我不喜欢这种想法 - 未来的供应商软件升级可能会改变数据结构,无论如何我的同行是否支持它还不清楚。我希望我可以采用更 Python 的方法。

我知道示例代码通常是预期的,但我什至不确定该采取什么方向。

作为额外的奖励,不一定特定于这个问题,而是它的产物。供应商很好,至少数据表现良好;也就是说,结构从一个元素到下一个元素是一致的。这里真的会弄得一团糟,有没有办法处理呢?

# row 1: dict with two keys; row 2: dict with 3 keys
[ { "pKey1" : 1, "pKey2" : { "dKey1" : "val1", "dKey2" : "val2" } },
  { "pKey1" : (2, 3), "pKey2" : "This is different", "pKey3" : [ "Very", ( "Very", "Different" ) ] } 
]

【问题讨论】:

    标签: python-3.x pandas list csv dictionary


    【解决方案1】:

    在进行了更多阅读和更多思考之后,我意识到我对挑战的理解有误。我不想转储复杂数据的 CSV。我正在尝试以 CSV 格式表示复杂数据。

    不幸的是,CSV 特别好,只有当每一行都是键值对数据的字典时,理想情况下每行都有公共键()(其中键()也称为“列标题”)。如果它比这更复杂,那么 CSV 将永远是错误的工具。

    JSON 虽然不一定可以在 Excel 中打开,但它是一种更好的序列化格式来表示复杂数据。仍然不完美,但我怀疑没有更好的标准数据表示格式,而且它至少是可读的(尤其是使用 json.dump() "indent" 参数)。

    【讨论】:

      【解决方案2】:

      使用pandas.json_normalizeDataFrame.explode,pandas 1.3.2:

      # Your example data
      d = [{"pKey1": 1, 
            "pKey2": ['a', 'b', 'c'], 
            "pKey3": {"dKey1": "val1", 
                       "dKey2": "val2"}},
           {"pKey1": 2, 
            "pKey2": ['d'],           
            "pKey3": {"dKey1": "val3", 
                      "dKey2": "val4"}} 
      ]
      
      df = pd.json_normalize(d)
      
      print(df)
      
         pKey1      pKey2 pKey3.dKey1 pKey3.dKey2
      0      1  [a, b, c]        val1        val2
      1      2        [d]        val3        val4
      
      # Split up the lists in pKey2, giving each item its own row
      res = df.explode('pKey2')
      
      print(res)
      
         pKey1 pKey2 pKey3.dKey1 pKey3.dKey2
      0      1     a        val1        val2
      0      1     b        val1        val2
      0      1     c        val1        val2
      1      2     d        val3        val4
      

      结果是一个平面表,但包含跨行的某些值的重复,这可能适合您,也可能不适合您。

      【讨论】:

      • 一种有趣的方法来解决这个问题。当然解决了如何展平作为键/值对之一的值的嵌入列表,如果我理解正确,它也不需要事先了解数据模式。我原以为我可能有认知错误,因为 CSV 文件是键:值对的列表,这使得它们通常不适合任何更复杂的东西。但是,让我测试一下,看看它对我正在评估的几个生产数据集的效果如何——这绝对是一种有趣的方法!
      • 我对此进行了测试。非常有趣,但是我错了,实际上它确实需要有关架构的特殊知识。它也只知道如何处理单个键的爆炸(我认为?),并且只知道 explode() 一个级别,因此作为列表列表的值不会完全爆炸。最终,我意识到 CSV 虽然不错,但其局限性在于它不适合作为通用数据序列化器,当它不是一个简单的单级字典列表时,JSON 会更好,所有字符串键和值。
      猜你喜欢
      • 2019-06-09
      • 2019-10-20
      • 1970-01-01
      • 2013-03-04
      • 2011-01-19
      • 2016-09-19
      • 1970-01-01
      • 2022-01-21
      • 1970-01-01
      相关资源
      最近更新 更多