У меня есть следующий вариант использования, когда у меня есть фрейм данных dfp
, содержащий цены на два актива a
и b
, и другой фрейм данных dfm
, содержащий метаданные об этих активах. Предположим, у меня есть даты начала и окончания, когда я хотел бы рассмотреть эти цены и установить все остальные цены вне этих диапазонов на np.nan
, поэтому у меня есть:
import pandas as pd
import numpy as np
# sample prices for two assets
dfp = pd.DataFrame(data=np.random.random_sample((20, 2)),
columns=['a', 'b'],
index=pd.date_range(end='2020-12-10', periods=20))
print(dfp)
a b
2020-11-21 0.411653 0.001124
2020-11-22 0.773671 0.210065
2020-11-23 0.143332 0.090111
2020-11-24 0.062085 0.475205
2020-11-25 0.160982 0.557469
2020-11-26 0.025793 0.353725
2020-11-27 0.651929 0.794265
2020-11-28 0.266566 0.270451
2020-11-29 0.713030 0.346842
2020-11-30 0.838571 0.969477
2020-12-01 0.701627 0.480349
2020-12-02 0.946619 0.344399
2020-12-03 0.430523 0.857529
2020-12-04 0.202790 0.003393
2020-12-05 0.293010 0.250172
2020-12-06 0.172535 0.932216
2020-12-07 0.508303 0.775843
2020-12-08 0.704445 0.760226
2020-12-09 0.515398 0.193958
2020-12-10 0.219717 0.040269
# metadata information for those two assets
dfm = pd.DataFrame(data=[['a', '2020-11-22', '2020-11-29'],
['b', '2020-12-01', '2020-12-07']],
columns=['name', 'start', 'end'])
# set all prices outside the range to np.nan in a loop :(
for index, row in dfm.iterrows():
dfp.loc[(dfp.index < row['start']) | (row['end'] < dfp.index), row['name']] = np.nan
print(dfp)
a b
2020-11-21 NaN NaN
2020-11-22 0.773671 NaN
2020-11-23 0.143332 NaN
2020-11-24 0.062085 NaN
2020-11-25 0.160982 NaN
2020-11-26 0.025793 NaN
2020-11-27 0.651929 NaN
2020-11-28 0.266566 NaN
2020-11-29 0.713030 NaN
2020-11-30 NaN NaN
2020-12-01 NaN 0.480349
2020-12-02 NaN 0.344399
2020-12-03 NaN 0.857529
2020-12-04 NaN 0.003393
2020-12-05 NaN 0.250172
2020-12-06 NaN 0.932216
2020-12-07 NaN 0.775843
2020-12-08 NaN NaN
2020-12-09 NaN NaN
2020-12-10 NaN NaN
Можно ли (и как) здесь заменить зацикливание расширенной индексацией? если да, то как?
@Manakin большой на самом деле, 40 миллионов элементов :( форма dfp составляет около 10k x 400
Ах, хорошо, может быть, лучше объединиться с таблицей измерений и использовать ее в качестве фильтра, чтобы вы не запрашивали 400 столбцов в таблице фактов (или это источник данных из рабочей таблицы)?
Данные:
np.random.seed(44)
dfp = pd.DataFrame(data=np.random.random_sample((20, 2)),
columns=['a', 'b'],
index=pd.date_range(end='2020-12-10', periods=20))
dfm = pd.DataFrame(data=[['a', '2020-11-22', '2020-11-29'],
['b', '2020-12-01', '2020-12-07']],
columns=['name', 'start', 'end'])
dfp:
a b
2020-11-21 0.834842 0.104796
2020-11-22 0.744640 0.360501
2020-11-23 0.359311 0.609238
2020-11-24 0.393780 0.409073
2020-11-25 0.509902 0.710148
2020-11-26 0.960526 0.456621
2020-11-27 0.427652 0.113464
2020-11-28 0.217899 0.957472
2020-11-29 0.943351 0.881824
2020-11-30 0.646411 0.213825
2020-12-01 0.636832 0.139146
2020-12-02 0.458704 0.873863
2020-12-03 0.258450 0.664851
2020-12-04 0.862674 0.148848
2020-12-05 0.562950 0.159155
2020-12-06 0.172895 0.104023
2020-12-07 0.202938 0.455189
2020-12-08 0.794575 0.990823
2020-12-09 0.805017 0.377415
2020-12-10 0.515737 0.058899
ДФМ:
name start end
0 a 2020-11-22 2020-11-29
1 b 2020-12-01 2020-12-07
x = dfm.apply(lambda row: (dfp.index < row['start']) | (row['end'] < dfp.index),
axis=1)
final = dfp[~pd.DataFrame({'a' : x[0], 'b' : x[1]}, index=dfp.index)]
финал:
a b
2020-11-21 NaN NaN
2020-11-22 0.744640 NaN
2020-11-23 0.359311 NaN
2020-11-24 0.393780 NaN
2020-11-25 0.509902 NaN
2020-11-26 0.960526 NaN
2020-11-27 0.427652 NaN
2020-11-28 0.217899 NaN
2020-11-29 0.943351 NaN
2020-11-30 NaN NaN
2020-12-01 NaN 0.139146
2020-12-02 NaN 0.873863
2020-12-03 NaN 0.664851
2020-12-04 NaN 0.148848
2020-12-05 NaN 0.159155
2020-12-06 NaN 0.104023
2020-12-07 NaN 0.455189
2020-12-08 NaN NaN
2020-12-09 NaN NaN
2020-12-10 NaN NaN
большое спасибо! очень умное решение :) Однако я не вижу, как кадры данных сопоставляются в части dfm.apply(...)
... это чувствительно к порядку?
если ваш фрейм данных не слишком велик, вы можете использовать melt
и merge
затем примените условное выражение, используя np.where
df1 = pd.merge(
pd.melt(dfp.reset_index(), id_vars = "index", var_name = "name"),
dfm,
on=["name"],
how = "left",
)
df1['value_new'] = np.where(
(df1['index'] > df1['start']) &
(df1['index'] < df1['end']),
df1['value'],
np.nan
)
index name value start end value_new
0 2020-11-21 a 0.460695 2020-11-22 2020-11-29 NaN
1 2020-11-22 a 0.818190 2020-11-22 2020-11-29 NaN
2 2020-11-23 a 0.869208 2020-11-22 2020-11-29 0.869208
3 2020-11-24 a 0.466557 2020-11-22 2020-11-29 0.466557
4 2020-11-25 a 0.218630 2020-11-22 2020-11-29 0.218630
5 2020-11-26 a 0.769285 2020-11-22 2020-11-29 0.769285
6 2020-11-27 a 0.066418 2020-11-22 2020-11-29 0.066418
7 2020-11-28 a 0.746973 2020-11-22 2020-11-29 0.746973
8 2020-11-29 a 0.881565 2020-11-22 2020-11-29 NaN
9 2020-11-30 a 0.856797 2020-11-22 2020-11-29 NaN
10 2020-12-01 a 0.303156 2020-11-22 2020-11-29 NaN
11 2020-12-02 a 0.152055 2020-11-22 2020-11-29 NaN
12 2020-12-03 a 0.239251 2020-11-22 2020-11-29 NaN
13 2020-12-04 a 0.579377 2020-11-22 2020-11-29 NaN
14 2020-12-05 a 0.950465 2020-11-22 2020-11-29 NaN
15 2020-12-06 a 0.017557 2020-11-22 2020-11-29 NaN
16 2020-12-07 a 0.459709 2020-11-22 2020-11-29 NaN
17 2020-12-08 a 0.235053 2020-11-22 2020-11-29 NaN
18 2020-12-09 a 0.935113 2020-11-22 2020-11-29 NaN
19 2020-12-10 a 0.121584 2020-11-22 2020-11-29 NaN
20 2020-11-21 b 0.982475 2020-12-01 2020-12-07 NaN
21 2020-11-22 b 0.006563 2020-12-01 2020-12-07 NaN
22 2020-11-23 b 0.863132 2020-12-01 2020-12-07 NaN
23 2020-11-24 b 0.059826 2020-12-01 2020-12-07 NaN
24 2020-11-25 b 0.853701 2020-12-01 2020-12-07 NaN
25 2020-11-26 b 0.494347 2020-12-01 2020-12-07 NaN
26 2020-11-27 b 0.680949 2020-12-01 2020-12-07 NaN
27 2020-11-28 b 0.247310 2020-12-01 2020-12-07 NaN
28 2020-11-29 b 0.777140 2020-12-01 2020-12-07 NaN
29 2020-11-30 b 0.552633 2020-12-01 2020-12-07 NaN
30 2020-12-01 b 0.330672 2020-12-01 2020-12-07 NaN
31 2020-12-02 b 0.295119 2020-12-01 2020-12-07 0.295119
32 2020-12-03 b 0.361580 2020-12-01 2020-12-07 0.361580
33 2020-12-04 b 0.874205 2020-12-01 2020-12-07 0.874205
34 2020-12-05 b 0.754738 2020-12-01 2020-12-07 0.754738
35 2020-12-06 b 0.135053 2020-12-01 2020-12-07 0.135053
36 2020-12-07 b 0.998768 2020-12-01 2020-12-07 NaN
37 2020-12-08 b 0.955664 2020-12-01 2020-12-07 NaN
38 2020-12-09 b 0.330856 2020-12-01 2020-12-07 NaN
39 2020-12-10 b 0.826502 2020-12-01 2020-12-07 NaN
насколько велик dfp?