Digamos que tengo una matriz NumPy:
x = np.array([0, 1, 2, 0, 4, 5, 6, 7, 0, 0])
En cada índice, quiero encontrar la distancia al valor cero más cercano. Si la posición es un cero, devuelva cero como distancia. Después, solo nos interesan las distancias al cero más cercano que está a la derecha de la posición actual. El enfoque súper ingenuo sería algo como:
out = np.full(x.shape[0], x.shape[0]-1)
for i in range(x.shape[0]):
j = 0
while i + j < x.shape[0]:
if x[i+j] == 0:
break
j += 1
out[i] = j
Y la salida sería:
array([0, 2, 1, 0, 4, 3, 2, 1, 0, 0])
Estoy notando un patrón de cuenta regresiva / decremento en la salida entre los ceros. Por lo tanto, podría usar las ubicaciones de los ceros (es decir, zero_indices = np.argwhere(x == 0).flatten()
)
¿Cuál es la forma más rápida de obtener la salida deseada en tiempo lineal?
x.shape[0] - 1
)Respuestas:
Enfoque # 1: ¡
Searchsorted
al rescate por tiempo lineal de manera vectorizada (antes de que entren los chicos de numba)!Enfoque # 2: Otro con algunos
cumsum
-Alternativamente, el último paso de
cumsum
podría ser reemplazado por larepeat
funcionalidad:Enfoque # 3: Otro con mayormente solo
cumsum
-fuente
Podrías trabajar desde el otro lado. Mantenga un contador sobre cuántos dígitos distintos de cero han pasado y asígnelo al elemento en la matriz. Si ve 0, restablezca el contador a 0
Editar: si no hay cero a la derecha, entonces necesita otra verificación
fuente
Puede usar la diferencia entre los índices de cada posición y el máximo acumulado de las posiciones cero para determinar la distancia al cero anterior. Esto se puede hacer hacia adelante y hacia atrás. El mínimo entre la distancia hacia adelante y hacia atrás al cero anterior (o siguiente) será el más cercano:
resultados:
Caso especial donde no hay ceros en los bordes exteriores:
también funciona sin ceros en absoluto
[EDITAR] soluciones no numpy ...
Si está buscando una solución O (N) que no requiera numpy, puede aplicar esta estrategia utilizando la función de acumulación de itertools:
salida:
Si no desea utilizar ninguna biblioteca, puede acumular las distancias manualmente en un bucle:
salida:
fuente
Mi primera intuición sería usar rebanar. Si x puede ser una lista normal en lugar de una matriz numpy, entonces podría usar
si es necesario numpy, entonces puede usar
pero esto es menos eficiente porque está buscando todas las ubicaciones cero a la derecha del valor y luego extrae solo la primera. Definitivamente, una mejor manera de hacer esto en numpy.
fuente
Editar: Lo siento, no lo entendí. Esto le dará la distancia a los ceros más cercanos, ya sea a la izquierda o a la derecha. Pero puedes usarlo
d_right
como resultado intermedio. Sin embargo, esto no cubre el caso límite de no tener ningún cero a la derecha.fuente