如何合并DataFrame中同类列至单行并复用student_id与date字段?
解决方案:将宽格式DataFrame转换为长格式
你的需求是把带有measure.N、level.N后缀的宽表,转成每行对应一组measure/level,同时保留student_id和date,这是典型的宽表转长表场景,用pandas可以轻松实现,下面提供两种实用方法:
方法一:用pd.wide_to_long(推荐,适合列名有规律的情况)
这个方法专门针对带后缀的重复列设计,代码简洁高效:
import pandas as pd # 构造和你结构一致的示例数据(替换成你的真实DataFrame即可) data = { 'student_id': [804322, 3424234, 2132121], 'date': ['9/2/2022', '9/3/2023', '4/5/2022'], 'measure': ['some string', 'some string', 'some string'], 'level': ['more string', 'more string', 'more string'], 'measure.1': ['some string', 'some string', 'some string'], 'level.1': ['more string', 'more string', 'more string'], 'measure.2': ['some string', 'some string', 'some string'], 'level.2': ['more string', 'more string', 'more string'] } df = pd.DataFrame(data) # 执行宽转长操作 df_long = pd.wide_to_long( df, stubnames=['measure', 'level'], # 指定列名的前缀 i=['student_id', 'date'], # 需要保留的唯一标识列 j='group', # 新增列:用来区分原有的不同组(可选,不需要可以后续删除) sep='.', # 列名中前缀和后缀的分隔符 suffix=r'\d+' # 匹配后缀的正则表达式,这里表示数字 ).reset_index() # 如果不需要group列,直接删除即可 df_long = df_long.drop(columns='group')
执行后,df_long的结构就是你想要的:每行对应一个student_id、date、measure、level,所有measure、measure.1、measure.2...的内容都合并到measure列,level列同理。
方法二:用pd.melt(灵活适配不规则列名)
如果你的列名后缀不太规则,或者需要更灵活的处理,可以用melt分别处理measure和level列,再合并:
import pandas as pd # 构造示例数据(同上) data = { 'student_id': [804322, 3424234, 2132121], 'date': ['9/2/2022', '9/3/2023', '4/5/2022'], 'measure': ['some string', 'some string', 'some string'], 'level': ['more string', 'more string', 'more string'], 'measure.1': ['some string', 'some string', 'some string'], 'level.1': ['more string', 'more string', 'more string'], 'measure.2': ['some string', 'some string', 'some string'], 'level.2': ['more string', 'more string', 'more string'] } df = pd.DataFrame(data) # 提取需要保留的标识列,以及所有measure、level相关列 id_vars = ['student_id', 'date'] measure_cols = [col for col in df.columns if 'measure' in col] level_cols = [col for col in df.columns if 'level' in col] # 分别对measure和level列做melt操作 df_measure = pd.melt(df, id_vars=id_vars, value_vars=measure_cols, value_name='measure') df_level = pd.melt(df, id_vars=id_vars, value_vars=level_cols, value_name='level') # 提取每组的编号,保证measure和level的对应关系 df_measure['group'] = df_measure['variable'].str.extract(r'(\d+)').fillna(0).astype(int) df_level['group'] = df_level['variable'].str.extract(r'(\d+)').fillna(0).astype(int) # 合并两个结果,得到最终长表 df_long = pd.merge(df_measure, df_level, on=['student_id', 'date', 'group']) # 删除不需要的中间列 df_long = df_long.drop(columns=['variable_x', 'variable_y', 'group'])
验证结果
转换后的df_long示例输出大致如下:
| student_id | date | measure | level |
|---|---|---|---|
| 804322 | 9/2/2022 | some string | more string |
| 804322 | 9/2/2022 | some string | more string |
| 804322 | 9/2/2022 | some string | more string |
| 3424234 | 9/3/2023 | some string | more string |
| ... | ... | ... | ... |
内容的提问来源于stack exchange,提问作者Andrew Smith
相关产品推荐
相关产品推荐

