2013-10-15 3 views
12

У меня массивная диаграмма рассеяния (~ 100 000 точек), которую я генерирую в matplotlib. Каждая точка имеет место в этом пространстве x/y, и я хотел бы генерировать контуры, содержащие определенные процентили от общего количества точек.Контуры рассеянности в Matplotlib

Есть ли функция в matplotlib, которая это сделает? Я просмотрел контур(), но мне пришлось бы написать свою собственную функцию для работы таким образом.

Спасибо!

ответ

40

В принципе, вам нужна оценка плотности. Там несколько способов сделать это: (. Вы можете также отобразить результаты в виде контуров - просто использовать numpy.histogram2d, а затем контурных результирующий массив)

  1. Используйте 2D-гистограмму своего рода (например, matplotlib.pyplot.hist2d или matplotlib.pyplot.hexbin)

  2. Сделайте оценку плотности ядра (KDE) и контур результатов. KDE - это, по сути, сглаженная гистограмма. Вместо точки, попадающей в конкретный бункер, он добавляет вес окружающим бункерам (обычно в форме гауссовой «колоколообразной кривой»).

Использование двумерной гистограммы прост и понятен, но в принципе дает «блочные» результаты.

Есть несколько морщин, чтобы сделать второй «правильно» (т. Е. Нет ни одного правильного пути). Я не буду вдаваться в подробности здесь, но если вы хотите интерпретировать результаты статистически, вам нужно прочитать об этом (в частности, выбор полосы пропускания).

Во всяком случае, вот пример различий. Я собираюсь построить каждый подобным образом, так что я не буду использовать контуры, но вы можете так же легко построить 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-гистограмму и смажьте ее с помощью гуассианского фильтра с правильным радиусом и ковариацией. Я могу привести пример, если хотите.

Еще одно предостережение: если вы делаете это в некарцевой системе координат, ни один из этих методов не применяется! Получение оценок плотности на сферической оболочке несколько сложнее.

+0

Это отличный ответ! Мой единственный вопрос теперь в том, что у меня есть метод бинирования данных, как я могу построить определенные проценты? Я настраиваю уровни контура, чтобы отразить проценты? Это похоже на доверительный интервал. – astromax

+2

Извините за задержку! В принципе, да, вы должны отрегулировать уровни контура, чтобы отразить проценты. Результаты gaussian_kde представляют собой оценку функции плотности вероятности (PDF). Следовательно, контурное значение 0,1 будет означать, что 90% данных находится внутри контура и т. Д. Для двумерной гистограммы значения являются необработанными подсчетами, поэтому вам нужно будет нормализовать. Надеюсь, это поможет немного прояснить ситуацию. –

+0

@ JoeKington, это круто. Но если бы я получил трехмерный случайный набор данных (x, y, z), можно ли применить этот метод? – diffracteD

2

У меня такой же вопрос. Если вы хотите построить контуры, которые содержат некоторую часть точек вы можете использовать следующий алгоритм:

создать 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 матрикса кумулятивного числа точек для прямоугольника ш hich содержит число очков, равное или большее, чем мы анализируем в настоящее время.

hunique = np.unique(hravel) 

hsum = np.sum(h2) 

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

Теперь участок контура для h2, это будет контур, содержащий некоторое количество всех точек

Смежные вопросы