index - pandas python
¿Cómo calculo un idxmax rodante? (4)
Aquí hay un enfoque que utiliza 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 rotatorias, indexa en la versión de matriz extraída con esos y así obtiene los índices máximos para cada ventana. Para una indexación más eficiente, podemos usar los NumPy strides
, como ese:
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)
considerar el 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 de 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
c c
d c
e e
f e
g e
h f
i i
j i
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 existe una forma sencilla de hacerlo, ya que el argumento que se pasa a la función de aplicación continua es una matriz numérica simple, no una serie de pandas, por lo que no conoce el índice. Además, las funciones de balanceo deben devolver un resultado flotante, por lo que no pueden devolver directamente los valores del í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 de argmax agregamos cero, porque nos está dando el índice en una subsecuencia que comienza en el índice 0 en la serie original; para el segundo valor de argmax agregamos uno, porque nos está dando el índice en una subsecuencia comenzando en el índice 1 en la serie original; etc.)
Esto proporciona los resultados correctos, pero no incluye los dos valores "Ninguno" al principio; Tendría que volver a agregarlos manualmente si los quisiera.
Existe un problema de pandas abierto para agregar idxmax rodante.
También puede simular la ventana DataFrame
creando un DataFrame
y usar 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 primeros dos términos son el idxmax
aplicado a las ventanas iniciales de las longitudes 1 y 2 en lugar de los valores nulos. No es tan eficiente como la respuesta aceptada y probablemente no es una buena idea para ventanas grandes, sino simplemente otra perspectiva.
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:])
c c
d c
e e
f e
g e
h f
i i
j i
dtype: object