Квантиль / медиана / 2D биннинг в Python

знаете ли вы быстрое / элегантное решение Python / Scipy / Numpy для следующей проблемы: У вас есть набор координат x, y со связанными значениями w (все массивы 1D). Теперь bin x и y на 2D-сетку (размер BINSxBINS) и вычисляют квантили (например, медиану) значений w для каждого Бина, что должно в конечном итоге привести к 2D-массиву BINSxBINS с требуемыми квантилями.

Это легко сделать с некоторым вложенным циклом,но я уверен, что есть более элегантный решение.

спасибо, Марк!--1-->

4 ответов


Это то, что я придумал, надеюсь, это полезно. Это не обязательно чище или лучше, чем использование цикла, но, возможно, это поможет вам начать что-то лучшее.

import numpy as np
bins_x, bins_y = 1., 1.
x = np.array([1,1,2,2,3,3,3])
y = np.array([1,1,2,2,3,3,3])
w = np.array([1,2,3,4,5,6,7], 'float')

# You can get a bin number for each point like this
x = (x // bins_x).astype('int')
y = (y // bins_y).astype('int')
shape = [x.max()+1, y.max()+1]
bin = np.ravel_multi_index([x, y], shape)

# You could get the mean by doing something like:
mean = np.bincount(bin, w) / np.bincount(bin)

# Median is a bit harder
order = bin.argsort()
bin = bin[order]
w = w[order]
edges = (bin[1:] != bin[:-1]).nonzero()[0] + 1
med_index = (np.r_[0, edges] + np.r_[edges, len(w)]) // 2
median = w[med_index]

# But that's not quite right, so maybe
median2 = [np.median(i) for i in np.split(w, edges)]

также взгляните на numpy.histogram2d


Я просто пытаюсь сделать это сам, и это звучит так, как будто вы хотите команду "scipy.статистика.binned_statistic_2d " Из вы можете найти среднее, медианное, стандартное отклонение или любую определенную функцию для третьего параметра, заданного бункерами.

Я понимаю, что на этот вопрос уже ответили, но я считаю, что это хорошее встроенное решение.


большое спасибо за ваш код. На его основе я нашел следующее решение моей проблемы (только незначительная модификация код):

import numpy as np
BINS=10
boxsize=10.0
bins_x, bins_y = boxsize/BINS, boxsize/BINS
x = np.array([0,0,0,1,1,1,2,2,2,3,3,3])
y = np.array([0,0,0,1,1,1,2,2,2,3,3,3])
w = np.array([0,1,2,0,1,2,0,1,2,0,1,2], 'float')

# You can get a bin number for each point like this
x = (x // bins_x).astype('int')
y = (y // bins_y).astype('int')
shape = [BINS, BINS]
bin = np.ravel_multi_index([x, y], shape)


# Median 
order = bin.argsort()
bin = bin[order]
w = w[order]
edges = (bin[1:] != bin[:-1]).nonzero()[0] + 1
median = [np.median(i) for i in np.split(w, edges)]

#construct BINSxBINS matrix with median values
binvals=np.unique(bin)
medvals=np.zeros([BINS*BINS])
medvals[binvals]=median
medvals=medvals.reshape([BINS,BINS])

print medvals

операций с numpy/составляющей, это идет как это:

    import numpy as np
    import scipy.stats as stats

    x = np.random.uniform(0,200,100)
    y = np.random.uniform(0,200,100)
    w = np.random.uniform(1,10,100)

    h = np.histogram2d(x,y,bins=[10,10], weights=w,range=[[0,200],[0,200]])
    hist, bins_x, bins_y = h
    q = stats.mstats.mquantiles(hist,prob=[0.25, 0.5, 0.75])

    >>> q.round(2)
    array([ 512.8 ,  555.41,  592.73])

    q1 = np.where(hist<q[0],1,0)
    q2 = np.where(np.logical_and(q[0]<=hist,hist<q[1]),2,0)
    q3 = np.where(np.logical_and(q[1]<=hist,hist<=q[2]),3,0)
    q4 = np.where(q[2]<hist,4,0)

    >>>q1 + q2 + q3 + q4
    array([[4, 3, 4, 3, 1, 1, 4, 3, 1, 2],
   [1, 1, 4, 4, 2, 3, 1, 3, 3, 3],
   [2, 3, 3, 2, 2, 2, 3, 2, 4, 2],
   [2, 2, 3, 3, 3, 1, 2, 2, 1, 4],
   [1, 3, 1, 4, 2, 1, 3, 1, 1, 3],
   [4, 2, 2, 1, 2, 1, 3, 2, 1, 1],
   [4, 1, 1, 3, 1, 3, 4, 3, 2, 1],
   [4, 3, 1, 4, 4, 4, 1, 1, 2, 4],
   [2, 4, 4, 4, 3, 4, 2, 2, 2, 4],
   [2, 2, 4, 4, 3, 3, 1, 3, 4, 4]])

проблема = [0.25, 0.5, 0.75] является значением по умолчанию для параметров квантильной, вы можете изменить его или оставить его.