2016-06-17 6 views
3

Bei einer Wahrscheinlichkeitsverteilung mit unbekannter funktioneller Form (Beispiel unten) zeichne ich gerne "prozentuale" Konturlinien, dh solche, die Regionen mit einem Integral von 10% entsprechen , 20%, ..., 90% usw.Python Plot prozentuale Konturlinien einer Wahrscheinlichkeitsverteilung

## 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 ich in mehrere Ansätze haben gesucht, von der Nutzung der Standard-Konturfunktion in matplotlib, Methoden stats.gaussian_kde in scipy beteiligt, und vielleicht sogar zu erzeugen zufällige Punkt-Samples aus der Distribution und danach einen Kernel zu schätzen. Keiner von ihnen scheint die Lösung zu bieten.

+0

Ihre Frage ist schlecht gestellt. Es gibt unendlich viele Möglichkeiten, wie Sie Ihr Beispielbild so aufteilen können, dass zum Beispiel jede Seite der Division ein Integral von 50% hat. Welche Abteilung willst du? Es klingt, als ob Sie Konturlinien wollen - aber nur solche, die Regionen mit einem Integral von 10%, 20%, ..., 90% entsprechen. Ist das korrekt? –

+0

@TimothyShields Danke für die Klarstellung. Was du besser gesagt hast, ist in der Tat, was ich will. –

Antwort

5

Blick auf das Integral von p (x) innerhalb der Kontur p (x) ≥ t und lösen für den gewünschten Wert von 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

Vielen Dank für die perfekte Lösung! Ich bin jedoch völlig verloren, wenn ich versuche, die Zeile "integral = ((z> = t [:, None, None]) * z) .sum (axis = (1,2))" zu verstehen. Gibt es eine Möglichkeit, die Konturlinien mit 0,9, 0,8, 0,7 usw. zu beschriften? –

+2

@ wish-nor 'z' ist ein 2D-Array, das die Verteilung p (x) darstellt. 't' ist ein 1D-Array verschiedener Schwellen zwischen' 0' und 'z.max()'. 'mask = (z> = t [:, None, None])' ist ein 3D-Array mit der Form 't.shape + z.shape', wobei jede' mask [i] 'ein 2D-Array mit 0/1-Werten ist 1 sind innerhalb der Kontur p (x)> = t [i]. Integral = (mask * z) .sum (axis = (1,2)) 'ist ein 1D-Array der Integrale über diesen Regionen, wobei' integral [i] 'das Integral von p (x) über die Region p ist (x)> = t [i]. –

-3

Sie können etwas tun:

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() 

Welche gibt:

enter image description here

+0

Diese Höhenlinien entsprechen der Höhe der Verteilung, nicht der Menge an Volumen in ihnen. –

Verwandte Themen