Я смог ответить на мой вопрос с помощью подсказки @ roganjosh.Вот решение, которое я в итоге использовал:
city_data = {
'San Francisco': {'x': [1, 2, 3], 'y': [4, 1, 2]},
'Montreal': {'x': [1, 2, 3], 'y': [2, 4, 5]},
'New York City': {'x': [1, 2, 3], 'y': [2, 2, 7]},
'Cincinnati': {'x': [1, 2, 3], 'y': [1, 0, 2]},
'Toronto': {'x': [1, 2, 3], 'y': [4, 7, 3]},
'Ottawa': {'x': [1, 2, 3], 'y': [2, 3, 3]}
}
## Prepare my data
data = []
for city in city_data:
data.append({'x': city_data[city]['x'], 'y': city_data[city]['y'],
'city': city})
### use function from linked SO question
def explode(df, lst_cols, fill_value='', preserve_index=False):
# make sure `lst_cols` is list-alike
if (lst_cols is not None
and len(lst_cols) > 0
and not isinstance(lst_cols, (list, tuple, np.ndarray, pd.Series))):
lst_cols = [lst_cols]
# all columns except `lst_cols`
idx_cols = df.columns.difference(lst_cols)
# calculate lengths of lists
lens = df[lst_cols[0]].str.len()
# preserve original index values
idx = np.repeat(df.index.values, lens)
# create "exploded" DF
res = (pd.DataFrame({
col:np.repeat(df[col].values, lens)
for col in idx_cols},
index=idx)
.assign(**{col:np.concatenate(df.loc[lens>0, col].values)
for col in lst_cols}))
# append those rows that have empty lists
if (lens == 0).any():
# at least one list in cells is empty
res = (res.append(df.loc[lens==0, idx_cols], sort=False)
.fillna(fill_value))
# revert the original index order
res = res.sort_index()
# reset index if requested
if not preserve_index:
res = res.reset_index(drop=True)
return res
df = pd.DataFrame(data)
df = explode(df, ['x','y'], fill_value='')
Вывод:
city x y
0 San Francisco 1 4
1 San Francisco 2 1
2 San Francisco 3 2
3 Montreal 1 2
4 Montreal 2 4
Хотя это довольно подробный код, я был бы рад, если бы кто-то мог поделиться более краткимспособ решения этой проблемы.