Я хочу умножить два массива (а не их значения). В этом случае у меня есть массив последовательных дат, которые могут варьироваться, и еще один массив значений от 0 до 23 (т.е. часов).
a = np.arange(np.datetime64('2024-01-01'), np.datetime64('2024-01-11'))
и
b = np.linspace(0, 23, 24)
Как мне объединить их в новый массив так, чтобы (в приведенном выше примере) он давал массив из 240 строк, каждые 24 строки — это заданная дата и последовательные часы от 0 до 23?
Это даст следующий результат: array([['2024-01-01', 0],['2024-01-01', 1] ... ['2024-01-10', 22],['2024-01-10', 23]])
IIUC, конвертируйте b
в массив timedelta64 , затем транслируйте сложение и сгладьте с помощью ravel:
out = (a[:, None] + b*np.timedelta64(1, 'h')).ravel()
Или:
out = np.add.outer(a, b*np.timedelta64(1, 'h')).ravel()
Выход:
array(['2024-01-01T00', '2024-01-01T01', '2024-01-01T02', '2024-01-01T03',
'2024-01-01T04', '2024-01-01T05', '2024-01-01T06', '2024-01-01T07',
'2024-01-01T08', '2024-01-01T09', '2024-01-01T10', '2024-01-01T11',
...,
'2024-01-10T20', '2024-01-10T21', '2024-01-10T22', '2024-01-10T23'],
dtype='datetime64[h]')
Если вы хотите столбцы с парами даты/часов:
out = np.c_[np.repeat(a, len(b)).astype(object), np.tile(b, len(a))]
array([[datetime.date(2024, 1, 1), 0.0],
[datetime.date(2024, 1, 1), 1.0],
[datetime.date(2024, 1, 1), 2.0],
[datetime.date(2024, 1, 1), 3.0],
...,
[datetime.date(2024, 1, 1), 22.0],
[datetime.date(2024, 1, 1), 23.0],
[datetime.date(2024, 1, 2), 0.0],
[datetime.date(2024, 1, 2), 1.0],
...,
[datetime.date(2024, 1, 10), 21.0],
[datetime.date(2024, 1, 10), 22.0],
[datetime.date(2024, 1, 10), 23.0]], dtype=object)
Но это не очень хорошее использование numpy IMO (в этом случае лучше использовать структурированный массив или Pandas DataFrame):
out = np.empty(len(a)*len(b), dtype=[('date', a.dtype), ('hour', b.dtype)])
out['date'] = np.repeat(a, len(b))
out['hour'] = np.tile(b, len(a))
array([('2024-01-01', 0.), ('2024-01-01', 1.), ('2024-01-01', 2.),
('2024-01-01', 3.), ('2024-01-01', 4.), ('2024-01-01', 5.),
('2024-01-01', 6.), ('2024-01-01', 7.), ('2024-01-01', 8.),
...,
('2024-01-10', 18.), ('2024-01-10', 19.), ('2024-01-10', 20.),
('2024-01-10', 21.), ('2024-01-10', 22.), ('2024-01-10', 23.)],
dtype=[('date', '<M8[D]'), ('hour', '<f8')])
Или:
import pandas as pd
out = pd.DataFrame({'date': a}).merge(pd.DataFrame({'hour': b}), how='cross')
date hour
0 2024-01-01 0.0
1 2024-01-01 1.0
2 2024-01-01 2.0
3 2024-01-01 3.0
4 2024-01-01 4.0
.. ... ...
235 2024-01-10 19.0
236 2024-01-10 20.0
237 2024-01-10 21.0
238 2024-01-10 22.0
239 2024-01-10 23.0
[240 rows x 2 columns]
@Seamus, пожалуйста, отредактируйте свой вопрос, добавив явный ожидаемый результат (вы можете уменьшить его до 2 дней и 3 часов, чтобы пример был коротким)
Да, я согласен с тобой. Я ищу самый быстрый способ построить данные за год на основе трех переменных (0-7, 1-30, 0-30), что в конечном итоге даст> 65 миллионов строк :-(
Я добавил альтернативные подходы с использованием структурированных массивов и панд, которые следует предпочитать массиву объектов.
Еще раз спасибо Мозвей. Мне нужно провести исследование!!! но ваша помощь была значительной. Очень признателен.
Я считаю, что вы пытаетесь достичь декартова произведения двух массивов.
Чтобы получить это, вы можете использовать itertools.product из стандартной библиотеки:
permutations = list(itertools.product(a, b))
Результат:
[
(numpy.datetime64('2024-01-01'), 0),
(numpy.datetime64('2024-01-01'), 1),
(numpy.datetime64('2024-01-01'), 2),
...
]
ЭТО был @robertoschiavone. Спасибо за это. Я не мог придумать математический термин, который искал.
from sklearn.preprocessing import LabelEncoder as le
import numpy as np
import pandas as pd
# Define the date range and hours
# Create a date range from 1990-01-01 to 1990-01-10
dates = np.arange(np.datetime64('1990-01-01'), np.datetime64('1990-01-11'))
# Create an array of hours from 0 to 23
hours = np.linspace(0, 23, 24).astype(int)
# Create label encoders for dates and hours
le_hours = le()
le_dates = le()
# Encode dates and hours
date_encoded = le_dates.fit_transform(dates.astype(str))
hour_encoded = le_hours.fit_transform(hours)
# Create all combinations of dates and hours
# Repeat each date for all hours
date_repeated = np.repeat(date_encoded, len(hours))
# Tile the hour array for all dates
hour_tiled = np.tile(hour_encoded, len(dates))
# Decode the encoded dates and hours back to original format
date_decoded = le_dates.inverse_transform(date_repeated)
hour_decoded = le_hours.inverse_transform(hour_tiled)
# Combine dates and hours into a single array
data = np.column_stack([date_decoded, hour_decoded])
# Create a pandas DataFrame from the array
df = pd.DataFrame(data, columns=['Date', 'Hour'])
print(df)
'''
Date Hour
0 1990-01-01 0
1 1990-01-01 1
2 1990-01-01 2
3 1990-01-01 3
4 1990-01-01 4
.. ... ...
235 1990-01-10 19
236 1990-01-10 20
237 1990-01-10 21
238 1990-01-10 22
239 1990-01-10 23
'''
Спасибо @Soudipta, это довольно элегантное решение. Тем не менее, я реализовал тот вариант, который предложил Mozway, как только он появился. У меня есть скрытое подозрение, что ваш может быть «более правильным», хотя и длиннее в коде.
Спасибо за это Мозвей. Это работает как решение, но я надеялся получить два столбца [0] = дата (- которые будут повторяться более 24 строк) и [1] час от 0 до 23 для этой даты.