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
@ユーザー:データとパラメーターのどちらが速いかわかりません。どちらの方法も、あなたの方法よりも高速である必要がありますhistogram()。また、多数のビンに対しては、この方法の方が高速であることを期待しています。しかし、あなたはあなた自身をプロファイルしなければならないでしょう、私はあなたのためにこれをすることができません。
Sven Marnach、

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

私は追加し、質問に答えるために、scipy は1つ以上のデータセットの2次元のビニングされた統計計算するために特別に設計された関数もあるというhistogram2d python使用して平均ビン値を見つける

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

もう1つの方法は、ufunc.atを使用することです。このメソッドは、指定されたインデックスで目的の操作をインプレースで適用します。searchsortedメソッドを使用して、各データポイントのビンの位置を取得できます。次に、bin_indexesでインデックスに遭遇するたびに、atを使用して、bin_indexesで指定されたインデックスでのヒストグラムの位置を1ずつ増やすことができます。

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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.