如何用Pandas标准化地铁站客流时序数据的时间频率?
补全地铁站时序数据的Pandas解决方案
问题描述
现有不同地铁站的进出站人次时序数据,各站点运营时段如下:
- Station A:00:00-01:00
- Station B:01:00-02:00
- Station C:02:00起运营
初始数据如下:
| Date Time | Station | Entries | Exits |
|---|---|---|---|
| 2023-01-01 00:00:00 | Station A | 1 | 1 |
| 2023-01-01 01:00:00 | Station A | 1 | 1 |
| 2023-01-01 01:00:00 | Station B | 2 | 2 |
| 2023-01-01 02:00:00 | Station B | 2 | 2 |
| 2023-01-01 02:00:00 | Station C | 3 | 3 |
需要补充数据行,使每个小时时段都包含所有站点(共3个)的数据,缺失的Entries和Exits用0填充,目标格式如下:
| Date Time | Station | Entries | Exits |
|---|---|---|---|
| 2023-01-01 00:00:00 | Station A | 1 | 1 |
| 2023-01-01 00:00:00 | Station B | 0 | 0 |
| 2023-01-01 00:00:00 | Station C | 0 | 0 |
| 2023-01-01 01:00:00 | Station A | 1 | 1 |
| 2023-01-01 01:00:00 | Station B | 2 | 2 |
| 2023-01-01 01:00:00 | Station C | 0 | 0 |
| 2023-01-01 02:00:00 | Station A | 0 | 0 |
| 2023-01-01 02:00:00 | Station B | 2 | 2 |
| 2023-01-01 02:00:00 | Station C | 3 | 3 |
初始DataFrame生成代码:
import pandas as pd df = pd.DataFrame( {'Date Time':pd.to_datetime(['2023-01-01 00:00:00', '2023-01-01 01:00:00', '2023-01-01 01:00:00', '2023-01-01 02:00:00', '2023-01-01 02:00:00']), 'Station':['Station A', 'Station A', 'Station B', 'Station B', 'Station C'], 'Entries':[1, 1, 2, 2, 3], 'Exits':[1, 1, 2, 2, 3]} )
此前尝试groupby+resample仅能填补时段间隙,无法补全未运营时段的站点行,以下是可实现需求的Pandas方案:
解决方案
方法1:全量索引重映射(最直接)
核心是生成日期时段+站点的全量笛卡尔积索引,再将原数据映射到这个索引上,缺失值自动填充0。用到的关键函数:pd.MultiIndex.from_product、reindex。
代码实现:
# 提取所有唯一的日期时段和站点 unique_dates = df['Date Time'].unique() unique_stations = df['Station'].unique() # 生成日期与站点的全量组合索引 full_index = pd.MultiIndex.from_product( [unique_dates, unique_stations], names=['Date Time', 'Station'] ) # 将原数据转为多索引格式,重映射到全量索引并填充0 df_full = df.set_index(['Date Time', 'Station'])\ .reindex(full_index, fill_value=0)\ .reset_index() print(df_full)
方法2:透视表+逆透视
先将数据转为宽表(日期为行,站点为列),再逆透视回长表,过程中自动补全所有站点组合。用到的关键函数:pd.pivot_table、pd.melt。
代码实现:
# 透视数据:行=日期,列=站点,值=Entries/Exits,缺失值先填0 pivot_df = pd.pivot_table( df, index='Date Time', columns='Station', values=['Entries', 'Exits'], fill_value=0 ) # 逆透视回长表格式 df_full = pivot_df.unstack().reset_index(name='value')\ .pivot(index=['Date Time', 'Station'], columns='level_0', values='value')\ .reset_index() # 清理列名并排序 df_full.columns.name = None df_full = df_full.sort_values(['Date Time', 'Station']).reset_index(drop=True) print(df_full)
方法3:分组补全站点
对每个日期时段分组,手动补充当前时段缺失的站点数据。用到的关键函数:groupby、apply、pd.merge。
代码实现:
unique_stations = df['Station'].unique() # 定义分组补全函数 def fill_missing_stations(group): # 创建包含所有站点的临时表 all_stations = pd.DataFrame({'Station': unique_stations}) # 合并分组数据,缺失值填0 merged = pd.merge(all_stations, group, on='Station', how='left').fillna(0) # 统一当前分组的日期 merged['Date Time'] = group['Date Time'].iloc[0] # 转换数值类型为整数 merged[['Entries', 'Exits']] = merged[['Entries', 'Exits']].astype(int) return merged # 按日期分组并应用补全函数 df_full = df.groupby('Date Time').apply(fill_missing_stations)\ .reset_index(drop=True) print(df_full)
内容的提问来源于stack exchange,提问作者Paul Song
相关产品推荐
相关产品推荐

