web-dev-qa-db-fra.com

intervalles de confiance multidimensionnels

J'ai de nombreux n-uplets (par1, par2), c'est-à-dire des points dans un espace de paramètre bidimensionnel obtenu en répétant une expérience plusieurs fois.

Je cherche une possibilité de calculer et de visualiser des ellipses de confiance (je ne sais pas si c'est le terme qui convient pour cela). Voici un exemple d'intrigue que j'ai trouvé sur le Web pour montrer ce que je veux dire:

enter image description here

source: blogspot.ch/2011/07/classification-and-discrimination-with.html

Donc, en principe, il faut adapter une distribution multivariée normale à un histogramme 2D de points de données, je suppose. Quelqu'un peut-il m'aider avec ça?

19
Raphael Roth

On dirait que vous voulez juste l'ellipse 2-sigma de la dispersion de points?

Si tel est le cas, envisagez quelque chose comme ceci (à partir d'un code pour un article ici: https://github.com/joferkington/oost_paper_code/blob/master/error_ellipse.py ):

import numpy as np

import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse

def plot_point_cov(points, nstd=2, ax=None, **kwargs):
    """
    Plots an `nstd` sigma ellipse based on the mean and covariance of a point
    "cloud" (points, an Nx2 array).

    Parameters
    ----------
        points : An Nx2 array of the data points.
        nstd : The radius of the ellipse in numbers of standard deviations.
            Defaults to 2 standard deviations.
        ax : The axis that the ellipse will be plotted on. Defaults to the 
            current axis.
        Additional keyword arguments are pass on to the ellipse patch.

    Returns
    -------
        A matplotlib ellipse artist
    """
    pos = points.mean(axis=0)
    cov = np.cov(points, rowvar=False)
    return plot_cov_ellipse(cov, pos, nstd, ax, **kwargs)

def plot_cov_ellipse(cov, pos, nstd=2, ax=None, **kwargs):
    """
    Plots an `nstd` sigma error ellipse based on the specified covariance
    matrix (`cov`). Additional keyword arguments are passed on to the 
    ellipse patch artist.

    Parameters
    ----------
        cov : The 2x2 covariance matrix to base the ellipse on
        pos : The location of the center of the ellipse. Expects a 2-element
            sequence of [x0, y0].
        nstd : The radius of the ellipse in numbers of standard deviations.
            Defaults to 2 standard deviations.
        ax : The axis that the ellipse will be plotted on. Defaults to the 
            current axis.
        Additional keyword arguments are pass on to the ellipse patch.

    Returns
    -------
        A matplotlib ellipse artist
    """
    def eigsorted(cov):
        vals, vecs = np.linalg.eigh(cov)
        order = vals.argsort()[::-1]
        return vals[order], vecs[:,order]

    if ax is None:
        ax = plt.gca()

    vals, vecs = eigsorted(cov)
    theta = np.degrees(np.arctan2(*vecs[:,0][::-1]))

    # Width and height are "full" widths, not radius
    width, height = 2 * nstd * np.sqrt(vals)
    ellip = Ellipse(xy=pos, width=width, height=height, angle=theta, **kwargs)

    ax.add_artist(ellip)
    return ellip

if __== '__main__':
    #-- Example usage -----------------------
    # Generate some random, correlated data
    points = np.random.multivariate_normal(
            mean=(1,1), cov=[[0.4, 9],[9, 10]], size=1000
            )
    # Plot the raw points...
    x, y = points.T
    plt.plot(x, y, 'ro')

    # Plot a transparent 3 standard deviation covariance ellipse
    plot_point_cov(points, nstd=3, alpha=0.5, color='green')

    plt.show()

enter image description here

36
Joe Kington

Reportez-vous à la publication Comment dessiner une ellipse d'erreur de covariance .

Voici la réalisation python:

import numpy as np
from scipy.stats import norm, chi2

def cov_ellipse(cov, q=None, nsig=None, **kwargs):
    """
    Parameters
    ----------
    cov : (2, 2) array
        Covariance matrix.
    q : float, optional
        Confidence level, should be in (0, 1)
    nsig : int, optional
        Confidence level in unit of standard deviations. 
        E.g. 1 stands for 68.3% and 2 stands for 95.4%.

    Returns
    -------
    width, height, rotation :
         The lengths of two axises and the rotation angle in degree
    for the ellipse.
    """

    if q is not None:
        q = np.asarray(q)
    Elif nsig is not None:
        q = 2 * norm.cdf(nsig) - 1
    else:
        raise ValueError('One of `q` and `nsig` should be specified.')
    r2 = chi2.ppf(q, 2)

    val, vec = np.linalg.eigh(cov)
    width, height = 2 * sqrt(val[:, None] * r2)
    rotation = np.degrees(arctan2(*vec[::-1, 0]))

    return width, height, rotation

La signification de écart type est faux dans la réponse de Joe Kington. Nous utilisons habituellement 1, 2 sigma pour des niveaux de confiance de 68%, 95%, mais l’ellipse de 2 sigma dans sa réponse ne contient pas une probabilité de 95% de la distribution totale. La méthode correcte consiste à utiliser une distribution du chi carré pour estimer la taille de l'ellipse comme indiqué dans le post .

5
Syrtis Major

J'ai légèrement modifié l'un des exemples ci-dessus qui trace les contours des zones d'erreur ou de confiance. Maintenant, je pense que cela donne les bons contours.

Cela donnait des contours incorrects parce que la méthode scoreatpercentile était appliquée à l'ensemble de données joint (points bleus + rouges) lorsqu'elle devait être appliquée séparément à chaque ensemble de données.

Le code modifié se trouve ci-dessous:

import numpy
import scipy
import scipy.stats
import matplotlib.pyplot as plt

# generate two normally distributed 2d arrays
x1=numpy.random.multivariate_normal((100,420),[[120,80],[80,80]],400)
x2=numpy.random.multivariate_normal((140,340),[[90,-70],[-70,80]],400)

# fit a KDE to the data
pdf1=scipy.stats.kde.gaussian_kde(x1.T)
pdf2=scipy.stats.kde.gaussian_kde(x2.T)

# create a grid over which we can evaluate pdf
q,w=numpy.meshgrid(range(50,200,10), range(300,500,10))
r1=pdf1([q.flatten(),w.flatten()])
r2=pdf2([q.flatten(),w.flatten()])

# sample the pdf and find the value at the 95th percentile
s1=scipy.stats.scoreatpercentile(pdf1(pdf1.resample(1000)), 5)
s2=scipy.stats.scoreatpercentile(pdf2(pdf2.resample(1000)), 5)

# reshape back to 2d
r1.shape=(20,15)
r2.shape=(20,15)

# plot the contour at the 95th percentile
plt.contour(range(50,200,10), range(300,500,10), r1, [s1],colors='b')
plt.contour(range(50,200,10), range(300,500,10), r2, [s2],colors='r')

# scatter plot the two normal distributions
plt.scatter(x1[:,0],x1[:,1],alpha=0.3)
plt.scatter(x2[:,0],x2[:,1],c='r',alpha=0.3)
4
Rodrigo

Je suppose que ce que vous recherchez, c'est de calculer les régions de confiance .

Je ne sais pas trop quoi faire, mais comme point de départ, je vérifierais l’application sherpa pour python. Au moins, dans leur exposé sur Scipy 2011, les auteurs mentionnent que vous pouvez déterminer et obtenir des régions de confiance avec ce dernier (vous devrez peut-être toutefois disposer d'un modèle pour vos données).

Voir la vidéo et diapositives correspondantes du Sherpa.

HTH

0
gcalmettes