在numpy中生成指定范围内的随机日期

9

我怎样在numpy中生成一个指定日期范围内以两个月为间隔的随机日期?我能想到一种方法是先生成两个随机整数数组:

bimonthly1 = np.random.randint(1,15,12)
bimonthly2 = np.random.randint(16,30,12)

然后,我可以使用上述两个数组的“day”值来为每个月生成日期。然而,这将需要显式传递月份和年份数据。一个解决方法是首先生成所需的date_range,然后用上面的数组值替换范围内的“days”。但对于大型数组,这可能不是最佳解决方案。这种方法将需要对范围中的每个元素进行操作。

我希望能够得到在numpy中更高效的实现方法。


1
如果你想让每一天的概率相同,使用timedelta是一个更好的选择。 - Da Qi
5个回答

11

有一种更简单的方法可以实现这个,而不需要显式地调用除numpy之外的任何库。

Numpy有一个相当强大的日期时间数据类型:特别是对于这种情况,您可以添加和减去整数,并将其视为最小的可用时间单位。例如,对于%Y-%m-%d格式:

exampledatetime1 = np.datetime64('2017-01-01')
exampledatetime1 + 1
>>
2017-01-02

然而,对于 %Y-%m-%d %H:%M:%S 格式:

exampledatetime2 = np.datetime64('2017-01-01 00:00:00')
exampledatetime2 + 1
>>
2017-01-01 00:00:01
在这种情况下,由于你只有一天的分辨率信息,你可以简单地执行以下操作:
import numpy as np

bimonthly_days = np.arange(0, 60)
base_date = np.datetime64('2017-01-01')
random_date = base_date + np.random.choice(bimonthly_days)

或者,如果您希望更加严谨:

import numpy as np

def random_date_generator(start_date, range_in_days):
    days_to_add = np.arange(0, range_in_days)
    random_date = np.datetime64(start_date) + np.random.choice(days_to_add)
    return random_date

然后只需使用:

yourdate = random_date_generator('2012-01-15', 60)

在时间数组中使用np.choice是不可扩展的。随着频率的变化和时间范围的扩大,这一点变得更加明显。 - Reinderien

2
你可以预先创建日期范围,例如使用 pandasdate_range,并将其转换为 numpy 数组。然后,使用 numpy.random.choice 从这个日期数组中随机选择日期。

1
如果您将开始日期定义为每月的第一天,然后再添加随机时间差,会怎样呢?
例如:
import datetime
d0 = datetime.datetime.strptime('01/01/2016', '%d/%m/%Y')

from calendar import monthrange
max_day = monthrange(d0.year, d0.month)[1]

import numpy as np
random_dates_1 = []
random_dates_2 = []
for i in range(10):
    random_dates_1.append( d0 + datetime.timedelta(days=np.random.randint(0, int(max_day/2))) )
    random_dates_2.append( d0 + datetime.timedelta(days=np.random.randint(int(max_day/2), max_day+1)) )

说实话,我认为这是唯一可扩展的解决方案,比生成整个数组然后从中选择要好得多。 - Reinderien

1
这是一个纯numpy实现的代码,用于创建每个月份的两个日期时间数组。第一个数组包含每个月前半段的随机值,第二个数组包含每个月后半段的随机值。请保留html标签。
import datetime
from calendar import monthrange
import numpy as np

arr_first = np.array([])
arr_second = np.array([])

for i in range(1, 13):
    base = datetime.datetime(2016, i, 1)
    max_days = monthrange(2016, i)[1]
    first = np.random.randint(0, max_days // 2)
    second =np.random.randint(max_days // 2, max_days)
    arr_first = np.append(arr_first, base + datetime.timedelta(days=first))
    arr_second = np.append(arr_second, base + datetime.timedelta(days=second))

不建议迭代扩展数组 - 它们应该预先静态分配为13个元素 - 但除此之外,这是首选方法。 - Reinderien

0
所有已经给出的答案都涉及在一次生成多个日期时使用某种循环。这里有一个完全并行化的函数,它使用与@Alex相同的基本方法,但完全不使用迭代或追加。
这段代码不是通过逐个添加到已知起始值来构建一个数组,而是通过创建一个起始值数组和一个随机偏移量数组,然后将它们相加来工作。
import numpy as np

def random_dates(start, range_in_days, count):
    """
    Generate a number of random dates in Datetime format.
    :param start: Start date. Must be string or Datetime object.
    :param range_in_days: Number of days past the start (exclusive). Must be an int.
    :param count: Number of values to generate
    :return: An ndarray of length count and dtype datetime64, full of random dates.
    """
    start = np.datetime64(start)
    base = np.full(count, start)
    offset = np.random.randint(0, range_in_days, count)
    offset = offset.astype('timedelta64[D]')
    return base + offset

# prints 30 random dates within the month of January 2023
print(random_dates("2023-01-01", 31, 10))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接