как в pandas на основе DatetimeIndex одного массива получить значения из другого массива ориентируясь по его DatetimeIndex
Есть дневные данные из файла D, на основе которых создается серия, и квартальные данные Q по которым так же создается серия в pandas.
Мне нужно, используя DatetimeIndex дневных данных, получить значения массива из квартальных данных. То есть, найти ближайшее значение, при этом DatetimeIndex квартального должен быть меньше или равен дневному (не должно быть "заглядывания вперёд").
Пример:
2018-06-30, 1207.4 #квартальное значение
2018-07-02 00:00:00, 1.58479 # ближайшее дневное
2018-07-02 00:00:00, 1207.4 #синхронизировали по времени значение из квартальных данных с дневным
Сейчас я использую основной цикл по D и вложенный в него цикл по Q. Хотелось бы обойтись без циклов. Или быть может каким-либо образом numpy использовать, но у меня массивы разной длины. Возможно, в pandas есть функция наподобие этой:
index = data1.index.get_loc('1991-10-15', "nearest")
но для массива.
P.S. Нужно именно быстрое получение данных. С помощью циклов понятно, как сделать. Если есть ответ, как данную манипуляцию произвести в postgresql, то интересно было бы увидеть. Здесь задавал вопрос по этой теме.
Для лучшего понимания дополнил код функцией "def file", в которой циклы делают синхронизацию значений из квартальных данных с дневными. Если ее запустить, то наглядно видно, что мне необходимо. Данные бывают с различной частотой 7, 10 дней, месяц, квартал(не в одинаковые числа месяца).
import numpy as np
import pandas as pd
df = pd.read_csv('D.csv',
index_col='DATE',
parse_dates=True,
infer_datetime_format=True)
date = df.iloc[:, 0].index.date
z = df.iloc[:, 3].values
df1 = pd.read_csv('Q.csv',
index_col='DATE',
parse_dates=True,
infer_datetime_format=True)
date1 = df1.iloc[:, 0].index.date
z1 = df1.iloc[:, 0].values
date_ = np.array(date, dtype=np.datetime64)
data = pd.Series(z, index=date_)
date_1 = np.array(date1, dtype=np.datetime64)
data1 = pd.Series(z1, index=date_1)
def file(v,n,dv,dn): #v = z, n = z1, dv = date, dn = date1
z = np.copy(v)
news = np.copy(n)
date = dv
date_n = dn
N = len(date)
N1 = len(date_n)
x = N1 - 1
global u
u = 0
for q in range(0, N):
k = u
for i in range(k, N1):
if date_n[i - 1] <= date[q] and date_n[i] > date[q]:
u = i
z[q] = news[i - 1]
break
if x == i and date[q] >= date_n[i]:
u = i
z[q] = news[i]
break
return z
zn = file(z,z1,date,date1)
test_data = pd.Series(zn, index=date_)
print(test_data)
Ответы (1 шт):
Не совсем понятен вопрос. Пока я понял так - нужно найти в дневных данных значение, ближайшее по дате к имеющимся квартальным данным и дописать его в фрейм с квартальными данными. Если так, то это просто делается через ресамплинг и объединение:
import pandas as pd
df = pd.read_csv('D.csv',
index_col='DATE',
parse_dates=True,
usecols=[0, 4],
infer_datetime_format=True)
df1 = pd.read_csv('Q.csv',
index_col='DATE',
parse_dates=True,
infer_datetime_format=True)
df = df.resample("Q").last()
res = df1.join(df, how="inner")
получите res:
O C
DATE
1991-03-31 493.8 108.400
1991-06-30 485.6 105.530
1991-09-30 492.5 106.300
1991-12-31 500.3 94.900
1992-03-31 504.4 102.060
... ... ...
2017-06-30 1179.0 86.355
2017-12-31 1191.5 87.939
2018-06-30 1207.4 81.947
2018-12-31 1225.3 77.250
2019-06-30 1237.9 75.763
[100 rows x 2 columns]
в котором в колонке "C" будут ближайшие дневные данные к имеющимся квартальным.
Если нужно наоборот, в дневной датафрейм добавить данные квартального, то можно сделать так:
import pandas as pd
df = pd.read_csv('D.csv',
index_col='DATE',
parse_dates=True,
usecols=[0, 4],
infer_datetime_format=True)
df1 = pd.read_csv('Q.csv',
index_col='DATE',
parse_dates=True,
infer_datetime_format=True)
Нужно обратить внимание на разные временные промежутки в индексах обоих фреймов. в данном конкретном случае, если я не ошибаюсь, корректно будет расширить индекс квартального фрейма, для полного охвата индекса дневного фрейма:
df1 = df1.reindex(pd.date_range(df1.index.max(), df.index.max()).union(df1.index), method="pad")
Ну и затем:
df1 = df1.resample("D").fillna(method="ffill")
df["Q"] = df1.loc[df1.index.intersection(df.index)]
df["Q"] = df["Q"].fillna(method="ffill")
тогда df будет:
C Q
DATE
1991-02-04 102.230 489.0
1991-02-05 100.620 489.0
1991-02-06 100.010 489.0
1991-02-07 100.470 489.0
1991-02-08 99.650 489.0
... ... ...
2021-07-01 83.281 1237.9
2021-07-02 83.534 1237.9
2021-07-05 83.472 1237.9
2021-07-06 82.876 1237.9
2021-07-07 82.755 1237.9
[7849 rows x 2 columns]