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)
それは正しいですか?より簡単/より良い方法はありますか?
ありがとう。
それは(ほぼ)まさにあなたが望むものに見えます。 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:]
は各ビンの上端です。)
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の公平な推定量であり、ダウンサンプリング方法論と連携します。
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
に名前が変更されました。 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()
Pyplot.histの累積引数= Trueを試しましたか?
デイブの答えに基づいたワンライナー:
plt.plot(np.sort(arr), np.linspace(0, 1, len(arr), endpoint=False))
編集:これはコメントのhans_meineによっても提案されました。
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')
_
この場合、ゼロからの最初の垂直線はプロットされません。
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は正規化されません。自分でスケーリングする必要があります。
実際の真の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にバイアスを導入するリスクがあります)。
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を使用 も参照してください。
累積= Trueパラメーターを使用した、シーボーンの1ライナーです。どうぞ、
import seaborn as sns
sns.kdeplot(a, cumulative=True)
これはボケを使用しています
`` `
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)
`` `
(これは質問に対する私の答えのコピーです: 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')
Valsが値を保持していると仮定すると、次のように単純にCDFをプロットできます。
y = numpy.arange(0, 101)
x = numpy.percentile(vals, y)
plot(x, y)
0から1の間でスケーリングするには、yを100で除算します。
私の意見では、以前の方法はどれも、実験者の元の質問であった経験的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 )
これまでのところ、私がここに着陸したときに私が欲しかったものをカバーする答えはありません。
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)