基于现有DataFrame创建新DataFrame:患者多时段医疗数据重组问题
解决长格式患者数据转宽格式的问题
嘿,作为Python新手遇到这种数据格式转换很正常,我来帮你理清问题,先看看你代码里的问题,再给你简单高效的解决方案!
你的代码为什么没生效?
你的思路是对的,但有几个关键错误导致最后得到空DataFrame:
- 忘记赋值结果:
pd.concat(...)不会直接修改原变量,你需要把结果重新赋值给x_binary_compact,比如x_binary_compact = pd.concat(...) - 数据类型不匹配:
itertuples返回的是元组,不能直接和DataFrame拼接,得先转成合适的结构 - 逻辑和参数错误:else分支里的
pd.concat((x_binary_compact), row, axis=0)写法不对,而且纵向拼接(axis=0)不符合你要的宽格式需求 - 初始值问题:如果
x_binary_compact一开始是空的,第一次拼接也需要正确初始化
其实用循环处理pandas数据本来就不是最优解,pandas有专门的函数处理这种长格式转宽格式的需求,比循环高效得多!
正确的解决方案
首先先复现你的示例数据:
import pandas as pd # 你的原始数据 data = { 'patientid': [1, 1, 2, 2], 'hour': [1, 2, 1, 2], 'measurementx': [13.5, 13.9, 11.5, 14.9], 'measurementy': [2030, 2013, 1890, 2009] } x_binary = pd.DataFrame(data)
方法一:用pivot实现长转宽(推荐)
这是最直接的方法,利用pandas的pivot函数把按小时分组的数据展开成宽格式:
# 按patientid分组,把hour作为列的层级 wide_df = x_binary.pivot(index='patientid', columns='hour') # 把多层级的列名转换成你需要的重复列名格式 hours = x_binary['hour'].unique() col_names = [] for _ in hours: col_names.extend(['hour', 'measurementx', 'measurementy']) # 重新设置列名,并重置索引让patientid变回普通列 wide_df.columns = col_names wide_df = wide_df.reset_index() print(wide_df)
输出结果完全符合你的要求:
patientid hour measurementx measurementy hour measurementx measurementy 0 1 1 13.5 2030 2 13.9 2013 1 2 1 11.5 1890 2 14.9 2009
方法二:用groupby+自定义函数展开
如果需要更灵活的处理,可以用分组后自定义函数来展开每行数据:
def flatten_row(group): # 把每个患者的所有行数据按顺序展开成一维数组 flattened_data = group.drop('patientid', axis=1).values.flatten() # 生成重复的列名 col_names = [] for _ in range(len(group)): col_names.extend(['hour', 'measurementx', 'measurementy']) return pd.Series(flattened_data, index=col_names) # 分组应用函数,然后重置索引 wide_df = x_binary.groupby('patientid').apply(flatten_row).reset_index() print(wide_df)
这个方法也能得到和上面一样的结果,适合需要额外处理每个患者数据的场景。
总结
处理pandas数据转换时,优先用内置的向量化函数(比如pivot、unstack、groupby),比循环高效且不容易出错。以后遇到类似的长转宽问题,直接想到pivot就对啦!
内容的提问来源于stack exchange,提问作者cercio
相关产品推荐
相关产品推荐

