使用 Python 中的复杂数组将 JSON 转换为 CSV

Convert JSON to CSV with complex arrays in Python

我有几个包含嵌套数据的 JSON 文件。利用 Python,我能够使用 pandas 来帮助解决这个问题:

import pandas as pd

df = pd.read_json (r'data.json')
export_csv = df.to_csv (r'data.csv', index = None, header=True)

但是,这仅适用于简单的 JSON 文件。我拥有的那些嵌套数组很复杂,并且一些 JSON 数据合并在列下。例如,如果我们要使用此示例数据:

data.json

[
  {
    "id": 1,
    "name": {
      "english": "Bulbasaur",
      "french": "Bulbizarre"
    },
    "type": [
      "Grass",
      "Poison"
    ],
    "base": {
      "HP": 45,
      "Attack": 49,
      "Defense": 49
    }
  },
  {
    "id": 2,
    "name": {
      "english": "Ivysaur",
      "french": "Herbizarre"
    },
    "type": [
      "Grass",
      "Poison"
    ],
    "base": {
      "HP": 60,
      "Attack": 62,
      "Defense": 63
    }
  }
]

结果如下:

您可以看到任何超过第一级的数组都显示在 JSON 中(例如 {'english': 'Bulbasaur', 'french': 'Bulbizarre'})。理想情况下,它应该将这些子数组分解为具有元素名称的列:

最重要的是,其他 JSON 文件具有不同的元素名称和顺序。因此,脚本应该 捕获所有 不同的元素名称,然后将它们转换为 CSV 列。

我怎样才能做到这一点?

使用 json_normalize 就差不多了,但是要拆分列表,您需要一些额外的东西:

f = lambda x: 'type.{}'.format(x + 1)
df = df.join(pd.DataFrame(df.pop('type').values.tolist()).rename(columns=f))

print(df)

输出

   id name.english name.french  ...  base.Defense  type.1  type.2
0   1    Bulbasaur  Bulbizarre  ...            49   Grass  Poison
1   2      Ivysaur  Herbizarre  ...            63   Grass  Poison

[2 rows x 8 columns]

我建议使用 for 循环,结合 defaultdict,通常在进行迭代(没有聚合)时更容易和更快地远离 pandas 直到最终输出:

from collections import defaultdict

df = defaultdict(list)

val = {}
box = []
for entry in data: # data is the sample data you shared
    for key, value in entry.items():
        if key == "id":
            temp = [(key, value)]
        elif isinstance(value, dict):
            temp = [(f"{key}.{k}", v) for k, v in value.items()]
        else:
            temp = [(f"{key}.{k}", v) for k, v in enumerate(value, 1)]
        box.extend(temp)

for k, v in box:
    df[k].append(v)


df

defaultdict(list,
            {'id': [1, 2],
             'name.english': ['Bulbasaur', 'Ivysaur'],
             'name.french': ['Bulbizarre', 'Herbizarre'],
             'type.1': ['Grass', 'Grass'],
             'type.2': ['Poison', 'Poison'],
             'base.HP': [45, 60],
             'base.Attack': [49, 62],
             'base.Defense': [49, 63]})

创建数据框

pd.DataFrame(df)

    id  name.english    name.french type.1  type.2  base.HP base.Attack base.Defense
0   1   Bulbasaur      Bulbizarre   Grass   Poison     45      49       49
1   2   Ivysaur        Herbizarre   Grass   Poison     60      62       63

查看 flatten_json

from flatten_json import flatten
dic = [
  {
    "id": 1,
    "name": {
      "english": "Bulbasaur",
      "french": "Bulbizarre"
    },
    "type": [
      "Grass",
      "Poison"
    ],
    "base": {
      "HP": 45,
      "Attack": 49,
      "Defense": 49
    }
  },
  {
    "id": 2,
    "name": {
      "english": "Ivysaur",
      "french": "Herbizarre"
    },
    "type": [
      "Grass",
      "Poison"
    ],
    "base": {
      "HP": 60,
      "Attack": 62,
      "Defense": 63
    }
  }
]

dic_flattened = (flatten(d, '.') for d in dic)
df = pd.DataFrame(dic_flattened)

输出:

   id name.english name.french type.0  type.1  base.HP  base.Attack  base.Defense
0   1    Bulbasaur  Bulbizarre  Grass  Poison       45           49            49
1   2      Ivysaur  Herbizarre  Grass  Poison       60           62            63