如何计算滚动idxmax

时间:2016-10-18 06:35:34

标签: python pandas numpy dataframe series

考虑pd.Series s

import pandas as pd
import numpy as np

np.random.seed([3,1415])
s = pd.Series(np.random.randint(0, 10, 10), list('abcdefghij'))
s

a    0
b    2
c    7
d    3
e    8
f    7
g    0
h    6
i    8
j    6
dtype: int64

我想得到滚动窗口最大值为3

的索引
s.rolling(3).max()

a    NaN
b    NaN
c    7.0
d    7.0
e    8.0
f    8.0
g    8.0
h    7.0
i    8.0
j    8.0
dtype: float64

我想要的是

a    None
b    None
c       c
d       c
e       e
f       e
g       e
h       f
i       i
j       i
dtype: object

我做了什么

s.rolling(3).apply(np.argmax)

a    NaN
b    NaN
c    2.0
d    1.0
e    2.0
f    1.0
g    0.0
h    0.0
i    2.0
j    1.0
dtype: float64

这显然不是我想要的

5 个答案:

答案 0 :(得分:10)

没有简单的方法可以做到这一点,因为传递给滚动应用函数的参数是一个普通的numpy数组,而不是pandas系列,所以它不知道索引。此外,滚动函数必须返回浮点结果,因此如果它们不浮动,它们就不能直接返回索引值。

这是一种方法:

>>> s.index[s.rolling(3).apply(np.argmax)[2:].astype(int)+np.arange(len(s)-2)]
Index([u'c', u'c', u'e', u'e', u'e', u'f', u'i', u'i'], dtype='object')

我们的想法是获取argmax值并将它们与系列对齐,方法是添加一个值,表示我们在系列中的距离。 (也就是说,对于第一个argmax值,我们加零,因为它给我们索引到原始序列中从索引0开始的子序列;对于第二个argmax值,我们添加一个,因为它给了我们索引到一个从原始系列中的索引1开始的子序列;等等。)

这给出了正确的结果,但没有包括两个"无"开头的价值观;如果您需要,您必须手动添加它们。

an open pandas issue添加滚动idxmax。

答案 1 :(得分:2)

以下是使用broadcasting -

的方法
maxidx = (s.values[np.arange(s.size-3+1)[:,None] + np.arange(3)]).argmax(1)
out = s.index[maxidx+np.arange(maxidx.size)]

这将生成与滚动窗口相对应的所有索引,将索引转换为提取的数组版本,从而获得每个窗口的最大索引。为了更有效地建立索引,我们可以使用NumPy strides,就像这样 -

arr = s.values
n = arr.strides[0]
maxidx = np.lib.stride_tricks.as_strided(arr, \
                   shape=(s.size-3+1,3), strides=(n,n)).argmax(1)

答案 2 :(得分:2)

我使用了发电机

def idxmax(s, w):
    i = 0
    while i + w <= len(s):
        yield(s.iloc[i:i+w].idxmax())
        i += 1

pd.Series(idxmax(s, 3), s.index[2:])

c    c
d    c
e    e
f    e
g    e
h    f
i    i
j    i
dtype: object

答案 3 :(得分:1)

您还可以通过创建DataFrame并使用idxmax来模拟滚动窗口,如下所示:

window_values = pd.DataFrame({0: s, 1: s.shift(), 2: s.shift(2)})
s.index[np.arange(len(s)) - window_values.idxmax(1)]

Index(['a', 'b', 'c', 'c', 'e', 'e', 'e', 'f', 'i', 'i'], dtype='object', name=0)

如您所见,前两个术语是应用于长度为1和2的初始窗口而不是空值的idxmax。 它不如公认的答案那么有效,对于大窗户可能不是一个好主意,而只是另一个视角。

答案 4 :(得分:1)

只是了解我如何解决类似的问题。我不想精确地找到索引,我想找到最大值发生多久了。但这也可以用来查找索引。

我基本上是在使用轮班策略,但是我正在以可配置的长度迭代几个轮班。它可能很慢,但是对我来说足够好了。

import pandas as pd


length = 5

data = [1, 2, 3, 4, 5, 4, 3, 4, 5, 6, 7, 6, 5, 4, 5, 4, 3]
df = pd.DataFrame(data, columns=['number'])
df['helper_max'] = df.rolling(length).max()

for i in range(length, -1, -1):
    # Set the column to what you want. You may grab the index 
    # if you wish, I wanted number of rows since max happened
    df.loc[df['number'].shift(i) == df['helper_max'], 'n_rows_ago_since_max'] = i

print(df)

输出:

    number  helper_max  n_rows_ago_since_max
0        1         NaN                   NaN
1        2         NaN                   NaN
2        3         NaN                   NaN
3        4         NaN                   NaN
4        5         5.0                   0.0
5        4         5.0                   1.0
6        3         5.0                   2.0
7        4         5.0                   3.0
8        5         5.0                   0.0
9        6         6.0                   0.0
10       7         7.0                   0.0
11       6         7.0                   1.0
12       5         7.0                   2.0
13       4         7.0                   3.0
14       5         7.0                   4.0
15       4         6.0                   4.0
16       3         5.0                   2.0