복붙노트

[PYTHON] numpy에서 가우스 커널 행렬을 효율적으로 계산하는 방법은 무엇입니까?

PYTHON

numpy에서 가우스 커널 행렬을 효율적으로 계산하는 방법은 무엇입니까?

def GaussianMatrix(X,sigma):
    row,col=X.shape
    GassMatrix=np.zeros(shape=(row,row))
    X=np.asarray(X)
    i=0
    for v_i in X:
        j=0
        for v_j in X:
            GassMatrix[i,j]=Gaussian(v_i.T,v_j.T,sigma)
            j+=1
        i+=1
    return GassMatrix
def Gaussian(x,z,sigma):
    return np.exp((-(np.linalg.norm(x-z)**2))/(2*sigma**2))

이것이 나의 현재 방법입니다. 이 작업을 수행하기 위해 행렬 연산을 사용할 수있는 방법이 있습니까? X는 데이터 포인트입니다.

해결법

  1. ==============================

    1.예를 들어 가우스 커널을 사용 하시겠습니까? 이미지 스무딩? 그렇다면 scipy에 gaussian_filter () 함수가 있습니다 :

    예를 들어 가우스 커널을 사용 하시겠습니까? 이미지 스무딩? 그렇다면 scipy에 gaussian_filter () 함수가 있습니다 :

    또는 다음과 같이 작동해야합니다.

    import numpy as np
    import scipy.stats as st
    
    def gkern(kernlen=21, nsig=3):
        """Returns a 2D Gaussian kernel array."""
    
        interval = (2*nsig+1.)/(kernlen)
        x = np.linspace(-nsig-interval/2., nsig+interval/2., kernlen+1)
        kern1d = np.diff(st.norm.cdf(x))
        kernel_raw = np.sqrt(np.outer(kern1d, kern1d))
        kernel = kernel_raw/kernel_raw.sum()
        return kernel
    

    입력:

    import matplotlib.pyplot as plt
    plt.imshow(gkern(21), interpolation='none')
    

    산출:

  2. ==============================

    2.간단한 2D dirac 함수를 가우스 필터링 할 수 있습니다. 결과는 사용 된 필터 함수입니다.

    간단한 2D dirac 함수를 가우스 필터링 할 수 있습니다. 결과는 사용 된 필터 함수입니다.

    import numpy as np
    import scipy.ndimage.filters as fi
    
    def gkern2(kernlen=21, nsig=3):
        """Returns a 2D Gaussian kernel array."""
    
        # create nxn zeros
        inp = np.zeros((kernlen, kernlen))
        # set element at the middle to one, a dirac delta
        inp[kernlen//2, kernlen//2] = 1
        # gaussian-smooth the dirac, resulting in a gaussian filter mask
        return fi.gaussian_filter(inp, nsig)
    
  3. ==============================

    3.나 자신이 내 이미지 처리에 대한 대답을 사용했지만 다른 모듈에도 너무 많이 의존하고있다. 게다가, 수락 된 대답은 때로는 많은 제로 엔트리를 가진 커널을 생성합니다.

    나 자신이 내 이미지 처리에 대한 대답을 사용했지만 다른 모듈에도 너무 많이 의존하고있다. 게다가, 수락 된 대답은 때로는 많은 제로 엔트리를 가진 커널을 생성합니다.

    따라서, 여기 내 컴팩트 솔루션입니다 :

    import numpy as np
    
    
    def gkern(l=5, sig=1.):
        """
        creates gaussian kernel with side length l and a sigma of sig
        """
    
        ax = np.arange(-l // 2 + 1., l // 2 + 1.)
        xx, yy = np.meshgrid(ax, ax)
    
        kernel = np.exp(-(xx**2 + yy**2) / (2. * sig**2))
    
        return kernel / np.sum(kernel)
    
  4. ==============================

    4.2D 가우스 커널 행렬은 numpy 브로드 캐스트로 계산할 수 있습니다.

    2D 가우스 커널 행렬은 numpy 브로드 캐스트로 계산할 수 있습니다.

    def gaussian_kernel(size=21, sigma=3):
        """Returns a 2D Gaussian kernel.
        Parameters
        ----------
        size : float, the kernel size (will be square)
    
        sigma : float, the sigma Gaussian parameter
    
        Returns
        -------
        out : array, shape = (size, size)
          an array with the centered gaussian kernel
        """
        x = np.linspace(- (size // 2), size // 2)
        x /= np.sqrt(2)*sigma
        x2 = x**2
        kernel = np.exp(- x2[:, None] - x2[None, :])
        return kernel / kernel.sum()
    

    작은 커널 크기의 경우이 속도는 상당히 빠릅니다.

    참고 : 이렇게하면 허용되는 답변과 관련하여 시그마 매개 변수를보다 쉽게 ​​변경할 수 있습니다.

  5. ==============================

    5.linalg.norm은 축 매개 변수를 취합니다. 약간의 실험을 통해 모든 행 조합에 대한 표준을 계산할 수 있음을 발견했습니다.

    linalg.norm은 축 매개 변수를 취합니다. 약간의 실험을 통해 모든 행 조합에 대한 표준을 계산할 수 있음을 발견했습니다.

    np.linalg.norm(x[None,:,:]-x[:,None,:],axis=2)
    

    x를 모든 차이의 3d 배열로 확장하고 마지막 차원에서 표준을 취합니다.

    따라서 Gaussian에 축 매개 변수를 추가하여 코드에 적용 할 수 있습니다.

    def Gaussian(x,z,sigma,axis=None):
        return np.exp((-(np.linalg.norm(x-z, axis=axis)**2))/(2*sigma**2))
    
    x=np.arange(12).reshape(3,4)
    GaussianMatrix(x,1)
    

    생산하다

    array([[  1.00000000e+00,   1.26641655e-14,   2.57220937e-56],
           [  1.26641655e-14,   1.00000000e+00,   1.26641655e-14],
           [  2.57220937e-56,   1.26641655e-14,   1.00000000e+00]])
    

    어울리는:

    Gaussian(x[None,:,:],x[:,None,:],1,axis=2)
    
    array([[  1.00000000e+00,   1.26641655e-14,   2.57220937e-56],
           [  1.26641655e-14,   1.00000000e+00,   1.26641655e-14],
           [  2.57220937e-56,   1.26641655e-14,   1.00000000e+00]])
    
  6. ==============================

    6.FuzzyDuck의 대답을 개선하려고합니다. 나는이 접근법이 더 짧고 이해하기 쉽다고 생각한다. 여기에서는 signal.scipy.gaussian을 사용하여 2D 가우스 커널을 얻습니다.

    FuzzyDuck의 대답을 개선하려고합니다. 나는이 접근법이 더 짧고 이해하기 쉽다고 생각한다. 여기에서는 signal.scipy.gaussian을 사용하여 2D 가우스 커널을 얻습니다.

    import numpy as np
    from scipy import signal
    
    def gkern(kernlen=21, std=3):
        """Returns a 2D Gaussian kernel array."""
        gkern1d = signal.gaussian(kernlen, std=std).reshape(kernlen, 1)
        gkern2d = np.outer(gkern1d, gkern1d)
        return gkern2d
    

    matplotlib.pyplot을 사용하여 플로팅 :

    import matplotlib.pyplot as plt
    plt.imshow(gkern(21), interpolation='none')
    

  7. ==============================

    7.테디 하르 탕토의 대답을 토대로 자신의 1 차원 가우스 함수를 계산 한 다음 np.outer를 사용하여 2 차원을 계산할 수 있습니다. 매우 빠르고 효율적인 방법.

    테디 하르 탕토의 대답을 토대로 자신의 1 차원 가우스 함수를 계산 한 다음 np.outer를 사용하여 2 차원을 계산할 수 있습니다. 매우 빠르고 효율적인 방법.

    아래의 코드를 사용하여 모든 차원에 대해 다른 Sigmas를 사용할 수도 있습니다.

    import numpy as np
    def generate_gaussian_mask(shape, sigma, sigma_y=None):
        if sigma_y==None:
            sigma_y=sigma
        rows, cols = shape
    
        def get_gaussian_fct(size, sigma):
            fct_gaus_x = np.linspace(0,size,size)
            fct_gaus_x = fct_gaus_x-size/2
            fct_gaus_x = fct_gaus_x**2
            fct_gaus_x = fct_gaus_x/(2*sigma**2)
            fct_gaus_x = np.exp(-fct_gaus_x)
            return fct_gaus_x
    
        mask = np.outer(get_gaussian_fct(rows,sigma), get_gaussian_fct(cols,sigma_y))
        return mask
    
  8. ==============================

    8.나는 numpy만을 사용하여 시도했다. 여기 코드가있다.

    나는 numpy만을 사용하여 시도했다. 여기 코드가있다.

    def get_gauss_kernel(size=3,sigma=1):
        center=(int)(size/2)
        kernel=np.zeros((size,size))
        for i in range(size):
           for j in range(size):
              diff=np.sqrt((i-center)**2+(j-center)**2)
              kernel[i,j]=np.exp(-(diff**2)/2*sigma**2)
        return kernel/np.sum(kernel)
    

    다음 전화

    plt.imshow(get_gauss_kernel(5,1))
    

  9. from https://stackoverflow.com/questions/29731726/how-to-calculate-a-gaussian-kernel-matrix-efficiently-in-numpy by cc-by-sa and MIT license