使用 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
我有几个包含嵌套数据的 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