Suponiendo que tengo una matriz numpy como: [1,2,3,4,5,6] y otra matriz: [0,0,1,2,2,1] Quiero sumar los elementos en la primera matriz por grupo (la segunda matriz) y obtener resultados de n-groups en orden de número de grupo (en este caso, el resultado sería [3, 9, 9]). ¿Cómo hago esto en numpy?Suma matriz por número en numpy
Respuesta
Hay más de una manera de hacer esto, pero aquí es una manera:
import numpy as np
data = np.arange(1, 7)
groups = np.array([0,0,1,2,2,1])
unique_groups = np.unique(groups)
sums = []
for group in unique_groups:
sums.append(data[groups == group].sum())
Usted puede Vectorize cosas por lo que no hay para el lazo en absoluto, pero me gustaría recomendar en contra de ella. Se vuelve ilegible y requerirá un par de arreglos temporales en 2D, lo que podría requerir grandes cantidades de memoria si tiene muchos datos.
Editar: Aquí hay una forma de vectorizar completamente. Tenga en cuenta que esto puede (y probablemente será) más lento que la versión anterior. (Y puede haber una forma mejor de vectorizar esto, pero es tarde y estoy cansado, así que esto es solo lo primero que me viene a la cabeza ...)
Sin embargo, tenga en cuenta que este es un mal ejemplo ... Eres realmente mejor (tanto en términos de velocidad y facilidad de lectura) con el bucle de arriba ...
import numpy as np
data = np.arange(1, 7)
groups = np.array([0,0,1,2,2,1])
unique_groups = np.unique(groups)
# Forgive the bad naming here...
# I can't think of more descriptive variable names at the moment...
x, y = np.meshgrid(groups, unique_groups)
data_stack = np.tile(data, (unique_groups.size, 1))
data_in_group = np.zeros_like(data_stack)
data_in_group[x==y] = data_stack[x==y]
sums = data_in_group.sum(axis=1)
¡Gracias! La memoria no es un problema y me gustaría evitar los bucles. ¿Cómo lo vectorizarías? –
@Scribble Master - Ver la edición ... Sin embargo, no hay nada de malo en pasar por encima de los grupos únicos. La segunda versión probablemente sea lenta, y es muy difícil de leer. Con el bucle, solo está bucleando (en python, de todos modos) sobre el número de grupos únicos. La comparación interna 'data [groups == group]' será bastante rápida. –
¡Gracias de nuevo! –
Una aplicación Python puro:
l = [1,2,3,4,5,6]
g = [0,0,1,2,2,1]
from itertools import izip
from operator import itemgetter
from collections import defaultdict
def group_sum(l, g):
groups = defaultdict(int)
for li, gi in izip(l, g):
groups[gi] += li
return map(itemgetter(1), sorted(groups.iteritems()))
print group_sum(l, g)
[3, 9, 9]
Si los grupos son indexado por enteros consecutivos, puede abusar de la función numpy.histogram()
para obtener el resultado:
data = numpy.arange(1, 7)
groups = numpy.array([0,0,1,2,2,1])
sums = numpy.histogram(groups,
bins=numpy.arange(groups.min(), groups.max()+2),
weights=data)[0]
# array([3, 9, 9])
Esto evitará cualquier bucle de Python.
¡Buen punto! +1 de mi parte –
Este es un método vectorizado de hacer esta suma basado en la implementación de numpy.unique. De acuerdo con mis tiempos, es hasta 500 veces más rápido que el método de bucle y hasta 100 veces más rápido que el método de histograma.
def sum_by_group(values, groups):
order = np.argsort(groups)
groups = groups[order]
values = values[order]
values.cumsum(out=values)
index = np.ones(len(groups), 'bool')
index[:-1] = groups[1:] != groups[:-1]
values = values[index]
groups = groups[index]
values[1:] = values[1:] - values[:-1]
return values, groups
¡Funciona brillantemente! – Nate
La función numpy bincount
se hizo precisamente para este propósito y estoy seguro de que será mucho más rápido que los otros métodos para todos los tamaños de entradas:
data = [1,2,3,4,5,6]
ids = [0,0,1,2,2,1]
np.bincount(ids, weights=data) #returns [3,9,9] as a float64 array
El elemento i de el resultado es la suma de todos los elementos data
correspondientes a "id" i
.
Espero que ayude.
Puede confirmar que esto es muy rápido. Aproximadamente 10 veces más rápido que el método sum_by_group que Bi Rico proporcionó en pequeñas entradas. –
¿y si 'data' son vectores? – zzh1996
Parece que el argumento de los pesos tiene que ser de 1 dimensión. Una solución es ejecutar bincount una vez para cada dimensión del vector (es decir, dos veces si los datos son un conjunto de vectores bidimensionales). Una pequeña modificación de la respuesta de Peter también debería funcionar. – Alex
me trataron guiones de todos y mis consideraciones son:
Joe: sólo funcionará si usted tiene pocos grupos.
kevpie: Demasiado lento debido a los bucles (esto no es así Pythonic)
Bi_Rico y Sven: realizar buenas, pero sólo funcionarán para Int32 (si la suma va más de 2^32/2 se producirá un error)
Alex: es el más rápido, bueno para la suma.
Pero si quieres más flexibilidad y la posibilidad de agrupar por otras estadísticas sobre el uso SciPy:
from scipy import ndimage
data = np.arange(10000000)
groups = np.arange(1000).repeat(10000)
ndimage.sum(data, groups, range(1000))
Esto es bueno porque tiene muchas estadísticas de grupo (suma, media, la varianza, ...).
me di cuenta de la etiqueta numpy
pero en caso de que no les importa usar pandas
, esta tarea se convierte en una sola línea:
import pandas as pd
import numpy as np
data = np.arange(1, 7)
groups = np.array([0, 0, 1, 2, 2, 1])
df = pd.DataFrame({'data': data, 'groups': groups})
Así df
tendrá el aspecto siguiente:
data groups
0 1 0
1 2 0
2 3 1
3 4 2
4 5 2
5 6 1
Ahora puede usar las funciones groupby()
y sum()
print df.groupby(['groups'], sort=False).sum()
que le da la salida deseada
data
groups
0 3
1 9
2 9
Por defecto, sería solucionado la trama de datos, por lo tanto, usar la bandera sort=False
que podría mejorar la velocidad de tramas de datos enormes.
¡Estás todo mal! La mejor manera de hacerlo es:
a = [1,2,3,4,5,6]
ix = [0,0,1,2,2,1]
accum = np.zeros(np.max(ix)+1)
np.add.at(accum, ix, a)
print accum
> array([ 3., 9., 9.])
- 1. Suma una fila de una matriz NumPy
- 2. suma acumulativa de una matriz de numpy por el índice
- 3. Correr suma acumulada de 1d matriz NumPy
- 4. Long (> 20million element) suma de matriz en python numpy
- 5. suma de Python contra Numpy.sum de NumPy
- 6. Automatizar suma en la matriz
- 7. suma numpy lo largo del eje
- 8. matriz Numpy 2D Resta por fila
- 9. Numpy: ordenar una matriz multidimensional por una matriz multidimensional
- 10. multiplicar numpy matriz de escalares por matriz de vectores
- 11. acumulativa matriz suma en Ruby
- 12. Creando una matriz en numpy/scipy por iteración en Python?
- 13. Numpy matriz multidimensional rebanar
- 14. Convertir una matriz 1D en una matriz 2D en numpy
- 15. ¿Ver en una matriz numpy?
- 16. Grupo por max o min en una matriz numpy
- 17. Numpy matriz simétrica 'inteligente'
- 18. Flatten OpenCV/Numpy matriz
- 19. Python (Numpy) matriz de clasificación
- 20. matriz numpy inmutable?
- 21. filas eliminación en la matriz numpy
- 22. ¿Sumar de manera eficiente una matriz numpy pequeña, transmitida a través de una matriz numpy descomunal?
- 23. Suma de diferencias cuadradas (SSD) en numpy/scipy
- 24. Cortar la matriz numpy con otra matriz
- 25. Suma de matriz de Javascript
- 26. Número aleatorio no repetitivo en numpy
- 27. cuestión matriz singular con Numpy
- 28. matriz suma de valor basado en
- 29. Encontrar valores faltantes en una matriz numpy
- 30. ¿Cómo normalizar una matriz numpy bidimensional en python menos detallada?
¿Por qué necesitas numpy para esto? ¿No estás usando listas vanilla python? Si no, ¿qué tipo de numpy estás usando? –
Necesito numpy para esto porque no quiero recorrer la matriz n veces para n grupos, ya que los tamaños de mi matriz pueden ser arbitrariamente grandes. No estoy usando listas de Python, solo estaba mostrando un conjunto de datos de ejemplo entre paréntesis. El tipo de datos es int. –
relacionado http://stackoverflow.com/questions/7089379/most-efficient-way-to-sum-huge-2d-numpy-array-grouped-by-id-column – TooTone