Контуры Диаграммы Рассеяния В Matplotlib
У меня есть массивный scatterplot (~100,000 точек), который я генерирую в matplotlib. Каждая точка имеет местоположение в этом пространстве x/y, и я хотел бы создать контуры, содержащие определенные процентили от общего числа точек.
есть ли функция в matplotlib, которая сделает это? Я просмотрел contour (), но мне пришлось бы написать свою собственную функцию, чтобы работать таким образом.
спасибо!
2 ответов
в принципе, вы хотите какую-то оценку плотности. Существует несколько способов сделать это:
используйте какую-то 2D-гистограмму (например,
matplotlib.pyplot.hist2d
илиmatplotlib.pyplot.hexbin
) (вы также можете отобразить результаты в виде контуров-просто используйтеnumpy.histogram2d
а затем контур результирующего массива.)сделайте оценку плотности ядра (KDE) и контур результатов. KDE по существу является сглаженной гистограммой. Вместо точки, попадающей в определенный ящик, он добавляет вес в соседние ящики (обычно в форме гауссовой колоколообразной кривой).
С помощью 2D-гистограммы проста и легка для понимания, но fundementally дает "блочный" результаты.
есть некоторые морщины, чтобы сделать второй "правильно" (т. е. нет одного правильного способа). Я не буду вдаваться в подробности здесь, но если вы хотите интерпретировать результаты статистически, вам нужно прочитать об этом (особенно о пропускной способности выбор.)
во всяком случае, вот пример различий. Я собираюсь построить каждый из них аналогично, поэтому я не буду использовать контуры, но вы можете так же легко построить 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()
одно предостережение: с очень большим количеством очков,scipy.stats.gaussian_kde
станет очень медленной. Это довольно легко, чтобы его ускорить, сделав приближение ... просто в 2D гистограммы и размыть его с помощью фильтра guassian из правый радиус и ковариация. Я могу привести пример, если хочешь.
один нюанс: если вы делаете это в декартовой системе координат, ни один из этих методов применить! Получение оценок плотности на сферической оболочке немного сложнее.
у меня тот же вопрос. Если вы хотите построить контуры, которые содержат некоторую часть точек, вы можете использовать следующий алгоритм:
создать 2d гистограмму
h2, xedges, yedges = np.histogram2d(X, Y, bibs = [30, 30])
h2 теперь 2d-матрица, содержащая целые числа, которые являются количеством точек в некотором прямоугольнике
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, это будет контур, который содержит некоторое количество всех точек