将 Pandas DataFrame 行分成相似的 time-based 组

Dividing Pandas DataFrame rows into similar time-based groups

我有一个包含马拉松比赛结果的 DataFrame,其中每一行代表一个跑步者,列包括像 "Start Time" (timedelta)、"Net Time" (timedelta) 和 Place (int) 这样的数据).开始时间与净时间的散点图可以很容易地直观地识别比赛中不同的起跑区(预赛):

我想分别分析每个热量,但我不知道如何划分它们。大约有20,000名参赛者参加比赛。开始时间间隔不一致,给定畜栏中的跑步者数量也不一致

我用来组织数据的代码要点: https://gist.github.com/kellbot/1bab3ae83d7b80ee382a

包含大约 500 个结果的 CSV: https://github.com/kellbot/raceresults/blob/master/Full/B.csv

如果我没理解错的话,您是在寻求一种方法来通过算法将 Start Num 值聚合到不同的 heats 中。这是一个一维 classification/clustering 问题。

一个快速的解决方案是使用众多 Jenks 自然中断脚本之一。我之前用过drewda的版本:

https://gist.github.com/drewda/1299198

通过查看地块,我们知道有 16 场比赛。所以你可以先验 select 类 的数量是 16.

k = jenks.getJenksBreaks(full['Start Num'].tolist(),16)
ax = full.plot(kind='scatter', x='Start Num', y='Net Time Sec', figsize=(15,15))
[plt.axvline(x) for x in k]

从您的示例数据中,我们看到它做得很好,但是观察的稀疏性无法识别最小 Start Num bins 之间的中断:

有很多方法可以做到这一点(包括将 scipy 的 k-means 扔向它),但简单的检查可以清楚地表明两次加热之间至少有 60 秒。所以我们需要做的就是对开始时间进行排序,找到 60 秒的差距,每次我们找到一个差距分配一个新的热号。

这可以使用 diff-compare-cumsum 模式轻松完成:

starts = df["Start Time"].copy()
starts.sort()
dt = starts.diff()
heat = (dt > pd.Timedelta(seconds=60)).cumsum()
heat = heat.sort_index()

正确选择了 16 个(表观)组,此处按热号着色: