web-dev-qa-db-ja.com

Pythonの分布からのサンプルのリストを与えられた値の確率を計算する方法は?

これが統計に含まれるかどうかはわかりませんが、私はPythonを使用してこれを達成しようとしています。基本的には整数のリストがあります:

data = [300,244,543,1011,300,125,300 ... ]

そして、私はこのデータが与えられたときに発生する値の確率を知りたいのです。 matplotlibを使用してデータのヒストグラムをグラフ化し、これらを取得しました。

enter image description here

enter image description here

最初のグラフでは、数字はシーケンスの文字数を表しています。 2番目のグラフでは、ミリ秒単位で測定された時間です。最小値はゼロより大きいですが、必ずしも最大値があるとは限りません。グラフは数百万の例を使用して作成されましたが、分布について他の仮定を行うことができるかどうかはわかりません。数百万の値の例がある場合、新しい値の確率を知りたいです。最初のグラフでは、長さが異なる数百万のシーケンスがあります。たとえば、長さ200の確率を知りたい。

連続分布の場合、正確なポイントの確率はゼロになるはずですが、新しい値のストリームが与えられた場合、各値の可能性を示す必要があります。 numpy/scipy確率密度関数の一部を調べましたが、scipy.stats.norm.pdf(data)のようなものを実行した後、どの値から選択するか、または新しい値を照会する方法がわかりません。確率密度関数が異なるとデータの適合も異なるようです。ヒストグラムの形状を考えると、どちらを使用するかを決定する方法がわかりません。

15
qazplok11

特定の分布を念頭に置いていないようですが、多数のデータサンプルがある可能性があるため、ノンパラメトリック密度推定法を使用することをお勧めします。説明するデータ型の1つ(ミリ秒単位の時間)は明らかに連続的であり、連続確率変数の確率密度関数(PDF)のノンパラメトリック推定の1つの方法は、すでに述べたヒストグラムです。ただし、以下に示すように、 カーネル密度推定(KDE) の方が適しています。説明する2番目のタイプのデータ(シーケンス内の文字数)は、個別の種類です。ここでは、カーネル密度の推定も有用であり、離散変数のすべての値に対して十分な量のサンプルがない場合の平滑化手法と見なすことができます。

密度の推定

以下の例は、最初に2つのガウス分布の混合からデータサンプルを生成し、次にカーネル密度推定を適用して確率密度関数を見つける方法を示しています。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
from sklearn.neighbors import KernelDensity

# Generate random samples from a mixture of 2 Gaussians
# with modes at 5 and 10
data = np.concatenate((5 + np.random.randn(10, 1),
                       10 + np.random.randn(30, 1)))

# Plot the true distribution
x = np.linspace(0, 16, 1000)[:, np.newaxis]
norm_vals = mlab.normpdf(x, 5, 1) * 0.25 + mlab.normpdf(x, 10, 1) * 0.75
plt.plot(x, norm_vals)

# Plot the data using a normalized histogram
plt.hist(data, 50, normed=True)

# Do kernel density estimation
kd = KernelDensity(kernel='gaussian', bandwidth=0.75).fit(data)

# Plot the estimated densty
kd_vals = np.exp(kd.score_samples(x))
plt.plot(x, kd_vals)

# Show the plots
plt.show()

これにより、次のプロットが生成されます。真の分布は青で表示され、ヒストグラムは緑で表示され、KDEを使用して推定されたPDFは赤で表示されます。

Plot

ご覧のとおり、この状況では、PDFヒストグラムで概算することはあまり有用ではありませんが、KDEははるかに優れた推定を提供します。ただし、データサンプルの数が多く、適切な選択肢がある場合ビンサイズの場合、ヒストグラムも適切な推定値を生成します。

KDEの場合に調整できるパラメーターは、kernelbandwidth。カーネルは推定PDFのビルディングブロックと考えることができます。ScikitLearnでは、ガウス、トップハット、エパネチニコフ、指数、線形、コサインなどのいくつかのカーネル関数を使用できます。帯域幅を変更すると、バイアスと分散のトレードオフを調整できます。帯域幅を大きくするとバイアスが増加します。これは、データサンプルが少ない場合に適しています。帯域幅を狭くすると分散が大きくなります(推定に含まれるサンプルが少なくなります)が、より多くのサンプルが利用可能な場合は、より良い推定が得られます。

