使用包含 shift 方法的动态表达式获取 pandas DataFrame 的子集

Get subset of pandas DataFrame using dynamic expression including the shift method

我有这个 pandas 数据框:

In [1]: import pandas as pd

In [2]: df = pd.DataFrame([[43.97, 43.97, 43.75, 43.94],
   ...:                    [43.97, 44.25, 43.97, 44.25],
   ...:                    [44.22, 44.38, 44.12, 44.34],
   ...:                    [44.41, 44.84, 44.38, 44.81],
   ...:                    [44.97, 45.09, 44.47, 45.00],
   ...:                    [44.97, 45.06, 44.72, 44.97],
   ...:                    [44.97, 45.12, 44.91, 44.97]],
   ...:                   columns=['O', 'H', 'L', 'C'])

感谢@JoeKington,我能够使用这个表达式得到它的一个子集:

In [3]: values = df[(df.C > df.H.shift(2)) & (df.H > df.H.shift(1))]

In [4]: print values
       O      H      L      C
2  44.22  44.38  44.12  44.34
3  44.41  44.84  44.38  44.81
4  44.97  45.09  44.47  45.00

我想做的是进行一系列比较,例如:

C0 > L0 AND L0 > H2 AND H2 > L1 AND L1 > L2
H0 > C0 AND C0 > H1 AND H1 > C1 AND C1 > H2 AND H2 > L1 AND L1 > L2

并将它们转换成可用于 slice/filter/query 数据框的东西。我可以毫无问题地使用其中一个字符串并创建一个看起来像这样的字符串。

(df.C > df.L) & (df.L > df.H.shift(2)) & (df.H.shift(2) > df.L.shift(1)) & (df.L.shift(1) > df.L.shift(2))

我们称这个字符串为条件。现在,如果我想将它用于 return 数组的一个子集,我不能执行以下操作,因为这里不需要字符串。

values = df[condition]

我尝试使用这样的查询方法 values = df.query(condition),但我认为 shift 导致它失败,因为我收到此错误:NotImplementedError: 'Call' nodes are not implemented

我已通读 pandas 文档并搜索了数小时的解决方案,但没有找到。我是 pythonpandasnumpy 的新手。非常感谢任何指导。

使用字符串中的公式通常是失误的标志,但如果您已经有了它们,那么我们不妨使用它们。像

s = "C0 > L0 AND L0 > H2 AND H2 > L1 AND L1 > L2"
s = s.replace(" AND ", " and ")
shifted_cols = sorted({term for term in s.split() if 
                       term[0].isalpha() and term.lower() not in {"and", "or"}})
cshifts = [(c, c[0], int(c[1:])) for c in shifted_cols]
df_shift = pd.DataFrame({col: df[base_col].shift(s) for col, base_col, s in cshifts})
df.loc[df_shift.eval(s)]

会给

>>> df.loc[df_shift.eval(s)]
       O      H      L      C
3  44.41  44.84  44.38  44.81

之所以可行,是因为我们发现了我们需要的移位列:

>>> shifted_cols
['C0', 'H2', 'L0', 'L1', 'L2']

将其分解为 column + shift(这里的列都是一个字母,所以我做了尽可能简单的事情,这不是很健壮,但是切换到更聪明的东西是微不足道的):

>>> cshifts
[('C0', 'C', 0), ('H2', 'H', 2), ('L0', 'L', 0), ('L1', 'L', 1), ('L2', 'L', 2)]

然后我们构建一个临时数据框,我们可以在上面评估我们的字符串:

>>> df_shift
      C0     H2     L0     L1     L2
0  43.94    NaN  43.75    NaN    NaN
1  44.25    NaN  43.97  43.75    NaN
2  44.34  43.97  44.12  43.97  43.75
3  44.81  44.25  44.38  44.12  43.97
4  45.00  44.38  44.47  44.38  44.12
5  44.97  44.84  44.72  44.47  44.38
6  44.97  45.09  44.91  44.72  44.47
>>> df_shift.eval(s)
0    False
1    False
2    False
3     True
4    False
5    False
6    False
dtype: bool

我们最终用它来索引我们的原始框架。