web-dev-qa-db-ja.com

Pythonのmatplotlibで経験的累積分布関数をプロットする方法は?

Pythonでmatplotlibに数値の配列の経験的CDFをプロットするにはどうすればよいですか?私は、pylabの「hist」関数のcdfアナログを探しています。

私が考えることができる一つのことは:

from scipy.stats import cumfreq
a = array([...]) # my array of numbers
num_bins =  20
b = cumfreq(a, num_bins)
plt.plot(b)

それは正しいですか?より簡単/より良い方法はありますか?

ありがとう。

56
user248237

それは(ほぼ)まさにあなたが望むものに見えます。 2つのこと:

まず、結果は4つの項目のタプルです。 3番目はビンのサイズです。 2番目は、最小ビンの開始点です。最初は、各ビン内または下のポイントの数です。 (最後は制限外のポイントの数ですが、何も設定していないため、すべてのポイントがビニングされます。)

次に、CDFの通常の規則に従うために、最終値が1になるように結果を再スケーリングする必要がありますが、そうでない場合は正しいです。

これが内部で行うことです:

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番目のビンの最大値以下の配列値の数です。したがって、最終的な値は初期配列のサイズにすぎません。

最後に、プロットするには、ビンの初期値とビンサイズを使用して、必要な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:]は各ビンの上端です。)

16
AFoglia

linspaceが好きで、ワンライナーを好む場合は、次のことができます。

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

私の好みを考えると、私はほとんどいつも:

# a is the data array
x = np.sort(a)
y = np.arange(len(x))/float(len(x))
plt.plot(x, y)

>O(1e6)のデータ値があったとしても、それは私にとってはうまくいきます。本当にダウンサンプルが必要な場合は、設定します

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

Edit上記のようにendpoint=Falseまたはyを使用する理由に関するコメント/編集に応答します。以下は技術的な詳細です。

経験的CDFは通常、正式に次のように定義されます。

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

この正式な定義に正確に一致させるには、y = np.arange(1,len(x)+1)/float(len(x))を使用してy = [1/N, 2/N ... 1]を取得する必要があります。この推定量は、無限のサンプルの制限で真のCDFに収束する不偏推定量です Wikipedia ref。

私はy = [0, 1/N, 2/N ... (N-1)/N]を使用する傾向があります。なぜなら(a)コーディングがより簡単/よりイドマティックである、(b)常にCDF(x)1-CDF(x)収束証明、および(c)上記の(簡単な)ダウンサンプリング方法で動作します。

特定のケースでは、定義するのが便利です

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

これは、これら2つの規則の中間です。実際には、「サンプルで見た最低値よりも小さい値の1/(2N)チャンスがあり、最大値よりも大きい値の1/(2N)チャンスがある私はこれまで見てきました。

ただし、大規模なサンプルおよび合理的な分布の場合、回答の本文に記載されている規則は簡単に記述でき、真のCDFの公平な推定量であり、ダウンサンプリング方法論と連携します。

84
Dave

scikits.statsmodels ライブラリの ECDF 関数を使用できます。

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 に名前が変更されました。 ECDFdistributionsモジュールに配置されました( 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()
69
ars

Pyplot.histの累積引数= Trueを試しましたか?

15
Andrej Panjkov

デイブの答えに基づいたワンライナー:

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

編集:これはコメントのhans_meineによっても提案されました。

7
1''

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)で停止します。

または、step()に_where='post'_オプションを使用できます

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

この場合、ゼロからの最初の垂直線はプロットされません。

3
jolvi

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を正規化するとintegral unityになります。つまり、cdfは正規化されません。自分でスケーリングする必要があります。

3
Pete

実際の真のECDFを表示する場合(David Bが指摘したように、n個のデータポイントのそれぞれで1/n増加するステップ関数)、私の提案は各データポイントに対して2つの「プロット」ポイントを生成するコードを書くことです:

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)

この方法では、ECDFの特徴であるnステップのプロットを取得できます。これは、特にステップが見えるほど小さいデータセットの場合に便利です。また、ヒストグラムでビニングを行う必要はありません(描画されたECDFにバイアスを導入するリスクがあります)。

3
drjoga

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

ヒストグラム ビンの数に関するさまざまなルールをリストします。 num_bins ~ sqrt( len(a) )

(ファインプリント:ここでは2つのまったく異なることが行われていますが、

  • 生データのビニング/ヒストグラム化
  • plotは、たとえば20個のビン化された値を通して滑らかな曲線を補間します。

これらのいずれかは、1dデータであっても、「塊」であるか、長い尾を持つデータではうまくいきません。2d、3dデータはますます難しくなります。
Density_estimation および scipy gaussian kernel density evaluationを使用 も参照してください。

3
denis

累積= Trueパラメーターを使用した、シーボーンの1ライナーです。どうぞ、

import seaborn as sns
sns.kdeplot(a, cumulative=True)
2
dohmatob

これはボケを使用しています

`` `

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)

`` `

2
sushmit

(これは質問に対する私の答えのコピーです: pandas pythonのシリーズ)のCDFのプロット

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')
1
kadee

Valsが値を保持していると仮定すると、次のように単純にCDFをプロットできます。

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

0から1の間でスケーリングするには、yを100で除算します。

1
user1966078

私の意見では、以前の方法はどれも、実験者の元の質問であった経験的CDFをプロットする完全な(そして厳密な)仕事をしていません。私は失われた同情的な魂のために私の提案を投稿します。

私の提案には次のようなものがあります:1)最初の式 here のように定義された経験的CDFを考慮します。つまり、AW Van der Waartの漸近統計(1998)、2)関数のステップ動作を明示的に示す、3)不連続を解決するマークを表示することにより、経験的CDFが右から連続的であることを明示的に示す、4)ゼロを拡張し、ユーザー定義のマージンまでの極値で1つの値。私はそれが誰かを助けることを願っています:

def plot_cdf( data, xaxis = None, figsize = (20,10), line_style = 'b-',
ball_style = 'bo', xlabel = r"Random variable $X$", ylabel = "$N$-samples
empirical CDF $F_{X,N}(x)$" ):
     # Contribution of each data point to the empirical distribution
     weights = 1/data.size * np.ones_like( data )
     # CDF estimation
     cdf = np.cumsum( weights )
     # Plot central part of the CDF
     plt.figure( figsize = (20,10) )
     plt.step( np.sort( a ), cdf, line_style, where = 'post' )
     # Plot valid points at discontinuities
     plt.plot( np.sort( a ), cdf, ball_style )
     # Extract plot axis and extend outside the data range
     if not xaxis == None:
         (xmin, xmax, ymin, ymax) = plt.axis( )
         xmin = xaxis[0]
         xmax = xaxis[1]
         plt.axis( [xmin, xmax, ymin, ymax] )
     else:
         (xmin,xmax,_,_) = plt.axis()
         plt.plot( [xmin, a.min(), a.min()], np.zeros( 3 ), line_style )
     plt.plot( [a.max(), xmax], np.ones( 2 ), line_style )
     plt.xlabel( xlabel )
     plt.ylabel( ylabel )
0

これまでのところ、私がここに着陸したときに私が欲しかったものをカバーする答えはありません。

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

これは、ポイントxの配列で特定のデータセットの経験的CDFを評価します。これはソートする必要はありません。中間ビニングや外部ライブラリはありません。

大きな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)