2013-03-14 8 views
12

Ich mache ein Projekt mit Python, wo ich zwei Datenfelder haben. Nennen wir sie pc und pnc. Ich muss eine kumulative Verteilung der beiden auf dem gleichen Graphen darstellen. Für pc soll es ein weniger als Plot sein, d.h. an (x, y), y-Punkte in pc müssen Wert kleiner als x haben. Für pnc ist es ein mehr als Plot, d. H. Bei (x, y), y-Punkte in pnc müssen Wert mehr als x haben.kumulative Verteilung Plots python

Ich habe versucht, mit Histogramm-Funktion - pyplot.hist. Gibt es einen besseren und einfacheren Weg zu tun, was ich will? Außerdem muss es auf einer logarithmischen Skala auf der x-Achse aufgetragen werden.

+1

Es würde helfen, wenn Sie Ihre Versuche zeigen, so weit - Beispiel Eingabedaten, gewünschte Ausgabe etc ... Sonst liest dies als "zeige mir den Code" Frage –

+1

Um Jons Kommentar zu erweitern, sind die Menschen _much_ glücklicher, Ihnen zu helfen, den Code zu reparieren, den Sie haben, anstatt Code von Grund auf neu zu erstellen . Egal wie fehlerhaft und funktionsunfähig Ihr Code ist, zeigen Sie ihn und erklären Sie, was Sie erwarten und was er gerade macht. – tacaswell

Antwort

24

Sie waren in der Nähe. Sie sollten nicht plt.hist als numpy.histogram verwenden, das gibt Ihnen sowohl die Werte und die Behälter, als Sie das kumulative mit Leichtigkeit zeichnen kann:

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, du hast vergessen, das np vor dem cumsum einzuschließen, wie es dein np.histogram Befehl benötigt. – ehsteve

+0

@ehsteve feste Antwort. – Gabriel

+1

@ Gabriel danke! – ehsteve

15

Histogramme zu verwenden ist wirklich unnötig schwer und ungenau (das Binning macht die Daten unscharf): Sie können einfach alle x-Werte sortieren: Der Index jedes Werts ist die Anzahl der Werte, die kleiner sind. Diese kürzere und einfachere Lösung sieht wie folgt aus:

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

Außerdem eine geeignetere Plotstil ist in der Tat plt.step() statt plt.plot(), da die Daten in diskreten Orten ist.

Das Ergebnis ist:

enter image description here

können Sie sehen, dass es zerlumpter als die Ausgabe von EnricoGiampieri Antwort, aber dieses ist das eigentliche Histogramm (statt eine ungefähre des Seins, unschärfer Version davon).

PS: Wie SebastianRaschka angemerkt hat, sollte der letzte Punkt idealerweise die Gesamtanzahl zeigen (anstelle der Gesamtanzahl-1).

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

Es gibt so viele Punkte in data, dass die Wirkung nicht sichtbar ohne Zoom, aber der letzte Punkt an der Gesamtzahl ist von Bedeutung, wenn die Daten nur wenige Punkte enthalten: Dies kann erreicht werden durch.

+1

Aber für große Arrays möchten Sie mit dem Histogramm-Ansatz gehen, da es nicht so viel Speicher benötigt. Die 'plt.step'-Methode gibt mir einen Speicherfehler mit meinem 60 Millionen-Elementarray. – aaren

+0

Einverstanden. Ich bin mir nicht sicher, ob das Problem mit "plt.step" oder mit der Tatsache, dass diese genaue Methode verwendet vielleicht 3 mal den Speicher des Arrays oder beide ... – EOL

+0

Ich stimme zu: plt.step ist wahrscheinlich der geeignetere Ansatz für Plotten "zählt". Eine Frage: Müssten Sie 'plt.step (sorted_data, np.arange (1, data.size + 1))' 'nicht verwenden, um die richtigen Zahlen zu erhalten? – Sebastian

10

Nach abschließender Diskussion mit @EOL, wollte ich meine Lösung (links oben) unter Verwendung eines Zufall Gaussian Probe als eine Zusammenfassung schreiben:

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