如何在Pandas中聚合datetime64[ns]与float类型列的DataFrame
Pandas按选手分组聚合比赛时间与名次统计
原始数据
| racer | race_time_1 | race_time_2 | 1st_Place | 2nd_Place |
|---|---|---|---|---|
| joe shmo | 0:24:12 | NaN | 1 | 0 |
| joe shmo | NaN | 0:32:43 | 0 | 0 |
| joe shmo | NaN | 0:30:21 | 0 | 1 |
| sally sue | NaN | 0:29:54 | 1 | 0 |
需求
按racer字段分组,汇总每个选手的:
race_time_1:保留唯一的非空时长race_time_2:所有有效时长的总和1st_Place/2nd_Place:获得对应名次的总次数
期望结果:
| racer | race_time_1 | race_time_2 | 1st_Place | 2nd_Place |
|---|---|---|---|---|
| joe shmo | 0:24:12 | 1:03:04 | 1 | 1 |
| sally sue | NaN | 0:29:54 | 1 | 0 |
问题分析
直接使用df.groupby('racer').agg('sum')会因列类型不匹配报错:
- 初始列均为
object类型,无法直接聚合数值和时长 - 转
race_time为datetime64[ns](时间点类型)不适合时长统计,且分组时会被自动丢弃 - 单独转名次列为数值类型,会导致时间列丢失
解决方案
1. 转换列类型
将时间列转为**时间差(timedelta)**类型(适合时长计算),名次列转为整数类型:
import pandas as pd # 转换时间列为timedelta df['race_time_1'] = pd.to_timedelta(df['race_time_1']) df['race_time_2'] = pd.to_timedelta(df['race_time_2']) # 转换名次列为整数 df['1st_Place'] = df['1st_Place'].astype(int) df['2nd_Place'] = df['2nd_Place'].astype(int)
2. 指定分组聚合规则
针对不同列的需求设置对应的聚合函数:
# 定义各列的聚合逻辑 agg_rules = { # race_time_1取第一个非空值,无数据则返回空 'race_time_1': lambda x: x.dropna().iloc[0] if not x.dropna().empty else pd.NaT, # race_time_2求和所有有效时长 'race_time_2': 'sum', # 名次列统计总次数 '1st_Place': 'sum', '2nd_Place': 'sum' } # 分组聚合,保留racer作为列而非索引 result_df = df.groupby('racer', as_index=False).agg(agg_rules)
3. 转换时间差为可读格式(可选)
将timedelta类型转为HH:MM:SS格式的字符串,方便展示:
def timedelta_to_str(td): if pd.isna(td): return None total_sec = int(td.total_seconds()) hours = total_sec // 3600 mins = (total_sec % 3600) // 60 secs = total_sec % 60 return f"{hours}:{mins:02d}:{secs:02d}" # 应用格式转换 result_df['race_time_1'] = result_df['race_time_1'].apply(timedelta_to_str) result_df['race_time_2'] = result_df['race_time_2'].apply(timedelta_to_str)
运行后即可得到符合预期的聚合结果。
内容的提问来源于stack exchange,提问作者ForyinOuroboros
相关产品推荐
相关产品推荐

