
本教程探讨了如何在pandas dataframe中根据重复的序列模式(例如交通路线中的站点循环)进行数据拆分。文章提供了两种主要方法:一种是利用`groupby`结合累积求和动态识别并分组每个循环,另一种是利用`numpy.array_split`基于唯一停靠点数量进行固定间隔拆分。通过具体示例代码,本文旨在帮助读者高效地将连续数据流分解为独立的、结构化的子dataframe。
在数据分析和处理中,我们经常会遇到需要将一个大型数据集根据其内部的重复模式或周期性结构进行拆分的场景。一个典型的例子是公共交通数据,其中一辆巴士在一天内会重复执行相同的站点序列(例如A->B->C),形成多个独立的行程(或“循环”)。即使不知道每个循环具体包含多少个停靠点,我们仍然希望将原始DataFrame拆分成多个子DataFrame,每个子DataFrame代表一个完整的行程循环。
为了更好地说明这一需求,我们构建一个包含计划时间和停靠站点的Pandas DataFrame:
import pandas as pd
df = pd.DataFrame({
"scheduled": ["2023-05-25 13:00", "2023-05-25 13:15", "2023-05-25 13:45",
"2023-05-25 14:35", "2023-05-25 14:50", "2023-05-25 15:20"],
"stop": ["A", "B", "C", "A", "B", "C"]
})
df["scheduled"] = pd.to_datetime(df["scheduled"])
print("原始DataFrame:")
print(df)输出的DataFrame如下所示,清晰地展示了“A->B->C”的站点序列重复了两次:
原始DataFrame:
scheduled stop
0 2023-05-25 13:00:00 A
1 2023-05-25 13:15:00 B
2 2023-05-25 13:45:00 C
3 2023-05-25 14:35:00 A
4 2023-05-25 14:50:00 B
5 2023-05-25 15:20:00 C我们的目标是将这个DataFrame拆分为两个子DataFrame,每个子DataFrame对应一个完整的“A->B->C”行程。
方法一:利用 groupby 和动态分组标识符
这种方法的核心思想是动态地识别每个循环的起始点,并为每个循环分配一个唯一的组ID。它特别适用于我们不确定每个循环具体有多少个停靠点,但知道循环模式会重复的情况。
实现步骤:
-
识别循环起点: 我们假设每个循环都以相同的停靠点开始(在本例中是“A”)。通过比较 stop 列的当前值与第一个停靠点的值 (df['stop'].iloc[0]),我们可以得到一个布尔序列,其中 True 表示循环的起点。
df['stop'].eq(df['stop'].iloc[0]) # 输出示例: # 0 True # 1 False # 2 False # 3 True # 4 False # 5 False # Name: stop, dtype: bool
-
生成组ID: 对上述布尔序列执行累积求和 (cumsum())。每当遇到 True(即循环起点)时,累积和就会增加1,从而为新的循环分配一个递增的组ID。
group_id = df['stop'].eq(df['stop'].iloc[0]).cumsum() # 输出示例: # 0 1 # 1 1 # 2 1 # 3 2 # 4 2 # 5 2 # Name: stop, dtype: int64
为了更好地理解,我们可以将这个 group_id 列添加到原始DataFrame中作为中间步骤的参考:
df_with_group = df.copy() # 创建副本以避免修改原始df df_with_group['group'] = group_id print("\n带有分组ID的DataFrame:") print(df_with_group)输出结果如下,清晰地展示了每个行程的组ID:
带有分组ID的DataFrame: scheduled stop group 0 2023-05-25 13:00:00 A 1 1 2023-05-25 13:15:00 B 1 2 2023-05-25 13:45:00 C 1 3 2023-05-25 14:35:00 A 2 4 2023-05-25 14:50:00 B 2 5 2023-05-25 15:20:00 C 2 - 使用 groupby 拆分: 最后,使用 groupby() 方法










