如何在Python中将列值转为新列?DataFrame数据重塑求助
问题:DataFrame 重塑与列移位实现需求
我有如下格式的DataFrame数据:
import pandas as pd data = { 'accident_type': [1,1,1,2,2,2,3,3,3], 'office A': [0,0,0,0,0,0,0,0,0], 'office B': [0,2,0,0,0,0,0,1,0], 'office C': [0,2,0,1,1,0,0,1,0], 'information': ['number','fatality','frequency','number','fatality','frequency','number','fatality','frequency'] } df = pd.DataFrame(data)
原始数据预览:
| accident_type | office A | office B | office C | information |
|---|---|---|---|---|
| 1 | 0 | 0 | 0 | number |
| 1 | 0 | 2 | 2 | fatality |
| 1 | 0 | 0 | 0 | frequency |
| 2 | 0 | 0 | 1 | number |
| 2 | 0 | 0 | 1 | fatality |
| 2 | 0 | 0 | 0 | frequency |
| 3 | 0 | 0 | 0 | number |
| 3 | 0 | 1 | 1 | fatality |
| 3 | 0 | 0 | 0 | frequency |
我希望实现两个核心操作:
- 新增列将事故信息值纵向移位,得到
office列(对应office A/office B/office C循环) - 删除原有的
office A/office B/office C列,将这三列的值转换为number/fatality/frequency列,最终得到如下结果:
| accident_type | information | office | number | fatality | frequency |
|---|---|---|---|---|---|
| 1 | number | office A | 0 | 0 | 0 |
| 1 | fatality | office B | 0 | 2 | 0 |
| 1 | frequency | office C | 0 | 2 | 0 |
| 2 | number | office A | 0 | 0 | 0 |
| 2 | fatality | office B | 0 | 0 | 0 |
| 2 | frequency | office C | 1 | 1 | 0 |
| 3 | number | office A | 0 | 0 | 0 |
| 3 | fatality | office B | 0 | 1 | 0 |
| 3 | frequency | office C | 0 | 1 | 0 |
我尝试使用df.melt但未得到预期结果,请问如何用Python实现该需求?
解决方案
这个需求的核心是给每个事故类型分组内的行分配对应office,再将原office列的值按信息类别重新映射,可以通过以下步骤实现:
步骤1:为每行分配对应的office列
观察到每个accident_type下固定有3行,正好对应office A/office B/office C,我们可以按事故类型分组后,给每组的行循环分配这三个值:
# 定义要循环的office列表 office_list = ['office A', 'office B', 'office C'] # 按accident_type分组,给每组的行按顺序分配office值 df['office'] = df.groupby('accident_type').cumcount().map(lambda x: office_list[x])
步骤2:构建office与信息值的映射表
我们需要把原数据中每个(事故类型, office)对应的number/fatality/frequency值提取出来,这里用pivot_table结合多层索引转置来实现:
# 先按事故类型和信息类型做透视,再转置索引得到office对应的各信息值 map_df = df.pivot_table( index=['accident_type', 'information'], values=['office A', 'office B', 'office C'], aggfunc='first' ).unstack('information').stack(0).reset_index() # 调整列名到我们需要的格式 map_df.columns = ['accident_type', 'office', 'number', 'fatality', 'frequency']
步骤3:合并得到最终结果
最后把原始数据的information列和映射表合并,调整列顺序就得到目标格式:
# 保留原始数据的核心列 df_base = df[['accident_type', 'information', 'office']] # 合并核心列和映射表 final_df = df_base.merge(map_df, on=['accident_type', 'office']) # 调整列顺序和目标一致 final_df = final_df[['accident_type', 'information', 'office', 'number', 'fatality', 'frequency']]
完整简化版代码
把上面的逻辑整合起来,直接运行就能得到结果:
import pandas as pd data = { 'accident_type': [1,1,1,2,2,2,3,3,3], 'office A': [0,0,0,0,0,0,0,0,0], 'office B': [0,2,0,0,0,0,0,1,0], 'office C': [0,2,0,1,1,0,0,1,0], 'information': ['number','fatality','frequency','number','fatality','frequency','number','fatality','frequency'] } df = pd.DataFrame(data) # 1. 添加office列 office_list = ['office A', 'office B', 'office C'] df['office'] = df.groupby('accident_type').cumcount().map(dict(enumerate(office_list))) # 2. 构建映射表 map_df = df.pivot_table( index=['accident_type', 'information'], values=['office A', 'office B', 'office C'], aggfunc='first' ).unstack('information').stack(0).reset_index() map_df.columns = ['accident_type', 'office', 'number', 'fatality', 'frequency'] # 3. 合并得到最终结果 final_df = df[['accident_type', 'information', 'office']].merge(map_df, on=['accident_type', 'office']) final_df = final_df[['accident_type', 'information', 'office', 'number', 'fatality', 'frequency']] print(final_df)
这段代码的优势是利用pandas的内置函数处理索引和数据转置,避免了手动循环,效率更高也更易维护。
内容的提问来源于stack exchange,提问作者yangyang
相关产品推荐
相关产品推荐

