объединение данных в python с scipy / numpy - PullRequest
88 голосов
/ 28 мая 2011

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

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

Ответы [ 6 ]

154 голосов
/ 28 мая 2011

Возможно, быстрее и проще в использовании 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])

Попробуйте сами, какой из них быстрее ...:)

33 голосов
/ 12 ноября 2014

Функция 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]
14 голосов
/ 12 февраля 2014

Не уверен, почему этот поток получил некроед; но вот одобренный в 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
4 голосов
/ 02 апреля 2016

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

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

По сути, это то же решение, что и то, которое я опубликовал.ранее;но теперь завернутый в приятный интерфейс, с тестами и все:)

1 голос
/ 26 июля 2016

Я бы добавил, а также чтобы ответить на вопрос найти средние значения бина, используя histogram2d python , чтобы у scipy также была функция, специально предназначенная для вычисления двухмерной бинарной статистики для одного или нескольких наборов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

функция scipy.stats.binned_statistic_dd является обобщением этой функции для наборов данных более высоких измерений

0 голосов
/ 01 ноября 2018

Другой альтернативой является использование ufunc.at.Этот метод применяет на месте желаемую операцию по указанным индексам.Мы можем получить позицию бина для каждого datapoint, используя метод searchsorted.Затем мы можем использовать 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)
...