2011-05-28 20 views
75

¿hay una manera más eficiente de tomar un promedio de una matriz en contenedores preespecificados? por ejemplo, tengo una matriz de números y una matriz correspondiente a las posiciones inicial y final de la bandeja en esa matriz, y quiero simplemente tomar la media en esas ubicaciones. Tengo un código que lo hace a continuación, pero me pregunto cómo se puede reducir y mejorar. Gracias.agrupando datos en python con scipy/numpy

from scipy import * 
from numpy import * 

def get_bin_mean(a, b_start, b_end): 
    ind_upper = nonzero(a >= b_start)[0] 
    a_upper = a[ind_upper] 
    a_range = a_upper[nonzero(a_upper < b_end)[0]] 
    mean_val = mean(a_range) 
    return mean_val 


data = rand(100) 
bins = linspace(0, 1, 10) 
binned_data = [] 

n = 0 
for n in range(0, len(bins)-1): 
    b_start = bins[n] 
    b_end = bins[n+1] 
    binned_data.append(get_bin_mean(data, b_start, b_end)) 

print binned_data 

Respuesta

117

es probable que sea más rápido y más fácil de usar numpy.digitize():

import numpy 
data = numpy.random.random(100) 
bins = numpy.linspace(0, 1, 10) 
digitized = numpy.digitize(data, bins) 
bin_means = [data[digitized == i].mean() for i in range(1, len(bins))] 

Una alternativa a esto es utilizar numpy.histogram():

bin_means = (numpy.histogram(data, bins, weights=data)[0]/
      numpy.histogram(data, bins)[0]) 

Pruebe por sí mismo cuál es el más rápido ...:)

+0

No veo un diff - ¿qué es más rápido? – user248237dfsf

+3

@user: no sé cuál es más rápido para sus datos y parámetros. Ambos métodos deberían ser más rápidos que los tuyos, y esperaría que el método 'histogram()' fuera más rápido para una gran cantidad de contenedores. Pero tendrás que perfilarte a ti mismo, no puedo hacer esto por ti. –

14

No estoy seguro de por qué este hilo se necroed; pero aquí es una respuesta aprobada 2014, lo que debería ser mucho más rápido:

import numpy as np 

data = np.random.rand(100) 
bins = 10 
slices = np.linspace(0, 100, bins+1, True).astype(np.int) 
counts = np.diff(slices) 

mean = np.add.reduceat(data, slices[:-1])/counts 
print mean 
+1

estás respondiendo a una pregunta diferente. Por ejemplo, su 'mean [0] = np.mean (data [0:10])', mientras que la respuesta correcta debería ser 'np.mean (data [data <10])' –

28

El Scipy (> = 0.11) la función scipy.stats.binned_statistic se refiere específicamente a la pregunta anterior.

Para el mismo ejemplo que en las respuestas anteriores, la solución Scipy sería

import numpy as np 
from scipy.stats import binned_statistic 

data = np.random.rand(100) 
bin_means = binned_statistic(data, data, bins=10, range=(0, 1))[0] 
3

El numpy_indexed paquete (exención de responsabilidad: yo soy su autor) contiene funcionalidad para llevar a cabo de manera eficiente las operaciones de este tipo:

import numpy_indexed as npi 
print(npi.group_by(np.digitize(data, bins)).mean(data)) 

Esta es esencialmente la misma solución que la que publiqué anteriormente; pero ahora envuelto en una interfaz agradable, con las pruebas y todos :)

2

yo añadiría, y también para responder a la pregunta find mean bin values using histogram2d python que el scipy también tienen una función especialmente diseñada para compute a bidimensional binned statistic for one or more sets of data

import numpy as np 
from scipy.stats import binned_statistic_2d 

x = np.random.rand(100) 
y = np.random.rand(100) 
values = np.random.rand(100) 
bin_means = binned_statistic_2d(x, y, values, bins=10).statistic 

la función scipy.stats.binned_statistic_dd es una generalización de esta función para conjuntos de datos de mayores dimensiones