web-dev-qa-db-fra.com

binning des données en python avec scipy/numpy

existe-t-il un moyen plus efficace de prendre la moyenne d'un tableau dans des bacs spécifiés? Par exemple, j'ai un tableau de nombres et un tableau correspondant aux positions de début et de fin du bac dans ce tableau, et je veux simplement prendre la moyenne dans ces bacs? J'ai un code qui le fait ci-dessous mais je me demande comment il peut être réduit et amélioré. Merci.

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
84
user248237dfsf

C'est probablement plus rapide et plus facile à utiliser 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))]

Une autre solution consiste à utiliser numpy.histogram() :

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

Essayez par vous-même lequel est le plus rapide ... :)

142
Sven Marnach

La fonction Scipy (> = 0.11) scipy.stats.binned_statistic répond spécifiquement à la question ci-dessus.

Pour le même exemple que dans les réponses précédentes, la solution Scipy serait

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]
32
divenex

Vous ne savez pas pourquoi ce fil a été nécrosé; mais voici une réponse approuvée pour 2014, qui devrait être beaucoup plus rapide:

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
14
Eelco Hoogendoorn

Le package numpy_indexed package (disclaimer: je suis son auteur) contient des fonctionnalités permettant d'effectuer efficacement des opérations de ce type:

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

C’est essentiellement la même solution que celle que j’ai postée plus tôt; mais maintenant enveloppé dans une interface agréable, avec des tests et tout :)

4

J'ajouterais, et aussi pour répondre à la question trouver les valeurs de bin moyennes en utilisant histogram2d python que les scipy ont aussi une fonction spécialement conçue pour calculer une statistique bidimensionnelle séparée pour un ou plusieurs ensembles de données

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 fonction scipy.stats.binned_statistic_dd est une généralisation de cette fonction pour les ensembles de données de dimensions supérieures

1
Chmeul

Une autre alternative consiste à utiliser le fichier ufunc.at. Cette méthode applique sur place l'opération souhaitée à des index spécifiés .. Nous pouvons obtenir la position de la corbeille pour chaque point de donnée à l'aide de la méthode searchsorted. Ensuite, nous pouvons utiliser pour incrémenter de 1 la position de l’histogramme à l’index donné par bin_indexes, chaque fois que nous rencontrons un index à bin_indexes. 

np.random.seed(1)
data = np.random.random(100) * 100
bins = np.linspace(0, 100, 10)

histogram = np.zeros_like(bins)

bin_indexes = np.searchsorted(bins, data)
np.add.at(histogram, bin_indexes, 1)
0
kostas