Контурный график для ограниченных образцов / неровная сетка - PullRequest
0 голосов
/ 09 марта 2020

TLDR: я новичок в использовании matplotlib.pyplot.contourf. Как заставить это работать для пользовательской функции (ось z) и сгенерированных выборок (ось x и ось y)?


У меня есть пользовательская функция, которая возвращает распределение (в основном функция KDE, которую я переопределил в Python, чтобы в конечном итоге использовать настраиваемые переменные полосы пропускания).

У меня ограниченный размер выборки / мои выборки распределены неравномерно по осям X и Y.

Как получить contourf в matplotlib для отображения распределения, учитывая, что распределение вычисляется с помощью моей пользовательской функции и моих образцов? Я могу заставить contourf нормально работать с scipy.stats.multivariate_normal.pdf() функция, и, насколько я могу судить, это потому, что он принимает оси X и Y (np.linspace s) в качестве параметров. Это на самом деле не заботится о ваших реальных сэмплах.

Например:

# IMPORTS
import numpy as np
from scipy import stats
from numpy.random import multivariate_normal
from matplotlib import pyplot as plt
from functools import partial

# PARAMETERS
dim = 100
num_samples = dim**2

x = y = np.linspace(-4,4,dim)
X,Y = np.meshgrid(x,y)
X,Y = X.flatten(), Y.flatten()
XY = np.array([X,Y]).T

means = [[-1.5,0],[1.5,0]]
covs = [
    [[1,0],[0,1]],
    [[1,0],[0,1]],
       ]
N = num_samples // len(covs) # 10000

# GET DATA AND SCIPY.STATS DISTRIBUTION

datas = [multivariate_normal(mean=means[0],cov=covs[0],size=N)]
densities = stats.multivariate_normal.pdf(x=XY, mean=means[0], cov=covs[0])

for mean,cov in zip(means[1:], covs[1:]):
    datas += [multivariate_normal(mean=mean,cov=cov,size=N)]
    densities += stats.multivariate_normal.pdf(x=XY, mean=mean, cov=cov)

data = np.vstack(np.array(datas))
density = np.vstack(np.array(densities))

xline,yline, density= map(lambda A: A.reshape(dim,dim), [X,Y,density])

# CUSTOM FUNCTION

X,Y = data[:,0], data[:,1]
Z = KDE(S=[X,Y],m=2,bw='silverman')
X,Y,Z = map(lambda A: A.reshape(dim,dim), [X,Y,Z]) # reshape

# PLOTTING

method_data = {'Distribution':[xline,yline,density],
               'Data':[X,Y],
               'Silverman': [X,Y,Z]
              }

method_names = list(method_data.keys())

plt.figure(figsize=(20,10))

for i in range(len(method_names)):
    method_name = method_names[i]
    ax = plt.subplot(f'24{i+1}')

    if method_name == 'Data':
        plt.scatter(*method_data[method_name],alpha=0.2)
    else:
        ax.contourf(*method_data[method_name])

    ax.set_title(f"{method_name}")
    ax.set(xlabel="X", ylabel="Y")
#     ax.set_facecolor('#44146f')

plt.tight_layout(pad=1.0)
plt.show()

plots

Слева: ось Z состоит из stats.multivariate_normal.pdf(x=XY, mean=mean, cov=cov), и это просто xline и yline (из np.linspace и np.meshgrid) для оси X и оси Y очень хорошо.

Middle: диаграмма рассеяния некоторых данных образца, с координаты X и Y

Справа: красивая работа или моя грустная попытка ... ось Z сделана с использованием моей пользовательской функции для данных [X,Y]


Очевидно, что справа не используются xline и yline в качестве осей x и y, поэтому в контуре пропущено много точек.

Ниже приведены мои неудачные попытки исправить это:

plt.contourf(xline,yline,Z); plt.show()

enter image description here

X,Y = xline.flatten(), yline.flatten()
Z = KDE(S=[X,Y],m=2,bw='silverman')
X,Y,Z = map(lambda A: A.reshape(dim,dim), [X,Y,Z]) # reshape

plt.contourf(X,Y,Z)
plt.show()

enter image description here

plt.contourf(np.sort(X),np.sort(Y),Z); plt.show()

enter image description here

Помощь?

...