有一个包含多列的panda数据帧,我想获得每行n
观测值中列'high'
和后续值列'low'
之间的最大差值。
close high low open
0 12.65 13.16 12.63 12.80
1 12.46 12.84 12.28 12.70
2 13.14 13.25 12.63 13.16
3 12.92 13.14 12.79 12.98
4 12.95 13.05 12.69 13.00
5 13.40 13.71 13.03 13.10
让我们举一个例子:假设我们有一个n=3
。在这种情况下,df.max_loss[0]
将是:
max([df.high[0] - df.low[0],
df.high[0] - df.low[1], <---
df.high[0] - df.low[2],
df.high[1] - df.low[1],
df.high[1] - df.low[2],
df.high[2] - df.low[2]]
0.88
可以计算给定子集的值,但我想将其应用于整个df,为每个观测计算接下来三行的max_loss。
def max_loss(high, low, window=3):
lst = []
for ih in np.arange(0,window):
for il in np.arange(ih,window):
dd = round(high[ih] - low[il], 2)
lst.append(dd)
return max(lst)
max_loss(df.high, df.low, 3)
我可以再做一个for loop,但我觉得一定有更优雅的方式。我尝试过使用rolling().apply()
,但没有成功。是否可以将涉及多行和多列的函数应用于滚动窗口?知道吗?
可能不是最快的解决方案,但您可以定义一个自定义函数来交叉合并索引-high
的索引是leq
,而不是low
:
def greater_cartesian(df, n):
idx_frame = df.index[:n].to_frame()
product = idx_frame.merge(idx_frame, how='cross')
product.columns = ['high', 'low']
# filter out the indexes where high has greater index
product = product[product['high'] <= product['low']]
return product
然后在实际数据帧上应用high
和low
上的新索引,得到最大值:
greater_cartesian(df, 3).
apply(lambda row: df.loc[row.high, 'high'] - df.loc[row.low, 'low'], axis=1)
它给出
0 0.53
1 0.88
2 0.53
4 0.56
5 0.21
8 0.62
当然,您可以在apply
之后使用max
获得最大值。
一个非精细化的解决方案是"即兴"创建一个滚动窗口,以子集形式设置初始df。
def max_loss(df, n):
#initialize a max_loss column
df['max_loss'] = np.NaN
#roll through df with an improvised n-sized window
for i in np.arange(0, len(df)-n+1):
df_roll=df[i:i+n].copy()
lst=[]
#compute each loss in the roll (considering ih<=il) & append to the list
for ih in np.arange(0,n):
for il in np.arange(ih,n):
dd = round(df_roll.loc[df_roll.index[ih], 'high'] - df_roll.loc[df_roll.index[il], 'low'], 2)
lst.append(dd)
#get the max
df.loc[df.index[i], 'max_loss'] = max(lst)
return df
df = max_loss(df, n=3)
所需输出。我去掉了不必要的栏以提高可见性。
high low max_loss
0 13.16 12.63 0.88
1 12.84 12.28 0.62
2 13.25 12.63 0.62
3 13.14 12.79 0.68
4 13.05 12.69 NaN
5 13.71 13.03 NaN
然而,通过3 for循环不是很有效,尤其是如果我们想将其扩展到多个大型数据帧。
好的,所以我找到了另一种方法,快了约30倍(尽管门槛很低(
首先,我们生成元组(ih, il)
的列表,其中ih是high
列索引,il是low
列索引,考虑到ih<il
和<n
然后,我们遍历元组,并根据元组移动high
和low
列。我们将获得一系列计算两个移位列之间差异的列。然后,我们简单地获取伪"丢失"数据帧上各列的最大值。
def max_loss2(df, n):
#this is optional, just to avoid warnings when n is to big
from warnings import simplefilter
simplefilter(action="ignore", category=pd.errors.PerformanceWarning)
tuples = [(ih, il) for ih in np.arange(0,n) for il in np.arange(ih,n)]
loss = pd.DataFrame(index = df.index)
for ih, il in tuples:
loss[f'{ih}_{il}'] = round(df.high.shift(-ih) - df.low.shift(-il), 2)
df[f'max_loss{n}'] = loss.max(axis=1)
return df
考虑约400行的df:
%time max_loss2(df, n=5)
CPU times: user 21 ms, sys: 54 µs, total: 21.1 ms
Wall time: 19.7 ms
与之前的";循环通过":
%time df = max_loss(df, n=5)
CPU times: user 672 ms, sys: 14 ms, total: 686 ms
Wall time: 672 ms
有没有更快的想法?:(