Pandas DataFrame 算法

问题描述 投票:0回答:3

假设你有一个

DataFrame
有 n 行,在这种情况下有 3 行:

    High  Low  
0   100  90
1   110  95     
2   105  80

我想计算一行与后续行之间的最大差异,如下所示。

因此,例如,第一个计算是第一行的最高价,减去所有行的最低价:100 - 90、100 - 95 和 100 - 80。这些差异中最大的是 20。移动到下一行,110 - 95、110 - 80。这些差异中最大的是 30。转到最后一行,105 - 80 = 25。所有差异中最大的是 30,所以我想返回元组 (110, 80) ,或等价地,其中

loc
DataFrame
是,(1, 2)

我知道我可以用两个

for loop
。是否有
pythonic
pandas-onic
,我猜
functional
方法来做到这一点?

python pandas functional-programming
3个回答
2
投票

不是最漂亮的解决方案,但您可以利用

:=
运算符:

_, h, l, idx_high, idx_low = max(
    (
        (
            idxm:=((h:=df.at[i, "High"]) - (d2:=df.loc[i:, "Low"])).idxmax(),
            h,
            d2[idxm],
            i,
            idxm
        )
        for i in df.index
    ),
    key=lambda x: x[1] - x[2],
)
print(h, l, idx_high, idx_low)

印花:

110 80 1 2

0
投票

如果将查找范围的起点和终点的步骤分开,这个问题会更容易。您可以通过执行以下操作来避免在数据帧上进行嵌套循环来计算它:

  1. 对于每一行,找到 Low 对该行或任何后续行的最小值。这和
    cummin()
    一样,只是
    cummin()
    在数组中向前移动,而我们希望它向后移动。因此,在应用
    cummin()
    .
  2. 之前和之后反转数组
  3. 接下来,将 High 的每个值与最小的未来 Low 进行比较。这将为您提供范围开始的索引。
  4. 现在您知道范围的开始,搜索出现在范围内或之后的最低值。这相当于搜索使 High 和 Low 之间的差异最大化的值。 (假设高 > 低。)
lowest_future_value = df['Low'][::-1].cummin()[::-1]
hi_start = (df['High'] - lowest_future_value).argmax()
lo_end = df['Low'].iloc[hi_start:].argmin() + hi_start
hi_start, lo_end

这个解决方案在 O(N) 时间内工作,而使用嵌套循环的解决方案需要 O(N^2) 时间。

编辑:这是

df['Low'][::-1].cummin()[::-1]
步骤的替代实现,它跟踪每个值来自的索引。

def backwards_cummin_with_index(series):
    smallest = None
    smallest_idx = None
    ret = []
    for i, s in reversed(list(series.items())):
        if smallest is None or s < smallest:
            smallest = s
            smallest_idx = i
        ret.append((smallest, smallest_idx))
    return reversed(ret)

0
投票

我会使用 广播和

np.triu
只得到相关的组合:

a = np.triu(df['High'].to_numpy()[:, None]-df['Low'].to_numpy())

idx = np.unravel_index(a.argmax(), a.shape)
# (1, 2)

values = df.loc[df.index[idx[0]], 'High'], df.loc[df.index[idx[1]], 'Low']
# (110, 80)

中级

a
,只有上三角是相关的:

array([[10,  5, 20],
       [ 0, 15, 30],
       [ 0,  0, 25]])
© www.soinside.com 2019 - 2024. All rights reserved.