2012-05-17 10 views
13

ich eine CDF mit NumPy erstellen möchten, ist mein Code die nächste:Wie bekomme ich die kumulative Verteilungsfunktion mit NumPy?

histo = np.zeros(4096, dtype = np.int32) 
for x in range(0, width): 
    for y in range(0, height): 
     histo[data[x][y]] += 1 
     q = 0 
    cdf = list() 
    for i in histo: 
     q = q + i 
     cdf.append(q) 

ich durch das Feld gehe aber eine lange Zeit, um die Programmausführung nehmen. Es gibt eine eingebaute Funktion mit dieser Funktion, nicht?

Antwort

10

Ich bin nicht wirklich sicher, was Ihr Code tut, aber wenn Sie hist und bin_edges Arrays zurück von numpy.histogram können Sie numpy.cumsum verwenden, um eine kumulative Summe der Histogramm Inhalte zu erzeugen.

>>> import numpy as np 
>>> hist, bin_edges = np.histogram(np.random.randint(0,10,100), normed=True) 
>>> bin_edges 
array([ 0. , 0.9, 1.8, 2.7, 3.6, 4.5, 5.4, 6.3, 7.2, 8.1, 9. ]) 
>>> hist 
array([ 0.14444444, 0.11111111, 0.11111111, 0.1  , 0.1  , 
     0.14444444, 0.14444444, 0.08888889, 0.03333333, 0.13333333]) 
>>> np.cumsum(hist) 
array([ 0.14444444, 0.25555556, 0.36666667, 0.46666667, 0.56666667, 
     0.71111111, 0.85555556, 0.94444444, 0.97777778, 1.11111111]) 
+7

Dies führt jedoch einen Binning-Schritt ein, der für eine kumulative Verteilung nicht erforderlich wäre. –

+1

"Dieses Schlüsselwort, genormt 'ist in Numpy 1.6 wegen des verwirrenden/fehlerhaften Verhaltens veraltet. Es wird in Numpy 2.0 entfernt." Es gibt einen Fehler im Code, wenn' bin 'nicht in '[0,1]' ist. Füge x = np.cumsum (hist) hinzu; x = (x - x.min())/x.ptp() – Shaowu

3

Updates für numpy Version 1.9.0 . Die Antwort von user545424 funktioniert in 1.9.0 nicht. Das funktioniert:

>>> import numpy as np 
>>> arr = np.random.randint(0,10,100) 
>>> hist, bin_edges = np.histogram(arr, density=True) 
>>> hist = array([ 0.16666667, 0.15555556, 0.15555556, 0.05555556, 0.08888889, 
    0.08888889, 0.07777778, 0.04444444, 0.18888889, 0.08888889]) 
>>> hist 
array([ 0.1  , 0.11111111, 0.11111111, 0.08888889, 0.08888889, 
    0.15555556, 0.11111111, 0.13333333, 0.1  , 0.11111111]) 
>>> bin_edges 
array([ 0. , 0.9, 1.8, 2.7, 3.6, 4.5, 5.4, 6.3, 7.2, 8.1, 9. ]) 
>>> np.diff(bin_edges) 
array([ 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9]) 
>>> np.diff(bin_edges)*hist 
array([ 0.09, 0.1 , 0.1 , 0.08, 0.08, 0.14, 0.1 , 0.12, 0.09, 0.1 ]) 
>>> cdf = np.cumsum(hist*np.diff(bin_edges)) 
>>> cdf 
array([ 0.15, 0.29, 0.43, 0.48, 0.56, 0.64, 0.71, 0.75, 0.92, 1. ]) 
>>> 
+1

Sie könnten die ursprüngliche Antwort bearbeiten! – omar

+2

user12287, ich fühle mich komisch, die Antworten anderer Leute zu bearbeiten. Außerdem verschiedene Antworten für verschiedene Versionen. – offwhitelotus

44

Die Verwendung eines Histogramms ist eine Lösung, aber es beinhaltet das Binning der Daten. Dies ist nicht notwendig, um eine CDF von empirischen Daten aufzutragen. Lassen Sie F(x) die Anzahl der Einträge sein, die weniger als x sind, dann geht es um eins, genau wo wir eine Messung sehen. Wenn wir also unsere Abtastungen sortieren, dann erhöhen wir an jedem Punkt die Zählung um eins (oder den Bruchteil um 1/N) und zeichnen eine gegen die andere auf, und wir sehen die "exakte" (d. H. Nicht einbezogene) empirische CDF.

A folgende Codebeispiel zeigt die Methode

import numpy as np 
import matplotlib.pyplot as plt 

N = 100 
Z = np.random.normal(size = N) 
# method 1 
H,X1 = np.histogram(Z, bins = 10, normed = True) 
dx = X1[1] - X1[0] 
F1 = np.cumsum(H)*dx 
#method 2 
X2 = np.sort(Z) 
F2 = np.array(range(N))/float(N) 

plt.plot(X1[1:], F1) 
plt.plot(X2, F2) 
plt.show() 

Es gibt die folgenden

enter image description here

+4

Das ist die richtige Antwort, bravo! –

2

Dans Lösung zu ergänzen. In dem Fall, dass es mehrere identique Werte in Ihrer Probe ist, können Sie numpy.unique verwenden können:

Z = np.array([1,1,1,2,2,4,5,6,6,6,7,8,8]) 
X, F = np.unique(Z, return_index=True) 
F=F/X.size 

plt.plot(X, F) 
+1

Das gibt Ihnen Werte von 'F', die größer als 1 sind. Vielleicht wollten Sie' F = F/float (F.max()) 'verwenden (bedenken Sie auch, dass Integer-Division Probleme für Benutzer von Python 2x verursachen würde)). –

+0

Diese Antwort ist alt, danke für Ihre Kommentare und Antworten. Ich habe in jeder Antwort meinen rudimentären Ansatz von vor drei Jahren gesehen. – omar

+0

@Alex dies ist nicht ganz richtig, da es um mehr als 1/N für die Einträge, die dort mehr als einmal sind, gehen sollte. Du hast Recht, meine Lösung wird nur für das letzte dieser Ereignisse korrekt sein, aber es wird korrekt dargestellt. – Dan

-2

sicher, ich bin nicht, ob es eine Antwort fertig gemacht ist, ist die genaue Sache zu tun, ein definieren Funktion wie:

def _cdf(x,data): 
    return(sum(x>data)) 

Dies wird ziemlich schnell sein.