web-dev-qa-db-ja.com

Matplotlibの散布図の等高線

Matplotlibで生成している大規模な散布図(〜100,000ポイント)があります。各ポイントはこのx/y空間に位置しているので、ポイントの総数の特定のパーセンタイルを含む等高線を生成したいと思います。

これを行うmatplotlibの関数はありますか?私はcontour()を調べましたが、このように機能するには独自の関数を作成する必要があります。

ありがとう!

13
astromax

基本的に、ある種の密度推定が必要です。これを行うには複数の方法があります。

  1. ある種の2Dヒストグラムを使用します(例:matplotlib.pyplot.hist2dまたはmatplotlib.pyplot.hexbin)(結果を等高線として表示することもできます。numpy.histogram2dを使用して、結果の配列の等高線を作成するだけです)。

  2. カーネル密度推定(KDE)を作成し、結果の輪郭を描きます。 KDEは本質的に平滑化されたヒストグラムです。ポイントが特定のビンに入る代わりに、周囲のビンに重みを追加します(通常はガウスの「ベルカーブ」の形をしています)。

2Dヒストグラムの使用は単純で理解しやすいですが、基本的に「ブロック状」の結果が得られます。

2番目のものを「正しく」行うことにはいくつかのしわがあります(つまり、正しい方法は1つではありません)。ここでは詳細については説明しませんが、結果を統計的に解釈する場合は、それを確認する必要があります(特に帯域幅の選択)。

とにかく、ここに違いの例があります。それぞれを同様にプロットするので、等高線は使用しませんが、等高線プロットを使用して2DヒストグラムまたはガウスKDEを簡単にプロットできます。

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import kde

np.random.seed(1977)

# Generate 200 correlated x,y points
data = np.random.multivariate_normal([0, 0], [[1, 0.5], [0.5, 3]], 200)
x, y = data.T

nbins = 20

fig, axes = plt.subplots(ncols=2, nrows=2, sharex=True, sharey=True)

axes[0, 0].set_title('Scatterplot')
axes[0, 0].plot(x, y, 'ko')

axes[0, 1].set_title('Hexbin plot')
axes[0, 1].hexbin(x, y, gridsize=nbins)

axes[1, 0].set_title('2D Histogram')
axes[1, 0].hist2d(x, y, bins=nbins)

# Evaluate a gaussian kde on a regular grid of nbins x nbins over data extents
k = kde.gaussian_kde(data.T)
xi, yi = np.mgrid[x.min():x.max():nbins*1j, y.min():y.max():nbins*1j]
zi = k(np.vstack([xi.flatten(), yi.flatten()]))

axes[1, 1].set_title('Gaussian KDE')
axes[1, 1].pcolormesh(xi, yi, zi.reshape(xi.shape))

fig.tight_layout()
plt.show()

enter image description here

注意点:ポイント数が非常に多いと、scipy.stats.gaussian_kdeが非常に遅くなります。近似を行うことで速度を上げるのはかなり簡単です。2Dヒストグラムを取得し、正しい半径と共分散のガウスフィルターでぼかします。よろしければ例を挙げましょう。

もう1つの注意点:非デカルト座標系でこれを行う場合、これらの方法はいずれも適用されません!球殻で密度推定を取得するのは少し複雑です。

46
Joe Kington

同じ質問があります。ポイントの一部を含む等高線をプロットする場合は、次のアルゴリズムを使用できます。

2Dヒストグラムを作成する

h2, xedges, yedges = np.histogram2d(X, Y, bibs = [30, 30])

h2は、ある長方形の点の数である整数を含む2次元行列になりました。

hravel = np.sort(np.ravel(h2))[-1] #all possible cases for rectangles 
hcumsum = np.sumsum(hravel)

醜いハック、

h2 2d行列のすべての点について、現在分析している点と同じかそれ以上の点を含む長方形の累積点数を与えましょう。

hunique = np.unique(hravel)

hsum = np.sum(h2)

for h in hunique:
    h2[h2 == h] = hcumsum[np.argwhere(hravel == h)[-1]]/hsum

h2の等高線をプロットします。これは、すべての点をある程度含む等高線になります。

2
andrey