Двумерное гауссово распределение не равно единице?

Я построил обернутое двумерное гауссово распределение в Python, используя приведенное здесь уравнение: http://www.aos.wisc.edu/~dvimont/aos575/Handouts/bivariate_notes.pdf Однако я не понимаю, почему мое распределение не дает в сумме 1, несмотря на включение константы нормализации.

Для решетки U x U

import numpy as np
from math import *

U = 60
m = np.arange(U)
i = m.reshape(U,1)
j = m.reshape(1,U)

sigma = 0.1
ii = np.minimum(i, U-i)
jj = np.minimum(j, U-j)
norm_constant = 1/(2*pi*sigma**2)
xmu = (ii-0)/sigma; ymu = (jj-0)/sigma
rhs = np.exp(-.5 * (xmu**2 + ymu**2))
ker = norm_constant * rhs

>> ker.sum() # area of each grid is 1 
15.915494309189533

Я уверен, что в том, как я думаю об этом, в корне отсутствует, и подозреваю, что требуется какая-то дополнительная нормализация, хотя я не могу об этом рассуждать.

ОБНОВИТЬ:

Благодаря проницательным предложениям других, я переписал свой код, чтобы применить нормализацию L1 к ядру. Однако оказывается, что в контексте двумерной свертки с помощью БПФ сохранение диапазона в виде [0, U] все же может дать убедительный результат:

U = 100
Ukern = np.copy(U)
#Ukern = 15

m = np.arange(U)
i = m.reshape(U,1)
j = m.reshape(1,U)

sigma = 2.
ii = np.minimum(i, Ukern-i)
jj = np.minimum(j, Ukern-j)
xmu = (ii-0)/sigma; ymu = (jj-0)/sigma
ker = np.exp(-.5 * (xmu**2 + ymu**2))
ker /= np.abs(ker).sum()

''' Point Density '''
ido = np.random.randint(U, size=(10,2)).astype(np.int)
og = np.zeros((U,U))
np.add.at(og, (ido[:,0], ido[:,1]), 1)

''' Convolution via FFT and inverse-FFT '''
v1 = np.fft.fft2(ker)
v2 = np.fft.fft2(og)
v0 = np.fft.ifft2(v2*v1)
dd = np.abs(v0)

plt.plot(ido[:,1], ido[:,0], 'ko', alpha=.3)
plt.imshow(dd, origin='origin')
plt.show()

введите описание изображения здесь С другой стороны, определение размера ядра с помощью закомментированной строки дает неправильный график:

введите здесь описание изображения


person neither-nor    schedule 11.01.2016    source источник
comment
Я не совсем понимаю, зачем вам np.minimum(i, U-i). Чего вы там пытаетесь добиться?   -  person Praveen    schedule 11.01.2016
comment
Кроме того, не могли бы вы определить, что вы подразумеваете под оберткой здесь?   -  person Praveen    schedule 11.01.2016
comment
@Praveen imaluengo был прав, когда подозревал, что я пытаюсь построить гауссовское ядро ​​- оно представляет собой индивидуальный диапазон движения, и я сворачиваю его с дискретным распределением населения, чтобы получить оценку поверхности плотности населения. Функция минимума устанавливает пик ядра в начале координат, а значение ядра уменьшается с расстоянием до начала координат. Таким образом, свертывание подразумевает, что ядро ​​оборачивает края решетки UxU, в результате чего получается график с полукругами в четырех углах.   -  person neither-nor    schedule 11.01.2016


Ответы (2)


ПРИМЕЧАНИЕ. Как указано в комментариях ниже, это решение допустимо только в том случае, если вы пытаетесь построить ядро ​​свертки Гаусса (или фильтр Гаусса) для целей обработки изображений. Это не нормированная гауссова функция плотности, но это форма, которая используется для удаления гауссовского шума из изображений.


Вам не хватает нормализации L1:

ker /= np.abs(ker).sum()

Что заставит ваше ядро ​​вести себя как реальная функция плотности. Поскольку сетка, которую вы имеете, может сильно различаться по величине своих значений, необходим описанный выше шаг нормализации.

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

