2016-06-17 7 views
3

Учитывая распределение вероятностей с неизвестной функциональной формой (пример ниже), мне нравится строить контурные линии на основе «процентили», т. Е. Те, которые соответствуют областям с интегралом от 10% , 20%, ..., 90% и т.д.Python, строящий горизонтальные линии с процентилями распределения вероятности

## example of an "arbitrary" probability distribution ## 
from matplotlib.mlab import bivariate_normal 
import matplotlib.pyplot as plt 
import numpy as np 

X, Y = np.mgrid[-3:3:100j, -3:3:100j] 
z1 = bivariate_normal(X, Y, .5, .5, 0., 0.) 
z2 = bivariate_normal(X, Y, .4, .4, .5, .5) 
z3 = bivariate_normal(X, Y, .6, .2, -1.5, 0.) 
z = z1+z2+z3 
plt.imshow(np.reshape(z.T, (100,-1)), origin='lower', extent=[-3,3,-3,3]) 
plt.show() 

enter image description here Я посмотрел на несколько подходов, с помощью функции контура по умолчанию в Matplotlib, методы, включающие stats.gaussian_kde в SciPy, и даже, возможно, генерируя случайные выборки точек из распределения и оценки ядра впоследствии. Ни один из них, похоже, не дает решения.

+0

Ваш вопрос некорректен. Существует бесконечно много способов разделить ваш примерный рисунок, чтобы, например, каждая сторона подразделения имела интеграл в 50%. Какое подразделение вы хотите? Похоже, вам нужны контурные линии, но только те, которые соответствуют регионам с интегралом от 10%, 20%, ..., 90%, например. Это верно? –

+0

@TimothyShields Спасибо за разъяснение. То, что вы лучше заявили, действительно то, что я хочу. –

ответ

5

Посмотрите на интеграл от р (х) внутри контура р (х) ≥ т и решения для желаемого значения t:

import matplotlib 
from matplotlib.mlab import bivariate_normal 
import matplotlib.pyplot as plt 
import numpy as np 

X, Y = np.mgrid[-3:3:100j, -3:3:100j] 
z1 = bivariate_normal(X, Y, .5, .5, 0., 0.) 
z2 = bivariate_normal(X, Y, .4, .4, .5, .5) 
z3 = bivariate_normal(X, Y, .6, .2, -1.5, 0.) 
z = z1 + z2 + z3 
z = z/z.sum() 

n = 1000 
t = np.linspace(0, z.max(), n) 
integral = ((z >= t[:, None, None]) * z).sum(axis=(1,2)) 

from scipy import interpolate 
f = interpolate.interp1d(integral, t) 
t_contours = f(np.array([0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1])) 
plt.imshow(z.T, origin='lower', extent=[-3,3,-3,3], cmap="gray") 
plt.contour(z.T, t_contours, extent=[-3,3,-3,3]) 
plt.show() 

enter image description here

+1

Благодарим вас за идеальное решение! Тем не менее, я полностью потерял попытку понять строку '' integ = = ((z> = t [:, None, None]) * z) .sum (axis = (1,2)) ''. Кроме того, есть ли способ маркировать контурные линии с 0,9, 0,8, 0,7 и так далее? –

+2

@ no-nor 'z' - это 2D-массив, представляющий распределение p (x). 't' - это 1D-массив различных пороговых значений между' 0' и 'z.max()'. 'mask = (z> = t [:, None, None])' - это 3D-массив формы 't.shape + z.shape', где каждая' mask [i] 'является двумерным массивом значений 0/1, где 1 находятся внутри контура p (x)> = t [i]. 'интеграл = (маска * z) .sum (axis = (1,2))' представляет собой 1D массив интегралов по тем областям, где интеграл [i] 'является интегралом от p (x) по области p (x)> = t [i]. –

-3

Вы можете сделать что-то вроде этого:

from matplotlib.mlab import bivariate_normal 
import matplotlib.pyplot as plt 
import matplotlib.mlab as mlab 
import numpy as np 

X, Y = np.mgrid[-3:3:100j, -3:3:100j] 

sigma = 0.5 

z = bivariate_normal(X,Y,.5, .5, 0., 0.) 
z1 = bivariate_normal(0, 1 * sigma, sigma, sigma, 0.0, 0.0) 
z2 = bivariate_normal(0, 2 * sigma, sigma, sigma, 0.0, 0.0) 
z3 = bivariate_normal(0, 3 * sigma, sigma, sigma, 0.0, 0.0) 

plt.imshow(z, interpolation='bilinear', origin='lower', extent=[-3,3,-3,3]) 
contour = plt.contour(z,[z1,z2,z3],origin='lower',extent=[-3,3,-3,3],colors='yellow') 
plt.show() 

Что дает:

enter image description here

+0

Эти контурные линии соответствуют высоте распределения, а не количеству объема внутри них. –