Jak wykreślić empiryczne cdf w matplotlib w Pythonie?

Jak mogę narysować empiryczny CDF tablicy liczb w matplotlib w Pythonie? Szukam analoga cdf funkcji "hist" firmy pylab.

Jedna rzecz, o której myślę, to:

from scipy.stats import cumfreq
a = array([...]) # my array of numbers
num_bins =  20
b = cumfreq(a, num_bins)
plt.plot(b)
Czy to prawda? Czy istnieje łatwiejszy/lepszy sposób? Dzięki.
Author: bmu, 2010-07-09

14 answers

To wygląda na (prawie) dokładnie to, czego chcesz. Dwie rzeczy:

Po pierwsze, wyniki są krotką czterech pozycji. Trzecia to wielkość pojemników. Drugi jest punktem wyjścia najmniejszego pojemnika. Pierwsza to liczba punktów w każdym pojemniku lub poniżej. (Ostatnia to liczba punktów poza limitami, ale ponieważ nie ustawiłeś żadnych, wszystkie punkty zostaną usunięte.)

Po drugie, będziesz chciał przeskalować wyniki tak, aby ostateczna wartość wynosiła 1, aby postępować zgodnie ze standardowym konwencje CDF, ale poza tym to prawda.

Oto co robi pod maską:

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

Wykonuje histogramowanie, a następnie tworzy skumulowaną sumę zliczeń w każdym pojemniku. Tak więc i-ta wartość wyniku jest liczbą wartości tablicy mniejszą lub równą maksimum i-tego bin-a. Tak więc wartość końcowa jest tylko wielkością tablicy początkowej.

Wreszcie, aby go wykreślić, musisz użyć początkowej wartości kosza i rozmiaru kosza, aby określić, jaka oś x wartości, których potrzebujesz.

Inną opcją jest użycie numpy.histogram, które może wykonać normalizację i zwrócić krawędzie kosza. Będziesz musiał zrobić skumulowaną sumę uzyskanych liczy siebie.

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:] jest górną krawędzią każdego pojemnika.)

 15
Author: AFoglia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-09 15:07:20

Jeśli lubisz linspace i wolisz jednolinijkowe, możesz zrobić:

plt.plot(np.sort(a), np.linspace(0, 1, len(a), endpoint=False))
Biorąc pod uwagę moje gusta, prawie zawsze: {]}
# a is the data array
x = np.sort(a)
y = np.arange(len(x))/float(len(x))
plt.plot(x, y)

Który działa dla mnie, nawet jeśli istnieją >O(1e6) wartości danych. Jeśli naprawdę potrzebujesz obniżyć próbkę, ustawiłbym

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

Edytuj aby odpowiedzieć na komentarz / edytuj dlaczego używam endpoint=False lub y jak zdefiniowano powyżej. Poniżej znajdują się niektóre szczegóły techniczne.

Empiryczny CDF jest zwykle formalnie zdefiniowany jako

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

Aby dokładnie dopasować do tej formalnej definicji trzeba by użyć y = np.arange(1,len(x)+1)/float(len(x)), aby uzyskać y = [1/N, 2/N ... 1]. Ten Estymator jest bezstronnym estymatorem, który będzie zbieżny do prawdziwego CDF w granicy nieskończonych próbek Wikipedia ref..

Używam y = [0, 1/N, 2/N ... (N-1)/N] Ponieważ (a) łatwiej jest kodować/bardziej idomatycznie, (b) ale nadal jest formalnie uzasadnione, ponieważ zawsze można wymienić CDF(x) z 1-CDF(x) w dowodzie konwergencji, oraz (c) działa z (łatwą) metodą downsamplingu opisaną powyżej.

W niektórych przypadki szczególne warto zdefiniować

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

Który jest pośredni między tymi dwoma konwencjami. Co w efekcie mówi: "Istnieje 1/(2N) szansa na wartość mniejszą niż najniższa, jaką widziałem w mojej próbie, i 1/(2N) szansa na wartość większą niż największa, jaką widziałem do tej pory.

Jednak dla dużych próbek i rozsądnych rozkładów, konwencja podana w głównej części odpowiedzi jest łatwa do napisania, jest bezstronnym estymatorem prawdziwego CDF i działa z metodologią downsamplingu.

 74
Author: Dave,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-17 13:24:56

Możesz użyć ECDF funkcja z scikits.biblioteka 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)

W wersji 0.4 scicits.statsmodels została przemianowana na statsmodels. {[2] } znajduje się teraz w module distributions (podczas statsmodels.tools.tools.ECDF jest amortyzowany).

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()
 68
Author: ars,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-04 20:16:07

Czy próbowałeś argumentu cumulative = True do pyplota.hist?

 15
