如何将宽格式的Pandas DataFrame转换为长格式
如何将宽格式的Pandas DataFrame转换为长格式
嗨,我来帮你搞定这个格式转换的问题~你的DataFrame列名其实有很清晰的规律:f_proba_*和p_proba_*的后缀数字就是学生ID,这种场景下用Pandas的wide_to_long函数会比你尝试的普通melt更直接高效,而且能一步得到你想要的结果。
先说说你之前的melt为什么没成功:普通melt是把所有指定的value_vars转成一列值,但你试图把value_name设为两个列,这不符合它的使用逻辑,所以会出错。而我们的需求是两组变量(f_proba和p_proba)对应同一个分组键(Student_ID),wide_to_long就是专门为这种带前缀-后缀的宽表设计的工具。
解决方案代码
直接上可以运行的完整代码:
import pandas as pd # 你的原始宽表 df = pd.DataFrame({'Class_ID': {0: 432, 1: 493, 2: 32}, 'f_proba_1': {0: 3, 1: 8, 2: 6}, 'f_proba_2': {0: 4, 1: 9, 2: 9}, 'f_proba_3': {0: 2, 1: 4, 2: 1}, 'p_proba_1': {0: 3, 1: 82, 2: 36}, 'p_proba_2': {0: 2, 1: 92, 2: 96}, 'p_proba_3': {0: 8, 1: 41, 2: 18}, 'Meeting_ID': {0: 27, 1: 23, 2: 21}}) # 使用wide_to_long转换为长表 long_df = pd.wide_to_long( df, stubnames=['f_proba', 'p_proba'], # 列名的前缀部分 i=['Class_ID', 'Meeting_ID'], # 不需要转换的标识列 j='Student_ID', # 后缀对应的新列名 sep='_', # 前缀和后缀的分隔符 suffix=r'\d+' # 匹配数字后缀的正则 ) # 重置索引,把Student_ID从索引移到普通列 long_df = long_df.reset_index() print(long_df)
转换后的结果
运行后会得到你期望的长格式DataFrame:
Class_ID Meeting_ID Student_ID f_proba p_proba 0 432 27 1 3 3 1 432 27 2 4 2 2 432 27 3 2 8 3 493 23 1 8 82 4 493 23 2 9 92 5 493 23 3 4 41 6 32 21 1 6 36 7 32 21 2 9 96 8 32 21 3 1 18
参数简单解释
stubnames:指定要转换的列的公共前缀,这里就是f_proba和p_proba,后面跟着的是作为分组键的后缀。i:设置转换过程中保持不变的标识列,也就是每个长表行的所属分组。j:给后缀部分指定一个新列名,这里就是学生ID。sep:列名中分隔前缀和后缀的字符,我们的列名用下划线_分隔,所以填'_'。suffix:用正则匹配后缀的格式,r'\d+'表示匹配一个或多个数字,正好对应我们的1、2、3。
如果你一定要用melt的话(可选)
如果你想坚持用melt实现,也可以分两步处理f和p的列,再合并,不过会麻烦一些:
# 处理f_proba列 f_melt = df.melt( id_vars=['Class_ID', 'Meeting_ID'], value_vars=['f_proba_1', 'f_proba_2', 'f_proba_3'], var_name='Student_ID', value_name='f_proba' ) f_melt['Student_ID'] = f_melt['Student_ID'].str.extract(r'(\d+)').astype(int) # 处理p_proba列 p_melt = df.melt( id_vars=['Class_ID', 'Meeting_ID'], value_vars=['p_proba_1', 'p_proba_2', 'p_proba_3'], var_name='Student_ID', value_name='p_proba' ) p_melt['Student_ID'] = p_melt['Student_ID'].str.extract(r'(\d+)').astype(int) # 合并两个结果 long_df = pd.merge(f_melt, p_melt, on=['Class_ID', 'Meeting_ID', 'Student_ID'])
不过显然wide_to_long更适配你的场景,代码更简洁高效~
备注:内容来源于stack exchange,提问作者Apook
相关产品推荐
相关产品推荐

