【问题标题】:How to assign time objects to bins?如何将时间对象分配给 bin?
【发布时间】:2019-12-17 21:40:05
【问题描述】:

我有一个需要分配给时间窗口(7、9、12、15、18)的时间列表,以确保每个时间窗口都被列表中的一个元素覆盖。

from datetime import date, time, datetime

def nearest(items, target):
    return min(items, key=lambda x: abs(x - target))

time_list = [datetime.datetime(2019, 12, 17, 7, 30), 
             datetime.datetime(2019, 12, 17, 9, 0), 
             datetime.datetime(2019, 12, 17, 16, 0), 
             datetime.datetime(2019, 12, 17, 18, 30), 
             datetime.datetime(2019, 12, 17, 21, 30), 
             datetime.datetime(2019, 12, 17, 12, 30), 
             datetime.datetime(2019, 12, 17, 19, 0), 
             datetime.datetime(2019, 12, 17, 0, 0), 
             datetime.datetime(2019, 12, 17, 14, 30)]

target_times = [datetime.combine(date.today(),time(i,0)) for i in range(6,19,3)]
coverage = [abs(nearest(time_list, t)-t)<time(1,30) for t in target_times]

期望的输出:

[True, True, True, True, True]

这当前返回一个“

【问题讨论】:

  • 您想要的输出在列表中有 5 个条目,与 target_times 匹配...所以您是否要查看 time_list 的任何元素是否在 any 的 bin 中target_times?
  • 我想知道每个target_times 是否被time_list 元素之一覆盖

标签: python date datetime time comparison-operators


【解决方案1】:

这是我根据这个 SO 问题 How to check if the current time is in range in python? 汇总的解决方案。它有效,但我想知道是否有更好的解决方案。

def time_in_range(start, end, x):
    today = timezone.localtime().date()
    start = timezone.make_aware(datetime.combine(today, start))
    end = timezone.make_aware(datetime.combine(today, end))
    x = timezone.make_aware(datetime.combine(today, x))
    if end <= start:
        end += timedelta(days=1) # tomorrow!
    if x <= start:
        x += timedelta(days=1) # tomorrow!
    return start <= x <= end

downloaded = [False, False, False, False, False]
times = [time(i,0) for i in [5,8,10,13,16,20]]
for i in range(5):
    for start_time in start_times:
        if time_in_range(times[i], times[i+1], start_time):
            downloaded[i] = True

【讨论】:

    【解决方案2】:

    您当前问题的答案是您正在尝试将timedelta ob 对象与time 对象进行比较。在这种情况下,您可能希望像这样创建一个 timedelta 对象:

    timedelta(hours=1, minutes=30)
    

    代替

    time(1,30)
    

    【讨论】:

      【解决方案3】:

      您不妨在这里使用pandas;因为它具有处理 bin 和间隔的内置方法。

      在这种情况下,您有四 (4) 个时间间隔:

      1. [7 到 9)
      2. [9 到 12)
      3. [12 到 15)
      4. [15 到 18)
      5. ...是否应该有另一个 18 到 24 的间隔?

      “[”表示包含,“)”表示排除。

      您可以将time_list 加载到熊猫数据框中:

      import pandas as pd
      
      df = pd.DataFrame(time_list,columns=['timestamp']) # `columns` is how you name the column(s)
      

      那么,我推荐 pandas 的原因是它有一个名为 .cut() 的有用函数,它可以对值进行分类。

      >>> bins = [7, 9, 12, 15, 18]
      >>> pd.cut(df['timestamp'].dt.hour,bins=bins).unique().dropna().sort_values()
      [(7, 9], (9, 12], (12, 15], (15, 18]]
      

      然后您可以像这样测试上述操作的结果的适当长度(减1是因为有五个bin:

      >>> covered_intervals = _ # an underscore gets the most recent value in the interpreter
      >>> len(covered_intervals) == len(bins) - 1
      True
      

      如果你想要一个布尔值列表,你可以这样做:

      result = []
      for i in covered_intervals:
          if i.left in bins:
              result.append(True)
          else:
              result.append(False)
      

      【讨论】:

        猜你喜欢
        • 2011-01-09
        • 2011-07-19
        • 1970-01-01
        • 2010-11-15
        • 2020-01-10
        • 2011-01-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多