Pandas DataFrame含NaN时拆分多字符串列为多行的问题
解决DataFrame多列按分隔符拆分为多行的问题
问题场景
现有如下示例DataFrame:
| track_id | track_date | status | status_info |
|---|---|---|---|
| track_1 | 2021-01-01 | approved | None |
| track_2 | 2021-01-02 | None | accredited |
| track_3 | 2021-01-03 | approved | accredited |
| track_4 | 2021-01-04 | approved | approved |
| track_5 | 2021-01-05 | approved|approved | accredited|cancelled |
| track_6 | 2021-01-06 | None | accredited|cancelled |
需要将status和status_info两列按|拆分为多行,得到如下预期结果:
| track_id | track_date | status | status_info |
|---|---|---|---|
| track_1 | 2021-01-01 | approved | None |
| track_2 | 2021-01-02 | None | accredited |
| track_3 | 2021-01-03 | approved | accredited |
| track_4 | 2021-01-04 | approved | approved |
| track_5 | 2021-01-05 | approved | accredited |
| track_5 | 2021-01-05 | approved | cancelled |
| track_6 | 2021-01-06 | None | accredited |
| track_6 | 2021-01-06 | None | cancelled |
原代码错误分析
你尝试的代码报错ValueError: cannot reindex from a duplicate axis,核心原因是拆分后两列的元素数量不一致:
- 比如
track_6的status拆分为1个元素,status_info拆分为2个元素,导致new_status和new_status_info的索引匹配失败,concat时无法对齐行数据。
正确实现方法
方法1:对齐列表长度后使用explode
先将两列拆分为列表,对齐每行两个列表的长度(短列表重复元素补全),再通过explode拆分多行:
import pandas as pd # 构造示例DataFrame data = { 'track_id': ['track_1', 'track_2', 'track_3', 'track_4', 'track_5', 'track_6'], 'track_date': ['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', '2021-01-05', '2021-01-06'], 'status': ['approved', 'None', 'approved', 'approved', 'approved|approved', 'None'], 'status_info': ['None', 'accredited', 'accredited', 'approved', 'accredited|cancelled', 'accredited|cancelled'] } df = pd.DataFrame(data) # 1. 将列拆分为列表 df['status'] = df['status'].str.split('|') df['status_info'] = df['status_info'].str.split('|') # 2. 对齐每行两个列表的长度 def align_list_length(row): status_len = len(row['status']) info_len = len(row['status_info']) if status_len < info_len: row['status'] = row['status'] * info_len elif info_len < status_len: row['status_info'] = row['status_info'] * status_len return row df = df.apply(align_list_length, axis=1) # 3. 拆分多行并重置索引 df = df.explode(['status', 'status_info'], ignore_index=True) # 可选:将字符串'None'转为实际的None值 df = df.replace('None', None) print(df)
方法2:使用stack+merge(适合复杂场景)
通过保留原始索引,拆分后按索引合并:
import pandas as pd df = pd.DataFrame(data) # 拆分status并保留原始索引 status_split = df['status'].str.split('|', expand=True).stack().reset_index(level=1, drop=True).rename('status') # 拆分status_info并保留原始索引 info_split = df['status_info'].str.split('|', expand=True).stack().reset_index(level=1, drop=True).rename('status_info') # 按原始索引合并,自动补全缺失值 split_df = pd.merge(status_split, info_split, left_index=True, right_index=True, how='outer') # 合并回原数据 result = df.drop(['status', 'status_info'], axis=1).join(split_df).reset_index(drop=True) result = result.replace('None', None) print(result)
两种方法都能得到预期的输出结果,方法1更直观易读,适合大多数场景。
内容的提问来源于stack exchange,提问作者anajbellini
相关产品推荐
相关产品推荐

