Flatten a column with value of type list while duplicating the other column's value accordingly in Pandas
I guess easies way to flatten list of lists would be a pure python code, as this object type is not well suited for pandas or numpy. So you can do it with for example
>>> b_flat = pd.DataFrame([[i, x]
... for i, y in input['B'].apply(list).iteritems()
... for x in y], columns=list('IB'))
>>> b_flat = b_flat.set_index('I')
Having B column flattened, you can merge it back:
>>> input[['A']].merge(b_flat, left_index=True, right_index=True)
A B
0 1 a
0 1 b
1 2 c
[3 rows x 2 columns]
If you want the index to be recreated, as in your expected result, you can add .reset_index(drop=True)
to last command.
It is surprising that there isn't a more "native" solution. Putting the answer from @alko into a function is easy enough:
def unnest(df, col, reset_index=False):
import pandas as pd
col_flat = pd.DataFrame([[i, x]
for i, y in df[col].apply(list).iteritems()
for x in y], columns=['I', col])
col_flat = col_flat.set_index('I')
df = df.drop(col, 1)
df = df.merge(col_flat, left_index=True, right_index=True)
if reset_index:
df = df.reset_index(drop=True)
return df
Then simply
input = pd.DataFrame({'A': [1, 2], 'B': [['a', 'b'], 'c']})
expected = unnest(input, 'B')
I guess it would be nice to allow unnesting of multiple columns at once and to handle the possibility of a nested column named I
, which would break this code.
A slightly simpler / more readable solution than the ones above which worked for me.
out = []
for n, row in df.iterrows():
for item in row['B']:
row['flat_B'] = item
out += [row.copy()]
flattened_df = pd.DataFrame(out)