¿Cómo calculo un idxmax rodante

considera la serie pd.Series

 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 

Quiero obtener el índice para el valor máximo para la ventana móvil de 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 

Lo que quiero es

 a None b None cc dc ee fe ge hf ii ji dtype: object 

Qué he hecho

 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 

que obviamente no es lo que quiero

No hay una forma simple de hacerlo, porque el argumento que se pasa a la función de aplicación continua es una matriz de números simples, no una serie de pandas, por lo que no conoce el índice. Además, las funciones de rotación deben devolver un resultado flotante, por lo que no pueden devolver directamente los valores de índice si no son flotantes.

Aquí hay un enfoque:

 >>> 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') 

La idea es tomar los valores de argmax y alinearlos con la serie agregando un valor que indique qué tan avanzado estamos en la serie. (Es decir, para el primer valor argmax agregamos cero, porque nos da el índice en una subsecuencia que comienza en el índice 0 en la serie original; para el segundo valor argmax agregamos uno, porque nos da el índice en una subsecuencia que comienza en el índice 1 en la serie original; etc.)

Esto da los resultados correctos, pero no incluye los dos valores “Ninguno” al principio; Tendrías que agregarlos manualmente si los quisieras.

Hay un problema abierto de pandas para agregar idxmax rodante.

Aquí hay un enfoque utilizando la broadcasting

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

Esto genera todos los índices correspondientes a las ventanas móviles, los índices en la versión de matriz extraída con esos y, por lo tanto, obtiene los índices máximos para cada ventana. Para una indexación más eficiente, podemos usar NumPy strides , como así:

 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) 

Usé un generador

 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:]) cc dc ee fe ge hf ii ji dtype: object 

También puede simular la ventana móvil creando un DataFrame y usando idxmax siguiente manera:

 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) 

Como puede ver, los dos primeros términos son el idxmax aplicado a las ventanas iniciales de longitudes 1 y 2 en lugar de valores nulos. No es tan eficiente como la respuesta aceptada y probablemente no sea una buena idea para ventanas grandes, sino solo otra perspectiva.