149 votes

binning de données en python avec scipy/numpy

J'ai un tableau de nombres et un tableau correspondant aux positions de début et de fin de bac dans ce tableau, et je veux juste prendre la moyenne dans ces bacs ? J'ai un code qui le fait ci-dessous mais je me demande comment le réduire et l'améliorer. 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

228voto

Sven Marnach Points 133943

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 alternative à cela est d'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... :)

1 votes

Je ne vois pas de différence - lequel est le plus rapide ?

6 votes

@user : Je ne sais pas laquelle est la plus rapide pour vos données et paramètres. Les deux méthodes devraient être plus rapides que les vôtres, et je m'attendrais à ce que la méthode de l'utilisateur soit la plus rapide. histogram() pour être plus rapide pour un grand nombre de bacs. Mais vous devrez établir le profil vous-même, je ne peux pas le faire pour vous.

56voto

divenex Points 5192

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 la suivante

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]

17voto

Eelco Hoogendoorn Points 2218

Je ne sais pas pourquoi ce fil a été nécrosé, mais voici une réponse approuvée en 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

3 votes

Vous répondez à une autre question. Par exemple, votre mean[0] = np.mean(data[0:10]) alors que la bonne réponse devrait être np.mean(data[data < 10])

6voto

Eelco Hoogendoorn Points 2218

El numpy_indexé (disclaimer : je suis son auteur) contient des fonctionnalités pour effectuer efficacement des opérations de ce type :

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

Il s'agit essentiellement de la même solution que celle que j'ai postée plus tôt, mais maintenant enveloppée dans une interface agréable, avec des tests et tout le reste :)

6voto

Chmeul Points 49

J'ajouterais, et aussi pour répondre à la question trouver les valeurs moyennes des bin à l'aide d'histogramme2d python que les scipy ont aussi une fonction spécialement conçue pour calculer une statistique bidimensionnelle en binôme 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 plus grande dimension.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X