Ваша вторая ошибка, как заявил @Praveen, заключается в том, что вам нужно взять сетку из [-U//2, U//2]. Вы можете сделать это как:

i, j = np.mgrid[-U//2:U//2+1, -U//2:U//2+1]

Наконец, если вы пытаетесь построить фильтр Гаусса, размер ядра обычно оценивается от сигмы (чтобы избежать нулей далеко от центра) как U//2 <= t * sigma, где t — параметр усечения, обычно устанавливаемый t=3 или t=4.

person Imanol Luengo    schedule 11.01.2016
comment
Я не думаю, что это хорошая идея. ОП, похоже, пытается создать распределение вероятностей (согласно последующим примечаниям). Слепая нормализация ядра даст правильную плотность вероятности, но разрушит большую часть его статистических свойств. - person Praveen; 11.01.2016
comment
@Praveen И все же нормализованное гауссовское ядро ​​​​L1 - это то, что используется при обработке изображений для удаления гауссовского шума из изображения. Я согласен с тем, что он не сохраняет должным образом статистические свойства, но если я не ошибаюсь и то, что хочет ОП, - это фильтр Гаусса (а не модель Гаусса), это правильный путь. - person Imanol Luengo; 11.01.2016
comment
@Praveen, спасибо за комментарии. Вы помогли мне сделать это более понятным (для конкретного случая). У вас также есть мой, так как ваш ответ на самом деле моделирует настоящий гаусс (и мы еще не знаем, что такое OP после: p). Это весьма полезно такого рода обсуждения, поскольку всегда узнаешь что-то известное. Спасибо! - person Imanol Luengo; 11.01.2016
comment
@imaluengo Я действительно создаю гауссово ядро ​​​​для свертки. Вы хорошо прочитали мое намерение! :) Спасибо за ваш постоянный вклад и правки! Однако я все еще немного смущен последними двумя пунктами, которые вы сделали: почему необходимо сэмплировать сетку из [-U//2, U//2] и почему неправильно делать это по-моему, из [ 0, У]? - person neither-nor; 11.01.2016
comment
@ ни-ни Это потому, что, если вы установите диапазон как [0,U], вы по существу центрируете фильтр Гаусса в верхнем левом углу окна. Вместо этого, когда вы применяете гауссову свертку, ядро ​​​​центрируется на каждом пикселе изображения (становится этот пиксель центральным пикселем ядра, (0,0)). Это делается для того, чтобы центрировать двумерный фильтр Гаусса в центре окна (интересующий пиксель) и получить средневзвешенное значение Гаусса (чем дальше пиксель от центра, тем меньше его вес). - person Imanol Luengo; 11.01.2016
comment
@ни-ни-ни 2 изображения, опубликованные @Praveen, не показывают ваше фактическое: гауссовское центрирование в нижнем левом углу (или верхнем левом углу, если вы инвертируете ось y, как это обычно бывает при обработке изображений); и желаемое распределение (в центре посередине). - person Imanol Luengo; 11.01.2016
comment
@imaluengo Я только что реализовал 2D-гауссову свертка, используя оба параметра диапазона в своем обновлении. Хотя то, что вы сказали, имеет более интуитивный смысл, как-то численно [0,U] работает лучше, не знаю почему. - person neither-nor; 12.01.2016
comment
@ ни то, ни другое: выполняя v0 = np.fft.ifft2(v1*v2), вы сворачиваете свое ядро ​​​​с изображением, а не изображение с ядром. Эта строка должна быть v0 = np.fft.ifft2(v2*v1). И для теста сделайте v2 больше (100x100) и v1 (ядро) меньше (15x15). Они не должны иметь одинаковую форму. Наконец, рассмотрите возможность использования rfft2 и irfft2 (используйте только действительную часть). - person Imanol Luengo; 12.01.2016
comment
@imaluengo Только что реализовал предложения в обновлении. Возможно, это не работает в Python? - person neither-nor; 12.01.2016
comment
@neither-not Нет, это работает на питоне. Результат полностью устраивает. Вы просто вращаетесь в области Фурье, а не в области изображений (по промаху я удалил свой старый комментарий). Я сейчас не за компьютером (планшетом), завтра обновлю пост двумя примерами сверток Фурье и скользящего окна. - person Imanol Luengo; 12.01.2016

В настоящее время (сильно увеличенный) контурный график вашего ker выглядит следующим образом: Контур текущего ядра

Как видите, это совсем не похоже на ядро ​​Гаусса. Большая часть вашей функции умирает от 0 до 1. Глядя на само ядро, мы видим, что все значения действительно очень быстро умирают:

>>> ker[0:5, 0:5]
array([[  1.592e+001,   3.070e-021,   2.203e-086,   5.879e-195,   0.000e+000],
       [  3.070e-021,   5.921e-043,   4.248e-108,   1.134e-216,   0.000e+000],
       [  2.203e-086,   4.248e-108,   3.048e-173,   8.136e-282,   0.000e+000],
       [  5.879e-195,   1.134e-216,   8.136e-282,   0.000e+000,   0.000e+000],
       [  0.000e+000,   0.000e+000,   0.000e+000,   0.000e+000,   0.000e+000]])

Суммарное значение 15,915, которое вы получаете, в основном просто ker[0, 0]. Все это говорит вам о том, что вы неправильно строите свою сетку.

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

Итак, во-первых, если вы хотите, чтобы полная плотность была сосредоточена вокруг mu=0, вам нужно взять i и j от -U // 2 до U // 2. Но чтобы решить вашу проблему с разрешением, я рекомендую взять U точек между -0,5 и 0,5.

import numpy as np
import matplotlib.pyplot as plt

U = 60
m = np.linspace(-0.5, 0.5, U)    # 60 points between -1 and 1
delta = m[1] - m[0]              # delta^2 is the area of each grid cell
(x, y) = np.meshgrid(m, m)       # Create the mesh

sigma = 0.1
norm_constant = 1 / (2 * np.pi * sigma**2)

rhs = np.exp(-.5 * (x**2 + y**2) / sigma**2)
ker = norm_constant * rhs
print(ker.sum() * delta**2)

plt.contour(x, y, ker)
plt.axis('equal')
plt.show()

Это дает сумму, близкую к 1,0, и ядро ​​с центром в mu=0, как и ожидалось. Контурный график исправленного ядра

Знание того, какой диапазон выбрать (от -0,5 до 0,5) в этом случае, зависит от вашей функции. Например, если вы теперь возьмете sigma = 2, вы обнаружите, что ваша сумма снова не сработает, потому что теперь вы делаете выборку слишком мелко. Настройка вашего диапазона как функции ваших параметров - что-то вроде -5 * sigma до 5 * sigma - может быть лучшим вариантом.

person Praveen    schedule 11.01.2016
comment
Если хотите, можете добавить строку plt.axis('equal'), чтобы изображения имели соотношение сторон 1:1. - person heltonbiker; 11.01.2016
comment
@heltonbiker Верно. Я просто не рассматривал это. Тогда позвольте мне немного улучшить это. - person Praveen; 11.01.2016
comment
@Praveen Несмотря на то, что я не создаю здесь статистически достоверную плотность вероятности, ваши данные чрезвычайно полезны и наверняка скоро пригодятся мне! - person neither-nor; 11.01.2016