binning dữ liệu trong python với scipy / numpy


108

có cách nào hiệu quả hơn để lấy giá trị trung bình của một mảng trong các thùng được chỉ định trước không? ví dụ: tôi có một mảng số và một mảng tương ứng với các vị trí bắt đầu và kết thúc của bin trong mảng đó và tôi muốn chỉ lấy giá trị trung bình trong các thùng đó? Tôi có mã thực hiện nó bên dưới nhưng tôi đang tự hỏi làm thế nào nó có thể được cắt giảm và cải thiện. cảm ơn.

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

Câu trả lời:


181

Nó có thể nhanh hơn và dễ sử dụng hơn 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))]

Một thay thế cho điều này là sử dụng numpy.histogram():

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

Hãy thử cho mình cái nào nhanh hơn ... :)


1
Tôi không thấy sự khác biệt - cái nào nhanh hơn?

4
@ người dùng: Tôi không biết cái nào nhanh hơn cho dữ liệu và thông số của bạn. Cả hai phương pháp đều nhanh hơn phương pháp của bạn và tôi hy vọng histogram()phương pháp này sẽ nhanh hơn đối với một số lượng lớn các thùng. Nhưng bạn sẽ phải tự khai báo, tôi không thể làm điều này cho bạn.
Sven Marnach

39

Hàm Scipy (> = 0.11) scipy.stats.binned_statistic giải quyết cụ thể câu hỏi trên.

Đối với ví dụ tương tự như trong các câu trả lời trước, giải pháp Scipy sẽ là

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

Không chắc tại sao chủ đề này bị hoại tử; nhưng đây là câu trả lời đã được phê duyệt năm 2014, câu trả lời này sẽ nhanh hơn nhiều:

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
bạn đang trả lời cho một câu hỏi khác. Ví dụ của bạn mean[0] = np.mean(data[0:10]), trong khi câu trả lời đúng nênnp.mean(data[data < 10])
Ruggero Turra

5

Các numpy_indexed gói (từ chối trách nhiệm: Tôi là tác giả của nó) có chức năng để thực hiện có hiệu quả hoạt động của loại hình này:

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

Về cơ bản đây là giải pháp giống như giải pháp tôi đã đăng trước đó; nhưng bây giờ được bao bọc trong một giao diện đẹp, với các thử nghiệm và tất cả :)


3

Tôi sẽ thêm và cũng để trả lời câu hỏi tìm giá trị bin trung bình bằng cách sử dụng histogram2d python rằng scipy cũng có một chức năng được thiết kế đặc biệt để tính toán thống kê hai chiều cho một hoặc nhiều bộ dữ liệu

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

hàm scipy.stats.binned_statistic_dd là tổng quát của chức năng này cho các tập dữ liệu kích thước cao hơn


1

Một thay thế khác là sử dụng ufunc.at. Phương pháp này áp dụng tại chỗ một thao tác mong muốn tại các chỉ số được chỉ định. Chúng ta có thể lấy vị trí bin cho mỗi điểm dữ liệu bằng cách sử dụng phương pháp đã tìm kiếm. Sau đó, chúng ta có thể sử dụng at để tăng 1 vị trí của biểu đồ tại chỉ mục do bin_indexes cung cấp, mỗi khi chúng ta gặp một chỉ mục tại 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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.