You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何生成满足时间间隔约束的datetime序列?

问题:为Pandas DataFrame生成符合规则的单调递增datetime列

给定条件

  • 两个datetime对象与时间范围:
import datetime
start_dt = datetime.datetime(2023, 7, 26, 6, 0, 0)
end_dt = datetime.datetime(2023, 7, 26, 15, 0, 0)
range_of_minutes = range(15, 201) # 15到200分钟之间
  • Pandas DataFrame:
import pandas as pd
df = pd.DataFrame(
    {'item':
     ['XXX01', 'XXX02', 'XXX03', 'XXX04',
      'XXX05', 'XXX06', 'XXX07', 'XXX08', 'XXX09']}
)

需求

为DataFrame添加datetime列,规则如下:

  • 第一个item对应start_dt
  • 从第二个item开始,每个后续item的datetime必须介于start_dt和end_dt之间
  • 相邻item的时间间隔是range_of_minutes内的随机值
  • datetime必须单调递增
  • item数量不固定(可奇可偶)

预期输出示例(仅展示前两列)

item             datetime **datetimes are monotonic and range is respected**
0  XXX01  26/07/2023 06:00:00                           NaN
1  XXX02  26/07/2023 06:17:34                         15,52
2  XXX03  26/07/2023 06:53:55                         36,35
3  XXX04  26/07/2023 08:05:15                         71,33
4  XXX05  26/07/2023 09:54:10                        108,92
5  XXX06  26/07/2023 11:08:20                         74,17
6  XXX07  26/07/2023 11:30:20                            22
7  XXX08  26/07/2023 14:07:05                        156,75
8  XXX09  26/07/2023 14:45:08                         38,05

尝试的代码

import random

def r_interval():
    return random.randint(min(range_of_minutes), max(range_of_minutes))

df.loc[0, "datetime"] = pd.to_datetime(start_dt)

df["datetime"] = pd.to_datetime(start_dt) + [r_interval() + dt.shift() for dt in df["datetime"][1:]]

解决方案

你的代码里dt.shift()用法错误,而且没处理时间不能超过end_dt的限制,下面提供两种可行实现:

方法1:循环生成(直观易懂,适合小数据量)

import datetime
import pandas as pd
import random

start_dt = datetime.datetime(2023, 7, 26, 6, 0, 0)
end_dt = datetime.datetime(2023, 7, 26, 15, 0, 0)
range_of_minutes = range(15, 201)

df = pd.DataFrame(
    {'item':
     ['XXX01', 'XXX02', 'XXX03', 'XXX04',
      'XXX05', 'XXX06', 'XXX07', 'XXX08', 'XXX09']}
)

# 初始化datetime列
df['datetime'] = pd.NaT
df.loc[0, 'datetime'] = start_dt

current_dt = start_dt
# 从第二行开始逐个生成时间
for i in range(1, len(df)):
    # 计算当前到结束还剩多少分钟可用
    remaining_minutes = (end_dt - current_dt).total_seconds() / 60
    # 计算当前允许的最大间隔:不能超过剩余时间,还要给后面的item留够最小间隔
    min_interval = min(range_of_minutes)
    max_interval = min(max(range_of_minutes), remaining_minutes - min_interval * (len(df) - i - 1))
    # 兜底处理:如果剩余时间连最小间隔都不够,强制用最小间隔
    if max_interval < min_interval:
        max_interval = min_interval
    
    interval = random.randint(int(min_interval), int(max_interval))
    current_dt += datetime.timedelta(minutes=interval)
    df.loc[i, 'datetime'] = current_dt

方法2:向量化生成(效率更高,适合大数据量)

import datetime
import pandas as pd
import numpy as np

start_dt = datetime.datetime(2023, 7, 26, 6, 0, 0)
end_dt = datetime.datetime(2023, 7, 26, 15, 0, 0)
range_of_minutes = range(15, 201)

df = pd.DataFrame(
    {'item':
     ['XXX01', 'XXX02', 'XXX03', 'XXX04',
      'XXX05', 'XXX06', 'XXX07', 'XXX08', 'XXX09']}
)

total_allowed_minutes = (end_dt - start_dt).total_seconds() / 60
n_intervals = len(df) - 1

# 先生成初始随机间隔
intervals = np.random.randint(min(range_of_minutes), max(range_of_minutes)+1, size=n_intervals)
# 调整间隔总和,确保不超过允许的总时间,同时保证每个间隔不小于最小值
total_intervals = intervals.sum()
if total_intervals > total_allowed_minutes:
    scale = (total_allowed_minutes - n_intervals * min(range_of_minutes)) / (total_intervals - n_intervals * min(range_of_minutes))
    intervals = (intervals - min(range_of_minutes)) * scale + min(range_of_minutes)
    intervals = np.round(intervals).astype(int)

# 计算累计间隔,生成datetime列
cumulative_intervals = np.cumsum(intervals)
df['datetime'] = [start_dt] + [start_dt + datetime.timedelta(minutes=int(ci)) for ci in cumulative_intervals]

说明

两种方法都满足所有要求:

  1. 第一个item的时间固定为start_dt
  2. 所有datetime严格单调递增
  3. 最后一个时间不会超过end_dt
  4. 相邻间隔始终在15-200分钟范围内
  5. 适配任意数量的item(奇/偶均可)

内容的提问来源于stack exchange,提问作者user21474411

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 18:39:52