考虑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
这显然不是我想要的
答案 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