2013-03-14 12 views
12

Sto facendo un progetto utilizzando python dove ho due array di dati. Chiamiamoli pc e PNC. Sono obbligato a tracciare una distribuzione cumulativa di entrambi su uno stesso grafico. Per pc si suppone che sia un valore inferiore alla trama, ad esempio (x, y), i punti y in pc devono avere un valore inferiore a x. Per pnc deve essere un valore maggiore della trama, ad esempio (x, y), i punti y in pnc devono avere un valore superiore a x.trame di distribuzione cumulativa di pitone

Ho provato a utilizzare la funzione istogramma - pyplot.hist. C'è un modo migliore e più semplice per fare ciò che voglio? Inoltre, deve essere tracciato su una scala logaritmica sull'asse x.

+1

che sarebbe d'aiuto se hai mostrato i tuoi tentativi finora - esempi di dati di input, output desiderato ecc ... Altrimenti si legge come una domanda "Mostrami il codice" –

+1

Per estendere il commento di Jon, le persone sono _molto più felici di aiutarti a correggere il codice che hai invece di generare codice da zero . Non importa quanto sia buggy e non funzionale il tuo codice, mostralo e spiegaci che a) ti aspetti che faccia e b) cosa sta facendo attualmente. – tacaswell

risposta

24

Si erano vicini. Non si deve usare come plt.hist numpy.histogram, che sia i valori ed i bidoni dà, che si può tracciare il cumulativo con facilità:

import numpy as np 
import matplotlib.pyplot as plt 

# some fake data 
data = np.random.randn(1000) 
# evaluate the histogram 
values, base = np.histogram(data, bins=40) 
#evaluate the cumulative 
cumulative = np.cumsum(values) 
# plot the cumulative function 
plt.plot(base[:-1], cumulative, c='blue') 
#plot the survival function 
plt.plot(base[:-1], len(data)-cumulative, c='green') 

plt.show() 

enter image description here

+0

FYI, hai dimenticato di includere il np prima della cumsum come richiesto dal comando np.histogram. – ehsteve

+0

@ehsteve ha risolto la risposta. – Gabriel

+1

@Gabriel ringraziamenti! – ehsteve

15

Utilizzando istogrammi è davvero inutilmente pesante e impreciso (il binning rende sfocati i dati): puoi solo ordinare tutti i valori x: l'indice di ogni valore è il numero di valori che sono più piccoli. Questa soluzione più breve e più semplice si presenta così:

import numpy as np 
import matplotlib.pyplot as plt 

# Some fake data: 
data = np.random.randn(1000) 

sorted_data = np.sort(data) # Or data.sort(), if data can be modified 

# Cumulative counts: 
plt.step(sorted_data, np.arange(sorted_data.size)) # From 0 to the number of data points-1 
plt.step(sorted_data[::-1], np.arange(sorted_data.size)) # From the number of data points-1 to 0 

plt.show() 

Inoltre, uno stile di stampa più appropriato è davvero plt.step() invece di plt.plot(), dal momento che i dati sono in posizioni discrete.

Il risultato è:

enter image description here

Si può vedere che è più frastagliato che l'output della risposta di EnricoGiampieri, ma questo è il vero istogramma (invece di essere un approssimativo, la versione più confusa di esso).

PS: come ha osservato SebastianRaschka, l'ultimo punto dovrebbe idealmente mostrare il conteggio totale (invece del conteggio totale-1). Ciò può essere ottenuto con:

plt.step(np.concatenate([sorted_data, sorted_data[[-1]]]), 
     np.arange(sorted_data.size+1)) 
plt.step(np.concatenate([sorted_data[::-1], sorted_data[[0]]]), 
     np.arange(sorted_data.size+1)) 

Ci sono tanti punti in data che l'effetto non è visibile senza uno zoom, ma l'ultimo punto al conteggio totale non importa quando i dati contiene solo un paio di punti.

+1

Tuttavia, per array di grandi dimensioni si desidera seguire l'approccio dell'istogramma in quanto non richiede quasi la stessa quantità di memoria. Il metodo 'plt.step' mi dà un errore di memoria con il mio array di 60 milioni di elementi. – aaren

