使用NumPy按整数类型的月份添加日期

plicqrtu  于 2023-10-19  发布在  其他
关注(0)|答案(2)|浏览(99)
date = np.array(['2023-01-01', '2023-02-02', '2023-03-03'])
months = np.array([3, 2, 1])
months = np.array([np.timedelta64(month, 'M') for month in months])

expectation = date + months  ?????

# the array I want to get
# expectation -> np.array(['2023-04-01', '2023-04-02', '2023-04-03'])

我想添加两个变量“日期”和“月份”。expectation变量是我想要得到的。
怎么做?

yfwxisqw

yfwxisqw1#

注意:这个答案的第1部分假设数组有一个dtype='datetime64[D]',与RJ's answer的区别在于,我展示了一种向量化的方法来构建最终结果,因为他们的答案在最后一步中以列表解析的形式存在一个鬼鬼祟祟的循环,在那里他们构建了expectation
如果输入数组有一个dtype='U10',就像运行date = np.array(['2023-01-01', '2023-02-02', '2023-03-03'])语句一样,跳到第2部分。

第一部分:如果date.dtype == 'datetime64[D]'

计算new_yearsnew_months,就像RJ在他们的答案中显示的那样:

# Given date and months arrays
date = np.array(['2023-01-01', '2023-02-02', '2023-03-03'], dtype='datetime64[D]')
months = np.array([3, 2, 1])

# Extracting year, month, and day components
years = date.astype('datetime64[Y]').astype(int) + 1970
months_from_date = date.astype('datetime64[M]').astype(int) % 12 + 1
days = date.astype('datetime64[D]') - date.astype('datetime64[M]')

# Adding the respective month values and handling overflow
new_months = months_from_date + months
new_years = years + (new_months - 1) // 12
new_months = (new_months - 1) % 12 + 1

然后,通过颠倒将日期分解为年、月和日的步骤来构造结果:

expectation = (new_years - 1970).astype('datetime64[Y]') + \
              new_months.astype('timedelta64[M]') + \
              days

这将为您提供所需的数组

array(['2023-05-01', '2023-05-02', '2023-05-03'], dtype='datetime64[D]')

第二部分:如果date.dtype == '<U10'

对于RJ将输入字符串数组拆分为日期、月份和年份的方法的替代方案:你可以直接从字符串数组的字符中获取这些,而不是转换为日期时间数组:
首先,转换为(N, 10)字符数组:

>>> date_chars = date.view('U1').reshape((-1, 10))

array([['2', '0', '2', '3', '-', '0', '1', '-', '0', '1'],
       ['2', '0', '2', '3', '-', '0', '2', '-', '0', '2'],
       ['2', '0', '2', '3', '-', '0', '3', '-', '0', '3']], dtype='<U1')

接下来,通过对这个数组进行切片来获得年、月和日:

>>> years = date_chars[:, :4].view('U4').astype(int)

array([[2023],
       [2023],
       [2023]])

>>> months_from_date = date_chars[:, 5:7].view('U2').astype(int)

array([[1],
       [2],
       [3]])

>>> days = date_chars[:, 8:10].view('U2').astype(int)

array([[1],
       [2],
       [3]])

由于所有这些数组都是列向量,让我们将months转换为列向量,这样numpy就不会将结果广播到方阵中:

>>> months = np.array([3, 2, 1])
... months = months[:, None]

array([[3],
       [2],
       [1]])

然后,创建new_monthsnew_years,如下所示:

>>> new_months = months_from_date + months
... new_years = years + (new_months - 1) // 12
... new_months = (new_months - 1) % 12 + 1

最后,建立你的新日期:
创建一个与date_chars大小相同的字符数组,但充满了字符'0'。在正确位置插入连字符:

>>> new_date_chars = np.full_like(date_chars, '0', dtype='U1')
... new_date_chars[:, 4] = '-'
... new_date_chars[:, 7] = '-'

array([['0', '0', '0', '0', '-', '0', '0', '-', '0', '0'],
       ['0', '0', '0', '0', '-', '0', '0', '-', '0', '0'],
       ['0', '0', '0', '0', '-', '0', '0', '-', '0', '0']], dtype='<U1')

在下一步之前,让我们定义一个助手函数,它将接受一个数字数组(天或月),并返回一个填充零的字符数组:

def to_chars_pad_zero(arr):
    char_arr = arr.astype('U2').view('U1')
    one_digit_nums = (arr < 10).squeeze()
    char_arr[one_digit_nums, 1] = char_arr[one_digit_nums, 0]
    char_arr[one_digit_nums, 0] = '0'
    return char_arr

然后,插入年、月和日期:

>>> new_date_chars[:, :4] = new_years.astype('U4').view('U1')

array([['2', '0', '2', '3', '-', '0', '0', '-', '0', '0'],
       ['2', '0', '2', '3', '-', '0', '0', '-', '0', '0'],
       ['2', '0', '2', '3', '-', '0', '0', '-', '0', '0']], dtype='<U1')

>>> new_date_chars[:, 5:7] = to_chars_pad_zero(new_months)

array([['2', '0', '2', '3', '-', '0', '4', '-', '0', '0'],
       ['2', '0', '2', '3', '-', '0', '4', '-', '0', '0'],
       ['2', '0', '2', '3', '-', '0', '4', '-', '0', '0']], dtype='<U1')

>>> new_date_chars[:, 8:] = to_chars_pad_zero(days)

array([['2', '0', '2', '3', '-', '0', '4', '-', '0', '1'],
       ['2', '0', '2', '3', '-', '0', '4', '-', '0', '2'],
       ['2', '0', '2', '3', '-', '0', '4', '-', '0', '3']], dtype='<U1')

最后,将它们连接成一个字符串:

>>> new_dates = new_date_chars.view('U10').squeeze()

array(['2023-04-01', '2023-04-02', '2023-04-03'], dtype='<U10')
z6psavjg

z6psavjg2#

因为月份的长度不同,所以使用numpy来抵消日期可能会很棘手。但是,您可以通过提取年、月和日组件,执行加法,然后重新组合日期来实现这一点。
这里有一个方法:

import numpy as np

# Given date and months arrays
date = np.array(['2023-01-01', '2023-02-02', '2023-03-03'], dtype='datetime64[D]')
months = np.array([3, 2, 1])

# Extracting year, month, and day components
years = date.astype('datetime64[Y]').astype(int) + 1970
months_from_date = date.astype('datetime64[M]').astype(int) % 12 + 1
days = date.astype('datetime64[D]') - date.astype('datetime64[M]')

# Adding the respective month values and handling overflow
new_months = months_from_date + months
new_years = years + (new_months - 1) // 12
new_months = (new_months - 1) % 12 + 1

# Constructing the new datetime64[D] array and adding back the day component
expectation = np.array(["{}-{:02}-01".format(y, m) for y, m in zip(new_years, new_months)], dtype='datetime64[D]')
expectation_with_days = expectation + days

输出量:

array(['2023-04-01', '2023-04-02', '2023-04-03'], dtype='datetime64[D]')

相关问题