У меня есть следующий df:
Start_Date End_Date Relevant Volume
2024-10-01 2024-12-31 False 0.000000
2025-01-01 2025-03-31 True 0.097989
2025-04-01 2025-06-30 True -0.014449
2025-01-01 2025-12-31 True 0.195327
2026-01-01 2026-12-31 False 0.000000
Мне нужен почасовой индекс, начинающийся/заканчивающийся в первую/последнюю дату, где Релевантно == True. Я делаю это следующим образом:
relevant_df = df[df['Relevant']]
earliest_start = relevant_df['Start_Date'].min()
latest_end = relevant_df['End_Date'].max()
# Create DateTime index
date_range = pd.date_range(start=earliest_start, end=latest_end, freq='H')
aggregated_volumes = pd.Series(index=date_range, dtype=float)
Теперь, как я могу взять объем за период и сложить их вместе, чтобы в этом примере, в первые три месяца 2025 года, объем в час был равен 0,097989 + 0,195327, второй квартал -0,014449 + 0,195327 и т. д.
Поскольку ваши интервалы перекрываются, я считаю, что нет прямого способа индексировать ваши значения.
Однако вы можете создать массив NxM numpy (N: количество строк, M: количество истинных строк) и суммировать:
# ensure datetime
relevant_df[['Start_Date', 'End_Date']] = relevant_df[['Start_Date', 'End_Date']].apply(pd.to_datetime)
# compute a mask of the values between start/end
idx = date_range.to_numpy()[:, None]
m1 = idx>=relevant_df['Start_Date'].to_numpy()
m2 = idx<relevant_df['End_Date'].to_numpy()
# broadcast the values, sum, convert to Series
out = pd.Series(np.nansum(np.where(m1&m2, relevant_df['Volume'].to_numpy(), np.nan), axis=1),
index=date_range)
Выход:
2025-01-01 00:00:00 0.293316
2025-01-01 01:00:00 0.293316
2025-01-01 02:00:00 0.293316
2025-01-01 03:00:00 0.293316
2025-01-01 04:00:00 0.293316
...
2025-12-30 20:00:00 0.195327
2025-12-30 21:00:00 0.195327
2025-12-30 22:00:00 0.195327
2025-12-30 23:00:00 0.195327
2025-12-31 00:00:00 0.000000
Freq: h, Length: 8737, dtype: float64
В качестве альтернативы, если у вас редкие интервалы относительно всего диапазона:
out = pd.DataFrame([pd.Series(v, index=pd.date_range(s, e, inclusive='left', freq='h'))
for s,e,v in zip(relevant_df['Start_Date'],
relevant_df['End_Date'],
relevant_df['Volume']
)]).sum()
Выход:
2025-01-01 00:00:00 0.293316
2025-01-01 01:00:00 0.293316
2025-01-01 02:00:00 0.293316
2025-01-01 03:00:00 0.293316
2025-01-01 04:00:00 0.293316
...
2025-12-30 19:00:00 0.195327
2025-12-30 20:00:00 0.195327
2025-12-30 21:00:00 0.195327
2025-12-30 22:00:00 0.195327
2025-12-30 23:00:00 0.195327
Freq: h, Length: 8736, dtype: float64
Визуальный вывод:
import pandas as pd
import numpy as np
from scipy.sparse import coo_matrix, csc_matrix, csr_matrix
data = {
'Start_Date': ['2024-10-01', '2025-01-01', '2025-04-01', '2025-01-01', '2026-01-01'],
'End_Date': ['2024-12-31', '2025-03-31', '2025-06-30', '2025-12-31', '2026-12-31'],
'Relevant': [False, True, True, True, False],
'Volume': [0.0, 0.097989, -0.014449, 0.195327, 0.0]
}
df = pd.DataFrame(data)
# Ensure datetime format
df['Start_Date'] = pd.to_datetime(df['Start_Date'])
df['End_Date'] = pd.to_datetime(df['End_Date'])
print(df)
Start_Date End_Date Relevant Volume
0 2024-10-01 2024-12-31 False 0.000000
1 2025-01-01 2025-03-31 True 0.097989
2 2025-04-01 2025-06-30 True -0.014449
3 2025-01-01 2025-12-31 True 0.195327
4 2026-01-01 2026-12-31 False 0.000000
# Filter rows where Relevant == True
relevant_df = df[df['Relevant']]
print(relevant_df)
Start_Date End_Date Relevant Volume
1 2025-01-01 2025-03-31 True 0.097989
2 2025-04-01 2025-06-30 True -0.014449
3 2025-01-01 2025-12-31 True 0.195327
#generate hourly date range
date_range = pd.date_range(start= relevant_df['Start_Date'].min(),
end =relevant_df['Start_Date'].max() ,freq = 'h')
print(date_range.to_series())
2025-01-01 00:00:00 2025-01-01 00:00:00
2025-01-01 01:00:00 2025-01-01 01:00:00
2025-01-01 02:00:00 2025-01-01 02:00:00
2025-01-01 03:00:00 2025-01-01 03:00:00
2025-01-01 04:00:00 2025-01-01 04:00:00
...
2025-03-31 20:00:00 2025-03-31 20:00:00
2025-03-31 21:00:00 2025-03-31 21:00:00
2025-03-31 22:00:00 2025-03-31 22:00:00
2025-03-31 23:00:00 2025-03-31 23:00:00
2025-04-01 00:00:00 2025-04-01 00:00:00
Freq: h, Length: 2161, dtype: datetime64[ns]
date_range_length = len(date_range)
#print(date_range_length)#2161
rows
: этот массив определяет, к какой строке принадлежит каждый элемент данных.
Он создается путем повторения индексов соответствующих записей (len(relevant_df))
date_range_length раз.
cols
: этот массив определяет, какому столбцу принадлежит каждый элемент данных.
получить значения относительно first_non_null_indices
rows = np.repeat(np.arange(len(relevant_df)), len(date_range))
#print(rows)#[0 0 0 ... 2 2 2]
cols = np.tile(np.arange(len(date_range)), len(relevant_df))
#print(cols)#[ 0 1 2 ... 2158 2159 2160]
relevant_volume_data = relevant_df['Volume'].values.repeat(len(date_range))
relevant_volume_data :
[0.097989 0.097989 0.097989 ... 0.195327 0.195327 0.195327]
start_indices = np.searchsorted(date_range, relevant_df['Start_Date'].values)
end_indices = np.searchsorted(date_range, relevant_df['End_Date'].values)
-Ans
:
mask = (cols >= start_indices[rows]) & (cols < end_indices[rows])
rows_masked,cols_masked,relevant_volume_data_masked = rows[mask], cols[mask], relevant_volume_data[mask]
csr_sparse_matrix = csr_matrix( (relevant_volume_data_masked, (rows_masked,cols_masked)),
shape = (len(relevant_df), len(date_range) )
)
(0, 0) 0.097989
(0, 1) 0.097989
(0, 2) 0.097989
(0, 14) 0.097989
(0, 15) 0.097989
(0, 21) 0.097989
(0, 22) 0.097989
(0, 23) 0.097989
(0, 24) 0.097989
: :
(2, 2136) 0.195327
(2, 2137) 0.195327
(2, 2138) 0.195327
(2, 2139) 0.195327
(2, 2140) 0.195327
(2, 2159) 0.195327
(2, 2160) 0.195327
summed_volumes = np.array(csr_sparse_matrix.sum(axis=0)).flatten()
summed_volumes:
[0.293316 0.293316 0.293316 ... 0.195327 0.195327 0.180878]
res = pd.Series(summed_volumes,index = date_range)
print(res)
2025-01-01 00:00:00 0.293316
2025-01-01 01:00:00 0.293316
2025-01-01 02:00:00 0.293316
2025-01-01 03:00:00 0.293316
2025-01-01 04:00:00 0.293316
...
2025-03-31 20:00:00 0.195327
2025-03-31 21:00:00 0.195327
2025-03-31 22:00:00 0.195327
2025-03-31 23:00:00 0.195327
2025-04-01 00:00:00 0.180878
Freq: h, Length: 2161, dtype: float64
import pandas as pd
import numpy as np
from scipy.sparse import coo_matrix, csc_matrix, csr_matrix
data = {
'Start_Date': ['2024-10-01', '2025-01-01', '2025-04-01', '2025-01-01', '2026-01-01'],
'End_Date': ['2024-12-31', '2025-03-31', '2025-06-30', '2025-12-31', '2026-12-31'],
'Relevant': [False, True, True, True, False],
'Volume': [0.0, 0.097989, -0.014449, 0.195327, 0.0]
}
df = pd.DataFrame(data)
df['Start_Date'] = pd.to_datetime(df['Start_Date'])
df['End_Date'] = pd.to_datetime(df['End_Date'])
relevant_df = df[df['Relevant']]
date_range = pd.date_range(start= relevant_df['Start_Date'].min(),
end =relevant_df['Start_Date'].max() ,freq = 'h')
print(date_range.to_series())
date_range_length = len(date_range)
rows = np.repeat(np.arange(len(relevant_df)), len(date_range))
cols = np.tile(np.arange(len(date_range)), len(relevant_df))
relevant_volume_data = relevant_df['Volume'].values.repeat(len(date_range))
start_indices = np.searchsorted(date_range, relevant_df['Start_Date'].values)
end_indices = np.searchsorted(date_range, relevant_df['End_Date'].values)
mask = (cols >= start_indices[rows]) & (cols < end_indices[rows])
rows_masked,cols_masked,relevant_volume_data_masked = rows[mask], cols[mask], relevant_volume_data[mask]
csr_sparse_matrix = csr_matrix( (relevant_volume_data_masked, (rows_masked,cols_masked)),
shape = (len(relevant_df), len(date_range) )
)
summed_volumes = np.array(csr_sparse_matrix.sum(axis=0)).flatten()
res = pd.Series(summed_volumes,index = date_range)
Последние 23 часа не заполняются объемами даже после изменения приведенного выше значения на:latest_end =релевантная_база['End_Date'].max() + pd.DateOffset(hours=23). Все последние 23 строки равны нулю. Есть идеи, как это исправить?