確率の計算

PDFの場合、確率は、値の範囲にわたって積分を計算することによって取得されます。お気づきのように、特定の値の確率は0になります。

Scikit Learnには、確率を計算するための組み込み関数がないようです。ただし、ある範囲でPDFの積分を推定することは簡単です。PDFを範囲内で複数回評価し、得られた値に各評価ポイント間のステップサイズを掛けた値以下の例では、Nサンプルはステップstepで取得されます。

# Get probability for range of values
start = 5  # Start of the range
end = 6    # End of the range
N = 100    # Number of evaluation points 
step = (end - start) / (N - 1)  # Step size
x = np.linspace(start, end, N)[:, np.newaxis]  # Generate values in the range
kd_vals = np.exp(kd.score_samples(x))  # Get PDF values for each x
probability = np.sum(kd_vals * step)  # Approximate the integral of the PDF
print(probability)

kd.score_samplesは、データサンプルの対数尤度を生成することに注意してください。したがって、可能性を得るためにはnp.expが必要です。

組み込みのSciPy統合メソッドを使用して同じ計算を実行できます。これにより、より正確な結果が得られます。

from scipy.integrate import quad
probability = quad(lambda x: np.exp(kd.score_samples(x)), start, end)[0]

たとえば、1回の実行で、最初のメソッドは確率を0.0859024655305として計算し、2番目のメソッドは0.0850974209996139を生成しました。

19

OKこれを出発点として提供しますが、密度の推定は非常に広範なトピックです。シーケンス内の文字数が関係するケースでは、経験的確率を使用して、単純な頻度主義の観点からこれをモデル化できます。ここで、確率は本質的にパーセンテージの概念の一般化です。このモデルでは、サンプル空間は離散的で、すべて正の整数です。さて、次に、発生をカウントし、イベントの総数で除算して、確率の推定値を取得します。観測値がゼロの場合はどこでも、確率の推定値はゼロです。

>>> samples = [1,1,2,3,2,2,7,8,3,4,1,1,2,6,5,4,8,9,4,3]
>>> from collections import Counter
>>> counts = Counter(samples)
>>> counts
Counter({1: 4, 2: 4, 3: 3, 4: 3, 8: 2, 5: 1, 6: 1, 7: 1, 9: 1})
>>> total = sum(counts.values())
>>> total
20
>>> probability_mass = {k:v/total for k,v in counts.items()}
>>> probability_mass
{1: 0.2, 2: 0.2, 3: 0.15, 4: 0.15, 5: 0.05, 6: 0.05, 7: 0.05, 8: 0.1, 9: 0.05}
>>> probability_mass.get(2,0)
0.2
>>> probability_mass.get(12,0)
0

さて、タイミングデータについては、これを連続分布としてモデル化するのがより自然です。データにある程度の分布があると想定し、その分布をデータに適合させるパラメトリックアプローチを使用する代わりに、ノンパラメトリックアプローチを採用する必要があります。簡単な方法の1つは、 カーネル密度推定 を使用することです。これは単純に、ヒストグラムを平滑化して連続的な確率密度関数を与える方法と考えることができます。利用可能なライブラリがいくつかあります。おそらく、単変量データの最も簡単なものは、scipyのものです。

>>> import scipy.stats
>>> kde = scipy.stats.gaussian_kde(samples)
>>> kde.pdf(2)
array([ 0.15086911])

ある間隔での観測の確率を取得するには:

>>> kde.integrate_box_1d(1,2)
0.13855869478828692
5

これが可能な解決策の1つです。元のリストの各値の出現回数を数えます。特定の値の将来の確率は、過去の発生率です。これは、過去の発生数を元のリストの長さで割ったものです。 Pythonは非常に簡単です:

xは与えられた値のリストです

from collections import Counter
c = Counter(x)

def probability(a):
    # returns the probability of a given number a
    return float(c[a]) / len(x)
4
Paul Cornelius