Как ограничить контурный график только вариацией 3sigma для двумерного гауссова?

#python #matplotlib #contour #normal-distribution

Вопрос:

Мне было немного любопытно построить контурные графики для 2-мерного распределения Гаусса. В моем случае для заданного набора 2D-точек я группирую их в разные ячейки сетки и вычисляю матрицу ковариации для каждой ячейки и строю распределение Гаусса для каждой ячейки. Когда я строю график, мне нужен не весь контур ячейки, а распределение, ограниченное в пределах 3 сигм точек данных. Есть ли вообще возможность это сделать ?

Мой код выглядит следующим образом:

 import numpy as np
import matplotlib.pyplot as plt

def createCells():
    partition = 4
    coords = [np.linspace(-1.0 , 1.0, num = partition   1) for i in range(2)]
    x, y =  np.meshgrid(*coords)
    return x, y
    
def probab(mean, covMat, lPoints):
    lPoints = lPoints[..., np.newaxis] if lPoints.ndim == 2 else lPoints  ## Create vectorized values for the x, y
    if np.linalg.det(covMat) > 0:
        factor1 = (2*np.pi)*(np.linalg.det(covMat)**(-1/2))
        factor2 = np.exp((-1/2)*np.einsum('ijk,jl,ilk->ik', lPoints - mean, np.linalg.inv(covMat), lPoints - mean))
        return factor1*factor2
    
if __name__ == '__main__':
    points = np.array([[-0.35, -0.15], [0.1, 0.1], [-0.1, 0.1], [0.05, 0.05],[0.25, 0.05], [0.1, 0.15], [0.1, 0.2], [-0.2, -0.2], [-0.25, 0.25], [0.45, 0.45], [0.75, 0.75], [0.6, 0.6], [0.55, 0.55], [0.7, 0.7], [0.68, 0.73]])
    x1, y1 = createCells()
    x = x1[0]
    y = y1[:,0]
    lP = np.array([])
    numberOftimes = 0
    for i in range(len(x) - 1):
        for j in range(len(y) - 1):
            count = 0
            meanX = 0.0
            meanY = 0.0
            localPoints = []
            covMat1 = np.array([])
            covMat2 = np.array([])
            for point in points:
                inbetween_x = x[i] <= point[0] <= x[i   1]
                inbetween_y = y[j] <= point[1] <= y[j   1]
                if inbetween_x and inbetween_y:
                    count  = 1
                    meanX  = point[0]
                    meanY  = point[1]
                    localPoints.append([point[0], point[1]])
            if count >= 2:
                numberOftimes  = 1
                #print(f"The local points are {localPoints}")
                localPoints = np.array(localPoints)
                meanX /= count
                meanY /= count
                meanXY = np.array([meanX, meanY])
                #print(meanXY.shape)
                #print(localPoints.shape)
                lP = localPoints - meanXY
                for k in range(count):
                    lPtranspose = (np.array([lP[k]])).T
                    lPCurrent = (np.array([lP[k]]))
                    if len(covMat1) > 0:
                        covMat1  = lPtranspose.dot(lPCurrent)
                    else:
                        covMat1 = lPtranspose*lP[k]
                        covMat1 /= count
                lPoints = localPoints[..., np.newaxis] if lP.ndim == 2 else lP  ## Create vectorized values for the x, y
                meanXY1 = localPoints.mean(0)
                meanXY2 = lPoints.mean(0)
                covMat3 = np.einsum('ijk, ikj->jk', lPoints - meanXY2, lPoints - meanXY2) / lPoints[0] - 1
                #yamlStatus = self.savingYaml(i, j, meanXY, covMat3) ## To store the cell parameters in a yaml file (for now its just out of scope for the question)
                if np.linalg.det(covMat3) > 0:   #compute the probability only if the det is not 0
                    Xx = np.linspace(x[i], x[i   1], 1000)
                    Yy = np.linspace(y[i], y[i   1], 1000)
                    Xx,Yy = np.meshgrid(Xx, Yy)
                    lPoints = np.vstack((Xx.flatten(), Yy.flatten())).T
                    pos = np.empty(Xx.shape   (2,))
                    pos[:, :, 0] = Xx
                    pos[:, :, 1] = Yy
                    z2 = probab(meanXY2, covMat3, lPoints)
                    summed = np.sum(z2)
                    z2 = z2.reshape(1000, 1000)
                    cs = plt.contourf(Xx, Yy, z2)#, cmap=cm.viridis)
                    plt.clabel(cs)
                localPoints = []
                #print(f"The number of times count is greater than 1 is {numberOftimes}")
        plt.plot(x1, y1, marker='.', linestyle='none', markersize=20)
        plt.plot(points[:,0 ], points[:, 1], marker='.', linestyle='none', markersize=10)
        plt.grid(linewidth=0.5)#abs(x1[0][0]-y1[0][0]))
        plt.show()
 

Комментарии:

1. пожалуйста, измените свой код, чтобы он работал, тогда другие смогут вам помочь

2. @ted Спасибо вам за изучение этого вопроса и за предложение. Я отредактировал. В надежде получить какие-нибудь ответы

3. то, что вы показали, является только частью вашего класса, я не думаю, что им могут управлять другие. Сделайте свой код минимальным и выполнимым, тогда другие ребята будут тратить меньше времени на то, чтобы заставить его работать. Если код не может быть запущен, большинство людей просто проигнорируют ваш вопрос….

4. @ted930511, еще раз спасибо за ваше ценное предложение, вроде как привыкаю быть в stackoverflow. Я сделал код как отдельную часть, так что теперь он должен быть в порядке для запуска. Надеясь получить какие-то идеи и подсказки..

5. Я думаю, что вам нужно сделать 2d-подгонку по Гауссу? Каков ваш ожидаемый результат (если есть какие-либо аналогичные графики)? Вывод из вашего кода выглядит для меня странно…