Author: Andrej Panjkov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-28 05:59:43

One-liner na podstawie odpowiedzi Dave ' a:

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

Edit: to również zasugerował hans_meine w komentarzach.

 6
Author: 1'',
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-17 17:54:19

Co chcesz zrobić z CDF ? To dobry początek. Możesz wypróbować kilka różnych wartości, takich jak:

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 wymienia różne zasady dotyczące liczby pojemników, np. num_bins ~ sqrt( len(a) ).

(drobnym drukiem: dwie zupełnie różne rzeczy się tu dzieją,

  • binning / histogramming surowych danych
  • plot interpoluje gładką krzywą przez powiedzmy 20 wartości binarnych.

Któreś z nich może być daleko od danych, które są "clumpy" lub ma długie ogony, nawet dla danych 1d - 2d, dane 3d staje się coraz trudniejsze.
Density_estimation oraz z wykorzystaniem estymacji gęstości jądra Gaussa ).

 3
Author: denis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-09 15:52:02

Mam trywialny dodatek do metody Afoglii, do normalizacji 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

Normalizacja histo sprawia, że jej Całka jest jednością, co oznacza, że cdf nie będzie znormalizowany. Sam musisz to przeskalować.

 3
Author: Pete,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-14 04:08:54

Jeśli chcesz wyświetlić rzeczywisty prawdziwy ECDF (który, jak zauważył David B, jest funkcją krokową zwiększającą 1/N dla każdego z N punktów danych), moja sugestia jest taka, aby napisać kod, aby wygenerować dwa punkty "wykresu" dla każdego punktu danych:

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)

W ten sposób otrzymasz Wykres z N krokami charakterystycznymi dla ECDF, co jest przyjemne szczególnie dla zestawów danych, które są wystarczająco małe, aby kroki były widoczne. Nie ma też potrzeby robienia wiązania z histogramami (co grozi wprowadzeniem odchylenie od rysowanego ECDF).

 3
Author: drjoga,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-29 11:56:37

Możemy po prostu użyć funkcji step z matplotlib, która tworzy wykres stopniowy, który jest definicją empirycznego CDF:

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)

Ostateczna linia pionowa na max(data) została dodana ręcznie. W przeciwnym razie fabuła zatrzymuje się na poziomie 1 - 1/len(data).

Alternatywnie możemy użyć opcji where='post' do step()

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

W takim przypadku początkowa pionowa linia od zera nie jest wykreślona.

 2
Author: jolvi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-11 23:40:02

(jest to Kopia mojej odpowiedzi na pytanie: spisywanie CDF serii pandas w Pythonie )

CDF lub wykres funkcji rozkładu kumulacyjnego jest w zasadzie wykresem z posortowanymi wartościami na osi X, a na osi Y zbiorczym rozkładem. Tak więc, chciałbym utworzyć nową serię z wartości posortowane jako indeks i skumulowany rozkład jako wartości.

Najpierw Utwórz przykładową serię:

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

Sortuj serię:

ser = ser.order()

Teraz, przed kontynuowaniem, Dodaj ponownie ostatnią (i największą) wartość. Ten krok jest ważny szczególnie dla małych rozmiarów próbek, aby uzyskać bezstronny CDF:

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

Utwórz nową serię z wartościami posortowanymi jako indeks i rozkładem skumulowanym jako wartości

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

Na koniec wykreśl funkcję jako kroki:

ser_cdf.plot(drawstyle='steps')
 1
Author: kadee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:03:07

This is using 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)

```

 1
Author: sushmit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-16 21:06:26

Zakładając, że vals przechowuje twoje wartości, możesz po prostu narysować CDF w następujący sposób:

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

Aby przeskalować go między 0 a 1, wystarczy podzielić y przez 100.

 1
Author: user1966078,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-09 03:40:32

Jest to jednowierszowiec w seabornie, używając parametru kumulatywnego = True. Proszę bardzo,

import seaborn as sns
sns.kdeplot(a, cumulative=True)
 0
Author: dohmatob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-17 13:39:46

Żadna z odpowiedzi na razie nie obejmuje tego, co chciałem, gdy tu wylądowałem, czyli:

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

Ocenia empiryczne CDF danego zbioru danych w tablicy punktów x, które nie muszą być sortowane. Nie ma pośredniego binningu ani zewnętrznych bibliotek.

Równoważną metodą, która lepiej skaluje dla dużego x, jest sortowanie danych i używanie np.Wyszukiwanie:

def empirical_cdf(x, data):
    "evaluate ecdf of data at points x"
    data = np.sort(data)
    return np.searchsorted(data, x)/float(data.size)
 0
Author: Gregor Mitscha-Baude,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-20 12:22:19