Python:选择列表中最长的连续日期序列

Python:选择列表中最长的连续日期序列,python,python-3.x,date,datetime,series,Python,Python 3.x,Date,Datetime,Series,我有一系列的列表(实际上是np.array),其中的元素是日期 id 0a0fe3ed-d788-4427-8820-8b7b696a6033 [2019-01-30, 2019-01-31, 2019-02-01, 2019-02-0... 0a48d1e8-ead2-404a-a5a2-6b05371200b1 [2019-01-30, 2019-01-31, 2019-02-01, 2019-02-0... 0a9edba1-14e3-466a-8d0c-f8a8170cefc

我有一系列的列表(实际上是np.array),其中的元素是日期

id
0a0fe3ed-d788-4427-8820-8b7b696a6033    [2019-01-30, 2019-01-31, 2019-02-01, 2019-02-0...
0a48d1e8-ead2-404a-a5a2-6b05371200b1    [2019-01-30, 2019-01-31, 2019-02-01, 2019-02-0...
0a9edba1-14e3-466a-8d0c-f8a8170cefc8    [2019-01-29, 2019-01-30, 2019-01-31, 2019-02-0...
Name: startDate, dtype: object

对于序列中的每个元素(即每个日期列表),我希望保留所有日期都是连续的最长子列表。我正努力以一种简单有效的方式来解决这个问题。我能想到的唯一方法是使用多个循环:循环序列值(列表),循环列表中的每个元素。然后,我将存储第一个日期和连续天数,如果遇到更长的连续天数序列,则使用临时值覆盖结果。但这似乎效率很低。有更好的方法吗?

您可以将列表转换为序号,所有连续日期的序号都在增加。这意味着
下一个日期=上一个日期+1

然后找到最长的连续子数组

此过程将花费
O(n)->单循环
时间,这是实现此目的最有效的方法

代码

from datetime import datetime
def get_consecutive(date_list):
  # convert to ordinals
  v = [datetime.strptime(d, "%Y-%m-%d").toordinal()  for d in date_list]
  consecutive = []
  run = []
  dates = []

  # get consecutive ordinal sequence 
  for i in range(1, len(v) + 1):
    run.append(v[i-1])
    dates.append(date_list[i-1])
    if i == len(v) or v[i-1] + 1 != v[i]:
      if len(consecutive) < len(run):
        consecutive = dates
      dates = []
      run = []

  return consecutive

现在在
df.列中使用
get\u continuous
。应用(get\u continuous)
它将为您提供所有递增日期列表。或者,如果您使用的是其他数据结构,则可以对每个列表执行所有功能。

您可以将列表转换为序号,这些序号在所有连续日期中都会增加。这意味着
下一个日期=上一个日期+1

然后找到最长的连续子数组

此过程将花费
O(n)->单循环
时间,这是实现此目的最有效的方法

代码

from datetime import datetime
def get_consecutive(date_list):
  # convert to ordinals
  v = [datetime.strptime(d, "%Y-%m-%d").toordinal()  for d in date_list]
  consecutive = []
  run = []
  dates = []

  # get consecutive ordinal sequence 
  for i in range(1, len(v) + 1):
    run.append(v[i-1])
    dates.append(date_list[i-1])
    if i == len(v) or v[i-1] + 1 != v[i]:
      if len(consecutive) < len(run):
        consecutive = dates
      dates = []
      run = []

  return consecutive

现在在
df.列中使用
get\u continuous
。应用(get\u continuous)
它将为您提供所有递增日期列表。或者,如果您使用的是其他数据结构,则可以对每个列表执行所有操作。

我将把这个问题简化为在单个列表中查找连续的天数。正如你所说,有一些技巧可以让它更像蟒蛇。以下脚本应按原样运行。我已经记录了它是如何内联工作的:

从日期时间导入时间增量,日期
#示例输入
天数=[
日期(2020年1月1日),日期(2020年1月2日),日期(2020年1月4日),
日期(2020年1月5日)、日期(2020年1月6日)、日期(2020年1月8日),
]
#存储最长间隔和当前连续间隔
#当我们遍历一个列表时
最长间隔指数=当前间隔指数=0
最长间隔长度=当前间隔长度=1
#在此处使用zip减少索引操作的数量
#这将把天数列表变成[(2020-01-112020-01-02),(2020-01-022020-01-03),…]
#使用enumerate获取当天的索引
对于枚举中的i(前一天,当前天)(zip(天,天[1:]),开始=1):
如果当前日-前一日==timedelta(天=+1):
#我们找到了连续的一天!增加间隔长度
当前间隔长度+=1
其他:
#不,不是连续一天!从今天开始,从今天开始
#从1开始计算
当前间隔指数=i
当前间隔长度=1
如果当前间隔长度>最长间隔长度:
#我们打破了记录!将其记录为最长间隔
最长间隔指数=当前间隔指数
最长间隔长度=当前间隔长度
打印(“最长间隔索引:”,最长间隔索引)
打印(“最长间隔:”,天[最长间隔索引:最长间隔索引+最长间隔长度])

将其转换为可重用函数应该很容易。

我将把这个问题简化为在单个列表中查找连续的天数。正如你所说,有一些技巧可以让它更像蟒蛇。以下脚本应按原样运行。我已经记录了它是如何内联工作的:

从日期时间导入时间增量,日期
#示例输入
天数=[
日期(2020年1月1日),日期(2020年1月2日),日期(2020年1月4日),
日期(2020年1月5日)、日期(2020年1月6日)、日期(2020年1月8日),
]
#存储最长间隔和当前连续间隔
#当我们遍历一个列表时
最长间隔指数=当前间隔指数=0
最长间隔长度=当前间隔长度=1
#在此处使用zip减少索引操作的数量
#这将把天数列表变成[(2020-01-112020-01-02),(2020-01-022020-01-03),…]
#使用enumerate获取当天的索引
对于枚举中的i(前一天,当前天)(zip(天,天[1:]),开始=1):
如果当前日-前一日==timedelta(天=+1):
#我们找到了连续的一天!增加间隔长度
当前间隔长度+=1
其他:
#不,不是连续一天!从今天开始,从今天开始
#从1开始计算
当前间隔指数=i
当前间隔长度=1
如果当前间隔长度>最长间隔长度:
#我们打破了记录!将其记录为最长间隔
最长间隔指数=当前间隔指数
最长间隔长度=当前间隔长度
打印(“最长间隔索引:”,最长间隔索引)
打印(“最长间隔:”,天[最长间隔索引:最长间隔索引+最长间隔长度])

将其转换为可重用函数应该很容易。

既然您提到要使用numpy日期数组,那么坚持numpy类型而不是转换为内置类型是有意义的。我在这里假设数组的数据类型为“datetime64[D]”。那样的话,你可以这样做

import numpy as np

date_list = np.array(['2005-02-01', '2005-02-02', '2005-02-03',
       '2005-02-05', '2005-02-06', '2005-02-07', '2005-02-08', '2005-02-09',
       '2005-02-11', '2005-02-12',
       '2005-02-14', '2005-02-15', '2005-02-16', '2005-02-17',
       '2005-02-19', '2005-02-20',
       '2005-02-22', '2005-02-23', '2005-02-24',
       '2005-02-25', '2005-02-26', '2005-02-27', '2005-02-28'],
      dtype='datetime64[D]')

i0max, i1max = 0, 0
i0 = 0
for i1, date in enumerate(date_list):
    if date - date_list[i0] != np.timedelta64(i1-i0, 'D'):
        if i1 - i0 > i1max - i0max:
            i0max, i1max = i0, i1
        i0 = i1

print(date_list[i0max:i1max])

# output: ['2005-02-05' '2005-02-06' '2005-02-07' '2005-02-08' '2005-02-09']

这里,
i0
i1
表示当前连续日期子数组的开始和停止索引,
i0max
i1max
表示迄今为止找到的最长子数组的开始和停止索引。该解决方案使用了这样一个事实,即连续日期列表中的第i个和第0个条目之间的差异正好是第i个