binning data dengan python dengan scipy / numpy

108

adakah cara yang lebih efisien untuk mengambil rata-rata array di nampan yang telah ditentukan sebelumnya? misalnya, saya memiliki array angka dan array yang sesuai dengan posisi awal dan akhir bin dalam array itu, dan saya hanya ingin mengambil mean di tempat sampah itu? Saya memiliki kode yang melakukannya di bawah ini tetapi saya bertanya-tanya bagaimana hal itu dapat dipotong dan ditingkatkan. Terima kasih.

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

sumber

Jawaban:

181

Mungkin lebih cepat dan lebih mudah digunakan 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))]

Alternatif untuk ini adalah dengan menggunakan numpy.histogram():

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

Coba sendiri mana yang lebih cepat ... :)

Sven Marnach
sumber
1
Saya tidak melihat perbedaan - mana yang lebih cepat?
4
@user: Saya tidak tahu mana yang lebih cepat untuk data dan parameter Anda. Kedua metode tersebut harus lebih cepat dari Anda, dan saya berharap histogram()metode ini lebih cepat untuk sejumlah besar bin. Tetapi Anda harus membuat profil sendiri, saya tidak dapat melakukan ini untuk Anda.
Sven Marnach
39

Fungsi Scipy (> = 0.11) scipy.stats.binned_statistic secara khusus menjawab pertanyaan di atas.

Untuk contoh yang sama seperti pada jawaban sebelumnya, solusi Scipy adalah

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]
divenex
sumber
16

Tidak yakin mengapa utas ini perlu diperbaiki; tapi berikut adalah jawaban yang disetujui tahun 2014, yang seharusnya jauh lebih cepat:

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
Eelco Hoogendoorn
sumber
3
Anda menjawab pertanyaan lain. Misalnya Anda mean[0] = np.mean(data[0:10]), sementara jawaban yang benar seharusnyanp.mean(data[data < 10])
Ruggero Turra
5

The numpy_indexed paket (disclaimer: Saya penulisnya) berisi fungsi untuk secara efisien melakukan operasi jenis ini:

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

Ini pada dasarnya adalah solusi yang sama seperti yang saya posting sebelumnya; tapi sekarang dibungkus dengan antarmuka yang bagus, dengan tes dan semuanya :)

Eelco Hoogendoorn
sumber
3

Saya akan menambahkan, dan juga untuk menjawab pertanyaan menemukan nilai bin rata-rata menggunakan histogram2d python bahwa scipy juga memiliki fungsi yang dirancang khusus untuk menghitung statistik biner dua dimensi untuk satu atau lebih set 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

fungsi scipy.stats.binned_statistic_dd adalah generalisasi dari fungsi ini untuk dataset dimensi yang lebih tinggi

Chmeul
sumber
1

Alternatif lain adalah dengan menggunakan ufunc.at. Metode ini menerapkan operasi yang diinginkan di tempat pada indeks tertentu. Kita bisa mendapatkan posisi bin untuk setiap titik data menggunakan metode searchsorted. Kemudian kita dapat menggunakan di untuk menambah 1 posisi histogram pada indeks yang diberikan oleh bin_indexes, setiap kali kita menemukan indeks di 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)
kostas
sumber