Как построить эмпирический cdf в matplotlib в Python?
Как я могу построить эмпирический CDF массива чисел в matplotlib в Python? Я ищу cdf-аналог функции "hist" pylab.
Одна вещь, о которой я могу думать, - это:
from scipy.stats import cumfreq
a = array([...]) # my array of numbers
num_bins = 20
b = cumfreq(a, num_bins)
plt.plot(b)
Правильно ли это? Есть ли более простой/лучший способ?
спасибо.
Ответы
Ответ 1
Это похоже на то, что вы хотите. Две вещи:
Во-первых, результаты представляют собой набор из четырех элементов. Третий размер бункеров. Вторая - начальная точка самого маленького бункера. Первое - это количество точек в каждом или ниже каждого бункера. (Последнее - количество точек вне пределов, но поскольку вы не задали никаких параметров, все точки будут закодированы.)
Во-вторых, вы захотите перемасштабировать результаты, чтобы окончательное значение равно 1, чтобы следовать обычным соглашениям CDF, но в остальном это правильно.
Вот что он делает под капотом:
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
Выполняет гистограммирование, затем производит суммарную сумму отсчетов в каждом бункере. Таким образом, i-е значение результата - это количество значений массива, меньшее или равное максимальному значению i-го бина. Итак, конечное значение - это только размер исходного массива.
Наконец, чтобы построить его, вам нужно будет использовать начальное значение bin и размер бункера, чтобы определить, какие значения оси x вам понадобятся.
Другой вариант - использовать numpy.histogram
, который может выполнять нормализацию и возвращает края бункера. Вам нужно будет сделать кумулятивную сумму полученных результатов.
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:]
- верхний край каждого бина.)
Ответ 2
Вы можете использовать функцию ECDF
из 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)
С версией 0.4 scicits.statsmodels
было переименовано в statsmodels
. ECDF
теперь находится в модуле distributions
(в то время как statsmodels.tools.tools.ECDF
обесценивается).
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()
Ответ 3
Если вам нравится linspace
и предпочитаете однострочные, вы можете сделать:
plt.plot(np.sort(a), np.linspace(0, 1, len(a), endpoint=False))
Учитывая мои вкусы, я почти всегда делаю:
# a is the data array
sorted_ = np.sort(a)
yvals = np.arange(len(sorted_))/float(len(sorted_))
plt.plot(sorted_, yvals)
Что работает для меня, даже если есть значения данных >O(1e6)
.
Если вам действительно нужно пропустить образец, я бы установил
sorted_ = np.sort(a)[::down_sampling_step]
Изменить, чтобы ответить на комментарий/изменить, почему я использую endpoint=False
или yvals
, как определено выше. Ниже приведены некоторые технические детали.
Эмпирический CDF обычно формально определяется как
CDF(x) = "number of samples <= x"/"number of samples"
чтобы точно соответствовать этому формальному определению, вам нужно будет использовать yvals = np.arange(1,len(sorted_)+1)/float(len(sorted_))
, чтобы мы получили
yvals = [1/N, 2/N ... 1]
. Эта оценка является несмещенной оценкой, которая будет сходиться к истинному CDF в пределе бесконечных выборок Wikipedia ref..
Я склонен использовать yvals = [0, 1/N, 2/N ... (N-1)/N]
, так как (а) легче кодировать/более идоматично, (б), но формально все еще формально, так как всегда можно обменять CDF(x)
на 1-CDF(x)
в доказательстве сходимости и ( c) работает с методом (простой) понижающей дискретизации, описанным выше.
В некоторых частных случаях полезно определить
yvals = (arange(len(sorted_))+0.5)/len(sorted_)
который является промежуточным между этими двумя соглашениями. Что, по сути, говорит: "существует вероятность 1/(2N)
значения, меньшего, чем самая низкая, которую я видел в моем примере, и вероятность 1/(2N)
значения, которое больше, чем самое большое, которое я видел до сих пор.
Однако для больших выборок и разумных распределений соглашение, приведенное в основной части ответа, легко писать, является несмещенной оценкой истинного CDF и работает с методологией понижающей дискретизации.
Ответ 4
Вы пробовали кумулятивный аргумент = True для pyplot.hist?
Ответ 5
Один слот на основе ответа Дейва:
plt.plot(np.sort(arr), np.linspace(0, 1, len(arr), endpoint=False))
Изменить: это также было предложено hans_meine в комментариях.
Ответ 6
Что вы хотите делать с CDF?
Чтобы построить это, это начало. Вы можете попробовать несколько разных значений, например:
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
перечислены различные правила для количества ящиков, например. num_bins ~ sqrt( len(a) )
.
(Точная печать: здесь происходят две совершенно разные вещи,
- binning/histogramming необработанных данных
-
plot
интерполирует плавную кривую через 20 значений, обозначенных буквой.
Любой из них может уйти от данных, которые "clumpy"
или имеет длинные хвосты, даже для 1d данных - 2d, 3d данные становятся все труднее.
Смотрите также
Density_estimation
а также
используя scipy gaussian плотность плотности ядра
).
Ответ 7
У меня есть тривиальное дополнение к методу AFoglia, чтобы нормализовать 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
Нормализация histo делает его интегральное единство, что означает, что cdf не будет нормализоваться. Вы должны масштабировать его самостоятельно.
Ответ 8
Если вы хотите отобразить фактический истинный ECDF (который, как отметил Дэвид Б, является ступенчатой функцией, которая увеличивает 1/n в каждом из n точек данных), мое предложение состоит в том, чтобы написать код для создания двух точек "графика" для каждого дататопа:
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)
Таким образом вы получите график с n шагами, которые характерны для ECDF, что особенно приятно для наборов данных, которые достаточно малы, чтобы этапы были видимыми. Кроме того, нет необходимости делать какие-либо операции с гистограммами (которые рискуют ввести предвзятость в нарисованный ECDF).
Ответ 9
Мы можем просто использовать функцию step
из matplotlib
, которая делает поэтапный график, который является определением эмпирического 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)
Окончательная вертикальная линия в max(data)
была добавлена вручную. В противном случае график просто останавливается на уровне 1 - 1/len(data)
.
В качестве альтернативы мы можем использовать опцию where='post'
для step()
levels = np.linspace(1. / len(data), 1, len(data))
plt.step(sorted(data), levels, where='post')
в этом случае начальная вертикальная линия от нуля не строится.
Ответ 10
(Это копия моего ответа на вопрос: Построение CDF серии pandas в python)
График функции CDF или кумулятивного распределения в основном представляет собой график, по оси X - отсортированные значения, а по оси Y - кумулятивное распределение. Итак, я бы создал новую серию с отсортированными значениями как индекс и кумулятивное распределение как значения.
Сначала создайте примерную серию:
import pandas as pd
import numpy as np
ser = pd.Series(np.random.normal(size=100))
Сортировка серии:
ser = ser.order()
Теперь, прежде чем продолжить, добавьте снова последнее (и самое большое) значение. Этот шаг особенно важен для небольших размеров выборки, чтобы получить непредвзятый CDF:
ser[len(ser)] = ser.iloc[-1]
Создайте новую серию с отсортированными значениями как индекс и кумулятивное распределение как значения
cum_dist = np.linspace(0.,1.,len(ser))
ser_cdf = pd.Series(cum_dist, index=ser)
Наконец, постройте функцию как шаги:
ser_cdf.plot(drawstyle='steps')
Ответ 11
Это используется 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)
`` `
Ответ 12
Предполагая, что vals сохраняет ваши значения, вы можете просто построить CDF следующим образом:
y = numpy.arange(0, 101)
x = numpy.percentile(vals, y)
plot(x, y)
Чтобы масштабировать его между 0 и 1, просто разделите y на 100.
Ответ 13
Это один лайнер в морском дне, используя кумулятивный = истинный параметр. Здесь вы идете,
import seaborn as sns
sns.kdeplot(a, cumulative=True)
Ответ 14
Ни один из ответов пока не охватывает то, что я хотел, когда я приземлился здесь, а именно:
def empirical_cdf(x, data):
"evaluate ecdf of data at points x"
return np.mean(data[None, :] <= x[:, None], axis=1)
Он оценивает эмпирический CDF данного набора данных в массиве точек x, которые не нужно сортировать. Нет промежуточного биннинга и нет внешних библиотек.
Эквивалентный метод, который лучше масштабируется для больших x, заключается в сортировке данных и использовании 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)