существует ли более эффективный способ получить среднее значение массива в заранее определенных ячейках? например, у меня есть массив чисел и массив, соответствующий начальным и конечным позициям bin в этом массиве, и я хочу просто взять среднее значение в этих ячейках? У меня есть код, который делает это ниже, но мне интересно, как его можно сократить и улучшить. спасибо.
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
Ответ 1
Вероятно, быстрее и проще использовать 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])
Попробуйте сами, какой из них быстрее...:)
Ответ 2
Функция 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]
Ответ 3
Не знаю, почему эта нить стала некротической; но вот одобренный ответ 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
Пакет numpy_indexed (отказ от ответственности: я являюсь его автором) содержит функциональные возможности для эффективного выполнения операций этого типа:
import numpy_indexed as npi
print(npi.group_by(np.digitize(data, bins)).mean(data))
Это по существу то же самое решение, что и предыдущее; но теперь завернутый в приятный интерфейс, с тестами и все:)
Ответ 5
Я бы добавил, а также, чтобы ответить на вопрос найти средние значения bin с помощью python histogram2d, что scipy также имеет функцию, специально разработанную для вычислить двумерную бинную статистику для одного или нескольких наборов данных
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 является обобщением этой функции для наборов данных более высоких размеров
Ответ 6
Другой альтернативой является использование 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)