pyplot legends font python numpy statistics matplotlib scipy

python - legends - plot title font size matplotlib



Cómo trazar pldf empírico en matplotlib en Python? (14)

¿Has probado el argumento cumulativo = True para pyplot.hist?

¿Cómo puedo trazar la CDF empírica de una matriz de números en matplotlib en Python? Estoy buscando el análogo cdf de la función "hist" de pylab.

Una cosa que puedo pensar es:

from scipy.stats import cumfreq a = array([...]) # my array of numbers num_bins = 20 b = cumfreq(a, num_bins) plt.plot(b)

¿Eso es correcto? ¿Hay una manera más fácil / mejor?

Gracias.


¿Qué quieres hacer con el CDF? Para trazarlo, eso es un comienzo. Podrías probar algunos valores diferentes, como este:

from __future__ import division import numpy as np from scipy.stats import cumfreq import pylab as plt hi = 100. a = np.arange(hi) ** 2 for nbins in ( 2, 20, 100 ): cf = cumfreq(a, nbins) # bin values, lowerlimit, binsize, extrapoints w = hi / nbins x = np.linspace( w/2, hi - w/2, nbins ) # care # print x, cf plt.plot( x, cf[0], label=str(nbins) ) plt.legend() plt.show()

Histogram enumera varias reglas para el número de contenedores, por ejemplo, num_bins ~ sqrt( len(a) ) .

(Impresión fina: dos cosas bastante diferentes están sucediendo aquí,

  • binning / histogramación de los datos sin procesar
  • plot interpola una curva suave a través de los valores compartidos de decir 20.

Cualquiera de estos puede ir muy lejos en datos que son "agrupados" o tienen colas largas, incluso para datos 1d - 2d, los datos en 3D se vuelven cada vez más difíciles.
Ver también Density_estimation y usar scipy gaussian kernel density estimation ).


(Esta es una copia de mi respuesta a la pregunta: Trazar CDF de una serie de pandas en Python )

Un diagrama de funciones de distribución acumulativa o CDF es básicamente un gráfico con los valores ordenados en el eje X y en el eje Y la distribución acumulada. Entonces, crearía una nueva serie con los valores ordenados como índice y la distribución acumulativa como valores.

Primero crea una serie de ejemplos:

import pandas as pd import numpy as np ser = pd.Series(np.random.normal(size=100))

Ordenar la serie:

ser = ser.order()

Ahora, antes de continuar, vuelva a agregar el último (y mayor) valor. Este paso es importante especialmente para tamaños de muestra pequeños para obtener un CDF imparcial:

ser[len(ser)] = ser.iloc[-1]

Cree una nueva serie con los valores ordenados como índice y la distribución acumulativa como valores

cum_dist = np.linspace(0.,1.,len(ser)) ser_cdf = pd.Series(cum_dist, index=ser)

Finalmente, trace la función como pasos:

ser_cdf.plot(drawstyle=''steps'')


Es un juego de una sola línea en Seaborn usando el parámetro cumulativo = True. Aqui tienes,

import seaborn as sns sns.kdeplot(a, cumulative=True)


Eso parece ser (casi) exactamente lo que quieres. Dos cosas:

Primero, los resultados son una tupla de cuatro elementos. El tercero es el tamaño de los contenedores. El segundo es el punto de inicio del bin más pequeño. El primero es la cantidad de puntos en el interior o debajo de cada contenedor. (El último es el número de puntos fuera de los límites, pero como no ha configurado ninguno, todos los puntos se agruparán).

En segundo lugar, querrás volver a escalar los resultados para que el valor final sea 1, seguir las convenciones habituales de un CDF, pero de lo contrario es correcto.

Esto es lo que hace bajo el capó:

def cumfreq(a, numbins=10, defaultreallimits=None): # docstring omitted h,l,b,e = histogram(a,numbins,defaultreallimits) cumhist = np.cumsum(h*1, axis=0) return cumhist,l,b,e

Realiza la histogramación, luego produce una suma acumulada de los conteos en cada contenedor. Por lo tanto, el valor ith del resultado es el número de valores de matriz menores o iguales al máximo de la i-ésima categoría. Entonces, el valor final es solo el tamaño de la matriz inicial.

Finalmente, para trazarlo, necesitará usar el valor inicial de la bandeja y el tamaño de la bandeja para determinar qué valores de eje x necesitará.

Otra opción es usar numpy.histogram que puede hacer la normalización y devolver los bordes del contenedor. Tendrá que hacer la suma acumulativa de los recuentos resultantes usted mismo.

a = array([...]) # your array of numbers num_bins = 20 counts, bin_edges = numpy.histogram(a, bins=num_bins, normed=True) cdf = numpy.cumsum(counts) pylab.plot(bin_edges[1:], cdf)

( bin_edges[1:] es el borde superior de cada contenedor).


Esto es usando bokeh

`` `

from bokeh.plotting import figure, show from statsmodels.distributions.empirical_distribution import ECDF ecdf = ECDF(pd_series) p = figure(title="tests", tools="save", background_fill_color="#E8DDCB") p.line(ecdf.x,ecdf.y) show(p)

`` `


Ninguna de las respuestas hasta ahora cubre lo que quería cuando llegué aquí, que es:

def empirical_cdf(x, data): "evaluate ecdf of data at points x" return np.mean(data[None, :] <= x[:, None], axis=1)

Evalúa el CDF empírico de un conjunto de datos dado en una matriz de puntos x, que no tienen que ser ordenados. No hay binning intermedio y no hay bibliotecas externas.

