Как построить эмпирический cdf в matplotlib в Python? - программирование
Подтвердить что ты не робот

Как построить эмпирический 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)

Правильно ли это? Есть ли более простой/лучший способ?

спасибо.

4b9b3361

Ответ 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)