Another (similar) approach that works regardless of the list lengths, update the dataframe, and also handles the column names automatically in one-step:
col = 'b' # your target column
df.join(pd.DataFrame(df[col].tolist()).rename(columns=lambda x: col+str(x+1))).drop(col, 1)
Output:
a b1 b2 b3
0 jon (age, 12) (gender, 1) (marital, 1)
1 san (age, 34) (gender, 1) (marital, 2)
2 el (age, 14) (gender, 2) (marital, 1)
To make it scalable to other column as well, wrap it into a function like this:
def split_columns(df, cols):
for col in cols:
df = df.join(pd.DataFrame(df[col].tolist()).rename(columns=lambda x: col+str(x+1))).drop(col, 1)
return df
Example:
# Original tested data
df = pd.DataFrame({
'a': ['jon','san','el'],
'b': [[('age',12), ('gender',1), ('marital',1)],
[('age',34), ('gender',1), ('marital',2)],
[('age',14), ('gender',2), ('marital',1)]]
})
# Add further info for testing
df['c'] = df['b'] # create another column for testing
df.iloc[-1, -1] = [('age', 14)] # test with a list of length = 1
print(df.to_markdown())
| | a | b | c |
|---:|:----|:---------------------------------------------|:---------------------------------------------|
| 0 | jon | [('age', 12), ('gender', 1), ('marital', 1)] | [('age', 12), ('gender', 1), ('marital', 1)] |
| 1 | san | [('age', 34), ('gender', 1), ('marital', 2)] | [('age', 34), ('gender', 1), ('marital', 2)] |
| 2 | el | [('age', 14), ('gender', 2), ('marital', 1)] | [('age', 14)] |
then, a calling like split_columns(df, ['b','c'])
returns:
| | a | b1 | b2 | b3 | c1 | c2 | c3 |
|---:|:----|:------------|:--------------|:---------------|:------------|:--------------|:---------------|
| 0 | jon | ('age', 12) | ('gender', 1) | ('marital', 1) | ('age', 12) | ('gender', 1) | ('marital', 1) |
| 1 | san | ('age', 34) | ('gender', 1) | ('marital', 2) | ('age', 34) | ('gender', 1) | ('marital', 2) |
| 2 | el | ('age', 14) | ('gender', 2) | ('marital', 1) | ('age', 14) | | |