+0

concordato. Non sono sicuro se il problema si trova con 'plt.step' o con il fatto che questo metodo esatto utilizza forse 3 volte la memoria dell'array, o entrambi ... – EOL

+0

Sono d'accordo: plt.step è probabilmente l'approccio più appropriato per tracciare "conteggi". Una domanda: non dovresti usare 'plt.step (sorted_data, np.arange (1, data.size + 1))' per ottenere il conteggio corretto? – Sebastian

10

Dopo la discussione conclusiva con @EOL, ho voluto pubblicare la mia soluzione (in alto a sinistra) utilizzando un campione casuale gaussiana come una sintesi:

enter image description here

import numpy as np 
import matplotlib.pyplot as plt 
from math import ceil, floor, sqrt 

def pdf(x, mu=0, sigma=1): 
    """ 
    Calculates the normal distribution's probability density 
    function (PDF). 

    """ 
    term1 = 1.0/(sqrt(2*np.pi) * sigma) 
    term2 = np.exp(-0.5 * ((x-mu)/sigma)**2) 
    return term1 * term2 


# Drawing sample date poi 
################################################## 

# Random Gaussian data (mean=0, stdev=5) 
data1 = np.random.normal(loc=0, scale=5.0, size=30) 
data2 = np.random.normal(loc=2, scale=7.0, size=30) 
data1.sort(), data2.sort() 

min_val = floor(min(data1+data2)) 
max_val = ceil(max(data1+data2)) 

################################################## 




fig = plt.gcf() 
fig.set_size_inches(12,11) 

# Cumulative distributions, stepwise: 
plt.subplot(2,2,1) 
plt.step(np.concatenate([data1, data1[[-1]]]), np.arange(data1.size+1), label='$\mu=0, \sigma=5$') 
plt.step(np.concatenate([data2, data2[[-1]]]), np.arange(data2.size+1), label='$\mu=2, \sigma=7$') 

plt.title('30 samples from a random Gaussian distribution (cumulative)') 
plt.ylabel('Count') 
plt.xlabel('X-value') 
plt.legend(loc='upper left') 
plt.xlim([min_val, max_val]) 
plt.ylim([0, data1.size+1]) 
plt.grid() 

# Cumulative distributions, smooth: 
plt.subplot(2,2,2) 

plt.plot(np.concatenate([data1, data1[[-1]]]), np.arange(data1.size+1), label='$\mu=0, \sigma=5$') 
plt.plot(np.concatenate([data2, data2[[-1]]]), np.arange(data2.size+1), label='$\mu=2, \sigma=7$') 

plt.title('30 samples from a random Gaussian (cumulative)') 
plt.ylabel('Count') 
plt.xlabel('X-value') 
plt.legend(loc='upper left') 
plt.xlim([min_val, max_val]) 
plt.ylim([0, data1.size+1]) 
plt.grid() 


# Probability densities of the sample points function 
plt.subplot(2,2,3) 

pdf1 = pdf(data1, mu=0, sigma=5) 
pdf2 = pdf(data2, mu=2, sigma=7) 
plt.plot(data1, pdf1, label='$\mu=0, \sigma=5$') 
plt.plot(data2, pdf2, label='$\mu=2, \sigma=7$') 

plt.title('30 samples from a random Gaussian') 
plt.legend(loc='upper left') 
plt.xlabel('X-value') 
plt.ylabel('probability density') 
plt.xlim([min_val, max_val]) 
plt.grid() 


# Probability density function 
plt.subplot(2,2,4) 

x = np.arange(min_val, max_val, 0.05) 

pdf1 = pdf(x, mu=0, sigma=5) 
pdf2 = pdf(x, mu=2, sigma=7) 
plt.plot(x, pdf1, label='$\mu=0, \sigma=5$') 
plt.plot(x, pdf2, label='$\mu=2, \sigma=7$') 

plt.title('PDFs of Gaussian distributions') 
plt.legend(loc='upper left') 
plt.xlabel('X-value') 
plt.ylabel('probability density') 
plt.xlim([min_val, max_val]) 
plt.grid() 

plt.show()