Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

113
Vistas
Aplicar un cumcount a cada grupo de enteros idénticos

Digamos que tengo la siguiente matriz de enteros de orden ascendente (algunos pueden ser negativos):

 a = np.array([ 1, 1, 1, 1, 10, 10, 20, 20, 20, 30, 40, 40, 40, 40])

Quiero convertirlo en esto:

 a = np.array([ 1, 2, 3, 4, 10, 11, 20, 21, 22, 30, 40, 41, 42, 43])

...donde cada entero en cada grupo de los mismos enteros se incrementa, así que para los primeros 1:

 1 1 1 1 <--- these are the numbers from the array + 0 1 2 3 <--- these are counts of the number for its group ------- 1 2 3 4

¿Hay una manera más eficiente de hacer esto que la siguiente?

 a = np.array([ 1, 1, 1, 1, 10, 10, 20, 20, 20, 30, 40, 40, 40, 40]) ones = (a == np.pad(a, (1,0))[:-1]).astype(int) ones[ones == 0] = -np.diff(np.concatenate(([0.], np.cumsum(ones != 0)[ones == 0]))) new_a = a + ones.cumsum()

Tenga en cuenta que la matriz siempre estará en orden ascendente (de menor a mayor), y los números siempre serán enteros, y algunos pueden ser negativos.


Explicación, si no entiendes:

De hecho, ya lo hice funcionar, con la ayuda de esta publicación . Lo que estoy haciendo ahora es generar una matriz como esta, donde 0 marca el primero de un grupo de números idénticos y 1 marca el resto:

 1 1 1 1 10 10 20 20 20 30 40 40 40 40 0 1 1 1 0 1 0 1 1 0 0 1 1 1 ^ first 1 ^ first 10 ^ first 30 ^ first 20 ^ first 40

y luego usando la técnica de la publicación vinculada anteriormente para acumular todos los que están en esa matriz:

 # Shift `a` by one and compare it with the original array >>> ones = (a == np.pad(a, (1,0))[:-1]).astype(int) >>> ones array([0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1]) # This line is from the linked post (modified, of course) >>> ones[ones == 0] = -np.diff(np.concatenate(([0.], np.cumsum(ones != 0)[ones == 0]))) >>> ones array([ 0, 1, 1, 1, -3, 1, -1, 1, 1, -2, 0, 1, 1, 1]) >>> ones.cumsum() array([0, 1, 2, 3, 0, 1, 0, 1, 2, 0, 0, 1, 2, 3])

Ahora, podemos agregar esa matriz resultante a la original:

 >>> a array([ 1, 1, 1, 1, 10, 10, 20, 20, 20, 30, 40, 40, 40, 40]) >>> a + ones.cumsum() array([ 1, 2, 3, 4, 10, 11, 20, 21, 22, 30, 40, 41, 42, 43])
over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

Usar np.unique podría ser un poco más elegante:

 u, i = np.unique(a, return_index=True) # Indices where the sums restart b = np.ones_like(a) b[i] = u b[i[1:]] -= np.add.reduceat(b, i)[:-1] # Subtract the sum of the prior region from the next result = b.cumsum()

Dado que la matriz ya está ordenada, puede acceder directamente a esa parte de np.unique :

 i = np.r_[0, np.flatnonzero(np.diff(a)) + 1] # Get the indices directly from the diff b = np.ones_like(a) b[i] = a[i] b[i[1:]] -= np.add.reduceat(b, i)[:-1] result = b.cumsum()

Pero espera, la suma de cada región es solo la longitud más el valor inicial menos uno. Eso elimina la necesidad de sumar dos veces:

 i = np.r_[0, np.flatnonzero(np.diff(a)) + 1] b = np.ones_like(a) b[i] = a[i] b[i[1:]] -= np.diff(i) + a[i[:-1]] - 1 # Simpler way to sum the prior region result = b.cumsum()

Puedes simplificar un poco más. Dado que a[i[k]] es el comienzo de una ejecución, a[i[k] - 1] es lo mismo que a[i[k - 1]] . En otras palabras, el inicio de la ejecución anterior es el mismo que el último elemento de la ejecución anterior:

 d = np.diff(a) i = np.r_[0, np.flatnonzero(d) + 1] b = np.ones_like(a) b[0] = a[0] b[i[1:]] = d[i[1:] - 1] - np.diff(i) + 1 # Current region minus prior, reusing diff result = b.cumsum()

Cualquiera de las dos últimas versiones debería ser mejor que lo que está haciendo actualmente.

El código anterior está escrito para simplificar y acelerar. Si desea hacerlo más corto e ilegible, y está utilizando Python 3.8+, puede comenzar a usar el operador morsa:

 i = np.r_[0, np.flatnonzero(d := np.diff(a)) + 1] (b := np.ones_like(a))[0] = a[0] b[i[1:]] = d[i[1:] - 1] - np.diff(i) + 1 result = b.cumsum()

Dado que walrus evalúa de izquierda a derecha, puede crear una parodia final:

 (b := np.ones_like(a))[0] = a[0] b[(i := np.r_[0, np.flatnonzero(d := np.diff(a)) + 1])[1:]] = d[i[1:] - 1] - np.diff(i) + 1 result = b.cumsum()

Similar para el otro enfoque:

 (b := np.ones_like(a))[i := np.r_[0, np.flatnonzero(np.diff(a)) + 1]] = a[i] b[i[1:]] -= np.diff(i) + a[i[:-1]] - 1 result = b.cumsum()
over 4 years ago · Santiago Trujillo Denunciar

0

No estoy seguro de si esto es muy eficiente, pero es una sola línea:

 np.hstack([x + np.r_[:x.size] for x in np.split(a, np.flatnonzero(np.diff(a))+1)])
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda