дані бінінгу в python з scipy / numpy


108

чи є більш ефективний спосіб взяти середній масив у визначених бінах? наприклад, у мене є масив чисел і масив, відповідний початковій і кінцевій позиціям біна в цьому масиві, і я хочу просто взяти середнє значення в цих бункерах? У мене є код, який робить це нижче, але мені цікаво, як його можна скоротити та покращити. Дякую.

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

Відповіді:


181

Це, мабуть, швидше і простіше у використанні 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))]

Альтернативою цьому є використання numpy.histogram():

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

Спробуйте для себе, хто з них швидший ... :)


1
Я не бачу різниці - що швидше?

4
@user: Я не знаю, який із ваших даних і параметрів швидше. Обидва методи повинні бути швидшими, ніж ваш, і я б очікував, що histogram()метод буде швидшим для великої кількості бункерів. Але вам доведеться профайлювати себе, я не можу цього зробити для вас.
Свен Марнах

39

Функція Scipy (> = 0,11) scipy.stats.binned_statistic спеціально вирішує вищезазначене питання.

На тому ж прикладі, що і в попередніх відповідях, рішення Scipy було б

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]

16

Не впевнений, чому ця нитка не затопилася; але ось відповідь 2014 року, яка має бути набагато швидшою:

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
ви відповідаєте на інше запитання. Наприклад, ваша mean[0] = np.mean(data[0:10]), а правильна відповідь повинна бутиnp.mean(data[data < 10])
Ruggero Turra

5

Пакет numpy_indexed (відмова від відповідальності: я його автор) містить функціонал для ефективного виконання операцій такого типу:

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

Це по суті те саме рішення, що і те, що я розміщував раніше; але зараз загорнутий у приємний інтерфейс, з тестами і все :)


3

Я хотів би додати, а також відповісти на питання пошуку середніх значень біна за допомогою python histogram2d, що scipy також має функцію, спеціально розроблену для обчислення двовимірної binned статистики для одного або декількох наборів даних

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

функція scipy.stats.binned_statistic_dd є узагальненням цієї функції для наборів даних більших розмірів


1

Інша альтернатива - використовувати ufunc.at. Цей метод застосовується на місці потрібної операції за вказаними показниками. Ми можемо отримати бінну позицію для кожної точки даних за допомогою методу, який здійснює пошук. Тоді ми можемо використовувати на приріст на 1 положення гістограми в індексі, заданому bin_indexes, кожен раз, коли ми стикаємося з індексом у 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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.