按固定时间间隔统计Pandas DataFrame行数及占比
问题描述
我有如下Pandas DataFrame:
| id | entry_time | other_columns |
|---|---|---|
| 1 | 16:02:04 | other_values |
| 2 | 15:02:04 | other_values |
| 3 | 10:32:04 | other_values |
| 4 | 21:22:44 | other_values |
| 5 | 09:02:04 | other_values |
| 6 | 11:02:04 | other_values |
需要根据entry_time字段,按指定的3小时时间间隔统计各区间内的行数,同时为统计出的count列添加保留两位小数的占比(percentage)列,期望输出格式如下:
| time_slot | count | percentage |
|---|---|---|
| 00:00-03:00 | 0 | 0.00 |
| 03:00-06:00 | 0 | 0.00 |
| 06:00-09:00 | 0 | 0.00 |
| 09:00-12:00 | 3 | 50.00 |
| 12:00-15:00 | 0 | 0.00 |
| 15:00-18:00 | 2 | 33.33 |
| 18:00-21:00 | 0 | 0.00 |
| 21:00-00:00 | 1 | 16.67 |
解决方案
通过以下步骤实现需求:
- 转换时间格式:将
entry_time转为datetime类型,便于时间区间处理 - 定义时间区间:创建指定的3小时时间槽列表及对应边界
- 统计区间行数:用
pd.cut分配数据到对应区间,确保所有指定区间都被保留(包括计数为0的) - 计算占比:基于总数据量计算各区间占比并保留两位小数
完整代码如下:
import pandas as pd # 初始化原始DataFrame data = { 'id': [1, 2, 3, 4, 5, 6], 'entry_time': ['16:02:04', '15:02:04', '10:32:04', '21:22:44', '09:02:04', '11:02:04'], 'other_columns': ['other_values']*6 } df = pd.DataFrame(data) # 将entry_time转换为datetime类型(仅保留时间部分) df['entry_time'] = pd.to_datetime(df['entry_time'], format='%H:%M:%S').dt.time # 定义时间槽和对应的区间边界 time_slots = [ '00:00-03:00', '03:00-06:00', '06:00-09:00', '09:00-12:00', '12:00-15:00', '15:00-18:00', '18:00-21:00', '21:00-00:00' ] # 转换边界为datetime对象 bins = pd.to_datetime([ '00:00:00', '03:00:00', '06:00:00', '09:00:00', '12:00:00', '15:00:00', '18:00:00', '21:00:00', '23:59:59' ]) # 为每条数据分配对应时间槽 df['time_slot'] = pd.cut( pd.to_datetime(df['entry_time'], format='%H:%M:%S'), bins=bins, labels=time_slots[:-1], include_lowest=True ) # 单独处理21:00到次日00:00的区间 df.loc[ pd.to_datetime(df['entry_time'], format='%H:%M:%S') >= pd.to_datetime('21:00:00'), 'time_slot' ] = time_slots[-1] # 统计各时间槽行数,确保所有指定时间槽都被保留 count_df = pd.DataFrame({'time_slot': time_slots}).merge( df.groupby('time_slot', dropna=False).size().reset_index(name='count'), on='time_slot', how='left' ).fillna(0) # 计算占比并保留两位小数 total = count_df['count'].sum() count_df['percentage'] = (count_df['count'] / total * 100).round(2) # 输出结果 print(count_df)
运行结果
time_slot count percentage 0 00:00-03:00 0.0 0.00 1 03:00-06:00 0.0 0.00 2 06:00-09:00 0.0 0.00 3 09:00-12:00 3.0 50.00 4 12:00-15:00 0.0 0.00 5 15:00-18:00 2.0 33.33 6 18:00-21:00 0.0 0.00 7 21:00-00:00 1.0 16.67
内容的提问来源于stack exchange,提问作者Carola
相关产品推荐
相关产品推荐

