Я уже перепробовал все, что здесь написано, но ничего не работает, поэтому, пожалуйста, не отмечайте это как дубликат, потому что я думаю, что проблема в другом.
У меня есть такой json:
[{'Id': 1,
'Design': ["09",
'10',
'13'
],
'Research': ['Eng',
'Math']
}]
Плюс другие столбцы, не входящие в список. Это повторяется для 500 идентификаторов.
Мне нужно разбить столбцы списка. конечным результатом должен быть файл Excel, мне все равно, выполняется ли взрыв непосредственно в json или в pandas.
Уже пробовал:
def lenx(x):
return len(x) if isinstance(x,(list, tuple, np.ndarray, pd.Series)) else 1
def cell_size_equalize2(row, cols='', fill_mode='internal', fill_value=''):
jcols = [j for j,v in enumerate(row.index) if v in cols]
if len(jcols)<1:
jcols = range(len(row.index))
Ls = [lenx(x) for x in row.values]
if not Ls[:-1]==Ls[1:]:
vals = [v if isinstance(v,list) else [v] for v in row.values]
if fill_mode=='external':
vals = [[e] + [fill_value]*(max(Ls)-1) if (not j in jcols) and (isinstance(row.values[j],list))
else e + [fill_value]*(max(Ls)-lenx(e))
for j,e in enumerate(vals)]
elif fill_mode == 'internal':
vals = [[e]+[e]*(max(Ls)-1) if (not j in jcols) and (isinstance(row.values[j],list))
else e+[e[-1]]*(max(Ls)-lenx(e))
for j,e in enumerate(vals)]
else:
vals = [e[0:min(Ls)] for e in vals]
row = pd.Series(vals,index=row.index.tolist())
return row
Приводит к ошибке индекса
df.explode(['B', 'C', 'D', 'E']).reset_index(drop=True)
Столбцы должны иметь одинаковую длину
df1 = pd.concat([df[x].explode().to_frame()
.assign(g=lambda x: x.groupby(level=0).cumcount())
.set_index('g', append=True)
for x in cols_to_explode], axis=1)
Каким-то образом он создает много строк, я думаю, он просто разрывает столбец за другим, и это приводит к ошибке памяти.
Желаемый результат:
Id Design Research
1 09 Eng
1 10 Math
1 13
Вы можете использовать json_normalize и дедупликацию-взрыв (как представлено здесь):
tmp = pd.json_normalize(json)
def explode_dedup(s):
s = s.explode()
return s.set_axis(
pd.MultiIndex.from_arrays([s.index, s.groupby(level=0).cumcount()])
)
ids = ['Id']
cols = tmp.columns.difference(ids)
out = (tmp[ids]
.join(pd.concat({c: explode_dedup(tmp[c])
for c in cols}, axis=1)
.droplevel(-1)
)[tmp.columns]
)
Примечание. если вы знаете, что столбцы должны взорваться, вы можете альтернативно использовать:
cols = ['Design', 'Research']
ids = tmp.columns.difference(cols)
Выход:
Id Design Research
0 1 09 Eng
0 1 10 Math
0 1 13 NaN
import pandas as pd
from pandas.io.json._normalize import json_normalize
import numpy as np
data = [
{
'Id': 1,
'Design': ["09", "10", "13"],
'Research': ['Eng', 'Math']
}
]
# Convert JSON to DataFrame
#df = pd.DataFrame(data)
df = json_normalize(data)
df['Research'] = df['Research'].transform(
lambda x: x + [np.nan] * (len(df['Design'].iloc[0]) - len(x))
)
df = df.explode(['Design','Research'],ignore_index = True)
print(df)
"""
Id Design Research
0 1 09 Eng
1 1 10 Math
2 1 13 NaN
"""
метод 2:
import pandas as pd
from pandas.io.json._normalize import json_normalize
import numpy as np
data = [
{
'Id': 1,
'Design': ["09", "10", "13"],
'Research': ['Eng', 'Math']
}
]
# Convert JSON to DataFrame
#df = pd.DataFrame(data)
df = json_normalize(data)
df_exploded1 = df.explode('Design',ignore_index =True).assign(
Research = lambda x : pd.Series(df['Research'].explode().values)
.reindex(x.index).fillna(np.nan)
)
print(df_exploded1)
'''
Id Design Research
0 1 09 Eng
1 1 10 Math
2 1 13 NaN
'''