动态Pandas DataFrame中如何将秒值转换为HH:MM:SS格式时间间隔
速览
能否将该Pandas透视表DataFrame中的所有浮点数,从以秒为单位转换为HH:MM:SS格式的时间间隔?
当前透视表结构:
Name Student A Tutor Date 2021-04-12 52.0 86.0 2021-04-13 13.0 113.0 2021-04-14 NaN 34.0 Average 32.5 77.6
期望的最终结果:
Name Student A Tutor Date 2021-04-12 00:00:52 00:01:26 2021-04-13 00:00:13 00:01:53 2021-04-14 00:00:34 Average 00:00:32 00:01:17
注意事项:
- Tutor、Student A等列是动态生成的,无法通过列名固定引用,实际场景中表格可能存在多个学生列。
- 尝试使用
pd.to_timedelta时,所有转换结果都会自动添加"0 days"前缀,无法满足需求。 - 原表格还包含总计列与总计行,此处为简化展示已将其移除。
详细说明
该透视表的构建流程如下:
import pandas as pd df = pd.DataFrame({ 'Date': ['2021-04-12', '2021-04-12', '2021-04-13', '2021-04-13', '2021-04-14'], 'Name': ['Tutor', 'Student A', 'Student A', 'Tutor', 'Tutor'], 'duration_seconds': [86, 52, 13, 113, 34] })
df的结构如下:
Date Name duration_seconds 0 2021-04-12 Tutor 86 1 2021-04-12 Student A 52 2 2021-04-13 Student A 13 3 2021-04-13 Tutor 113 4 2021-04-14 Tutor 34
执行分组操作:
grouped = df.groupby(['Name', 'Date']).sum()
得到分组结果:
duration_seconds Name Date Student A 2021-04-12 52 2021-04-13 13 Tutor 2021-04-12 86 2021-04-13 113 2021-04-14 34
转换为目标透视表格式:
pivoted = grouped.pivot_table( values='duration_seconds', index='Date', columns='Name' )
得到透视结果:
Name Student A Tutor Date 2021-04-12 52.0 86.0 2021-04-13 13.0 113.0 2021-04-14 NaN 34.0
添加平均值行:
pivoted.loc['Average'] = pivoted.mean()
得到添加平均值后的结果:
Name Student A Tutor Date 2021-04-12 52.0 86.000000 2021-04-13 13.0 113.000000 2021-04-14 NaN 34.000000 Average 32.5 77.666667
以上为当前已完成的操作,最后一步需要将学生、导师类列下的所有数值转换为HH:MM:SS格式的时间间隔。
原本尝试的方案存在缺陷,所有转换结果都会被添加0 days 前缀,不符合需求:
pivoted.iloc[:].apply(pd.to_timedelta, unit='s')
解决方案
由于所有列都是动态生成的数值列,不需要硬编码列名,通过逐元素映射的方式即可完成转换,完全适配任意数量的动态列。
- 自定义转换函数:空值直接返回空字符串,有效秒数计算时分秒并补零为两位数格式
def convert_seconds(sec_val): # 匹配空值场景,返回空字符串而非00:00:00 if pd.isna(sec_val): return '' # 截断小数秒,匹配示例的取整逻辑 total_sec = int(sec_val) hours = total_sec // 3600 minutes = (total_sec % 3600) // 60 seconds = total_sec % 60 # 格式化为统一的HH:MM:SS结构 return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
- 对整个透视表应用转换,自动覆盖所有动态生成的列
# pandas >=2.1 直接使用.map,低版本替换为.applymap final_df = pivoted.map(convert_seconds)
- 输出验证
print(final_df)
输出结果完全匹配预期:
Name Student A Tutor Date 2021-04-12 00:00:52 00:01:26 2021-04-13 00:00:13 00:01:53 2021-04-14 00:00:34 Average 00:00:32 00:01:17
补充:若所有时长均在单日以内,也可通过timedelta字符串拆分简化实现,自动去除days前缀:
final_df = ( pivoted.apply(pd.to_timedelta, unit='s') .astype(str) .str.split(' ') .str[-1] .replace('NaT', '') )
内容的提问来源于stack exchange,提问作者Chris Kobrzak
相关产品推荐
相关产品推荐