Un método equivalente que se escala mejor para x grande es ordenar los datos y usar np.searchsorted:

def empirical_cdf(x, data): "evaluate ecdf of data at points x" data = np.sort(data) return np.searchsorted(data, x)/float(data.size)


One-liner basado en la respuesta de Dave:

plt.plot(np.sort(arr), np.linspace(0, 1, len(arr), endpoint=False))

Editar: esto también fue sugerido por hans_meine en los comentarios.


Podemos simplemente usar la función de step de matplotlib , que hace una gráfica paso a paso, que es la definición de la FCD empírica:

import numpy as np from matplotlib import pyplot as plt data = np.random.randn(11) levels = np.linspace(0, 1, len(data) + 1) # endpoint 1 is included by default plt.step(sorted(list(data) + [max(data)]), levels)

La línea vertical final en max(data) se agregó manualmente. De lo contrario, la trama simplemente se detiene en el nivel 1 - 1/len(data) .

Alternativamente, podemos usar la opción where=''post'' para el step()

levels = np.linspace(1. / len(data), 1, len(data)) plt.step(sorted(data), levels, where=''post'')

en cuyo caso, la línea vertical inicial desde cero no se traza.


Puede usar la función ECDF desde la biblioteca scikits.statsmodels :

import numpy as np import scikits.statsmodels as sm import matplotlib.pyplot as plt sample = np.random.uniform(0, 1, 50) ecdf = sm.tools.ECDF(sample) x = np.linspace(min(sample), max(sample)) y = ecdf(x) plt.step(x, y)

Con la versión 0.4 scicits.statsmodels se renombró a statsmodels . ECDF ahora se encuentra en el módulo de distributions (mientras que el statsmodels.tools.tools.ECDF ( statsmodels.tools.tools.ECDF se deprecia).

import numpy as np import statsmodels.api as sm # recommended import according to the docs import matplotlib.pyplot as plt sample = np.random.uniform(0, 1, 50) ecdf = sm.distributions.ECDF(sample) x = np.linspace(min(sample), max(sample)) y = ecdf(x) plt.step(x, y) plt.show()


Si desea visualizar el verdadero ECDF verdadero (que como notó David B es una función de paso que aumenta 1 / n en cada uno de los n puntos de datos), mi sugerencia es escribir código para generar dos puntos de "trazado" para cada punto de datos:

a = array([...]) # your array of numbers sorted=np.sort(a) x2 = [] y2 = [] y = 0 for x in sorted: x2.extend([x,x]) y2.append(y) y += 1.0 / len(a) y2.append(y) plt.plot(x2,y2)

De esta forma obtendrás un diagrama con los n pasos que son característicos de un ECDF, lo cual es bueno especialmente para los conjuntos de datos que son lo suficientemente pequeños para que los pasos sean visibles. Además, no hay necesidad de hacer ningún binning con histogramas (lo que corre el riesgo de introducir un sesgo en el ECDF extraído).


Si te gusta linspace y prefieres linspace , puedes hacer:

plt.plot(np.sort(a), np.linspace(0, 1, len(a), endpoint=False))

Dado mis gustos, casi siempre hago:

# a is the data array x = np.sort(a) y = np.arange(len(x))/float(len(x)) plt.plot(x, y)

Lo cual funciona para mí incluso si hay >O(1e6) valores de datos. Si realmente necesitas bajar la muestra, yo establecería

x = np.sort(a)[::down_sampling_step]

Edite para responder para comentar / editar sobre por qué uso endpoint=False o y como se define arriba. Los siguientes son algunos detalles técnicos.

El CDF empírico generalmente se define formalmente como

CDF(x) = "number of samples <= x"/"number of samples"

para que coincida exactamente con esta definición formal necesitaríamos usar y = np.arange(1,len(x)+1)/float(len(x)) para que obtengamos y = [1/N, 2/N ... 1] . Este estimador es un estimador insesgado que convergerá al verdadero CDF en el límite de infinitas muestras Wikipedia ref. .

Tiendo a usar y = [0, 1/N, 2/N ... (N-1)/N] ya que (a) es más fácil de codificar / más idóneo, (b) pero todavía está formalmente justificado ya que uno siempre puede intercambiar CDF(x) con 1-CDF(x) en la prueba de convergencia, y (c) funciona con el método de reducción de resolución (fácil) descrito anteriormente.

En algunos casos particulares, es útil definir

y = (arange(len(x))+0.5)/len(x)

que es intermedio entre estas dos convenciones. Lo cual, en efecto, dice "hay una posibilidad de 1/(2N) de un valor menor que el más bajo que he visto en mi muestra, y una probabilidad 1/(2N) de un valor mayor que el más grande que yo '' he visto hasta ahora.

Sin embargo, para muestras grandes y distribuciones razonables, la convención dada en el cuerpo principal de la respuesta es fácil de escribir, es un estimador insesgado de la verdadera CDF y funciona con la metodología de reducción de muestreo.


Suponiendo que vals tenga sus valores, entonces simplemente puede trazar el CDF de la siguiente manera:

y = numpy.arange(0, 101) x = numpy.percentile(vals, y) plot(x, y)

Para escalarlo entre 0 y 1, simplemente divida y por 100.


Tengo una adición trivial al método de AFoglia, para normalizar el CDF

n_counts,bin_edges = np.histogram(myarray,bins=11,normed=True) cdf = np.cumsum(n_counts) # cdf not normalized, despite above scale = 1.0/cdf[-1] ncdf = scale * cdf

La normalización del histo forma su unidad integral , lo que significa que el cdf no se normalizará. Tienes que escalarlo tú mismo.