2012-06-15 4 views
4

I는 2 차원의 입체 ndarray 예를 들면, 좌표 가지고NumPy와는 각각 ndarray 요소 위에 기능을 실행

[[[1704 1240] 
    [1745 1244] 
    [1972 1290] 
    [2129 1395] 
    [1989 1332]] 

[[1712 1246] 
    [1750 1246] 
    [1964 1286] 
    [2138 1399] 
    [1989 1333]] 

[[1721 1249] 
    [1756 1249] 
    [1955 1283] 
    [2145 1399] 
    [1990 1333]]] 

궁극적 인 목적은 주어진 지점에 가장 가까운 기점을 제거하는 것이다 ([1,989 1,332]) 5 좌표의 각 "그룹"으로부터. 내 생각은 비슷한 모양의 거리 배열을 생성 한 다음 argmin을 사용하여 제거 할 값의 인덱스를 결정하는 것이 었습니다. 그러나 적어도 NumPythonic 방식으로, ndarray의 모든 요소에 주어진 점까지의 거리를 계산하는 것과 같은 함수를 적용하는 방법에 대해서는 확실하지 않습니다.

답변

4

목록 함축은 매우 비효율적 방법 numpy 배열을 처리합니다. 거리 계산에 특히 적합하지 않습니다.

데이터와 포인트의 차이점을 찾으려면 data - point을 사용해보세요. 그런 다음 np.hypot을 사용하여 거리를 계산하거나 원하는 경우 사각형을 합계하여 제곱근을 취합니다.

계산을 위해 Nx2 배열을 만들면 조금 더 쉽습니다.

import numpy as np 

data = np.array([[[1704, 1240], 
        [1745, 1244], 
        [1972, 1290], 
        [2129, 1395], 
        [1989, 1332]], 

       [[1712, 1246], 
        [1750, 1246], 
        [1964, 1286], 
        [2138, 1399], 
        [1989, 1333]], 

       [[1721, 1249], 
        [1756, 1249], 
        [1955, 1283], 
        [2145, 1399], 
        [1990, 1333]]]) 

point = [1989, 1332] 

#-- Calculate distance ------------ 
# The reshape is to make it a single, Nx2 array to make calling `hypot` easier 
dist = data.reshape((-1,2)) - point 
dist = np.hypot(*dist.T) 

# We can then reshape it back to AxBx1 array, similar to the original shape 
dist = dist.reshape(data.shape[0], data.shape[1], 1) 
print dist 

이 수율 :

array([[[ 299.48121811], 
     [ 259.38388539], 
     [ 45.31004304], 
     [ 153.5219854 ], 
     [ 0.  ]], 

     [[ 290.04310025], 
     [ 254.0019685 ], 
     [ 52.35456045], 
     [ 163.37074401], 
     [ 1.  ]], 

     [[ 280.55837182], 
     [ 247.34186868], 
     [ 59.6405902 ], 
     [ 169.77926846], 
     [ 1.41421356]]]) 

지금, 가장 가까운 요소를 제거하는 것은 단순히 가장 가까운 요소를 얻기보다 약간 어렵

기본적으로, 당신은 이런 식으로 뭔가를 할 수 있습니다.

numpy를 사용하면 부울 인덱스를 사용하여이를 쉽게 처리 할 수 ​​있습니다.

그러나 축 정렬에 대해 조금 걱정할 필요가 있습니다.

키는 축 번호가 인 축 ( 축)을 따라 "브로드 캐스팅"하는 것을 이해하는 것이 중요합니다. 이 경우 중간 축을 따라 브로드 캐스트를 원합니다.

또한 -1은 축 크기의 자리 표시 자로 사용할 수 있습니다. Numpy는 축 크기로 -1을 입력하면 허용되는 크기를 계산합니다.

#-- Remove closest point --------------------- 
mask = np.squeeze(dist) != dist.min(axis=1) 
filtered = data[mask] 

# Once again, let's reshape things back to the original shape... 
filtered = filtered.reshape(data.shape[0], -1, data.shape[2]) 

당신은 한 줄, 난 그냥 가독성을 위해 그것을 분해하고있어 것을 만들 수 : 우리가 조금 같을 것이다해야 할 것입니다 무엇

. 중요한 점은 dist != something이 부울 배열을 생성 한 다음 원래 배열을 인덱싱하는 데 사용할 수 있다는 것입니다.

그래서, 모두 함께 퍼팅 :

import numpy as np 

data = np.array([[[1704, 1240], 
        [1745, 1244], 
        [1972, 1290], 
        [2129, 1395], 
        [1989, 1332]], 

       [[1712, 1246], 
        [1750, 1246], 
        [1964, 1286], 
        [2138, 1399], 
        [1989, 1333]], 

       [[1721, 1249], 
        [1756, 1249], 
        [1955, 1283], 
        [2145, 1399], 
        [1990, 1333]]]) 

point = [1989, 1332] 

#-- Calculate distance ------------ 
# The reshape is to make it a single, Nx2 array to make calling `hypot` easier 
dist = data.reshape((-1,2)) - point 
dist = np.hypot(*dist.T) 

# We can then reshape it back to AxBx1 array, similar to the original shape 
dist = dist.reshape(data.shape[0], data.shape[1], 1) 

#-- Remove closest point --------------------- 
mask = np.squeeze(dist) != dist.min(axis=1) 
filtered = data[mask] 

# Once again, let's reshape things back to the original shape... 
filtered = filtered.reshape(data.shape[0], -1, data.shape[2]) 

print filtered 

수익률 : 두 개 이상의 지점이 똑같이 가까운 경우

array([[[1704, 1240], 
     [1745, 1244], 
     [1972, 1290], 
     [2129, 1395]], 

     [[1712, 1246], 
     [1750, 1246], 
     [1964, 1286], 
     [2138, 1399]], 

     [[1721, 1249], 
     [1756, 1249], 
     [1955, 1283], 
     [2145, 1399]]]) 

를 보조 노트에,이 작동하지 않습니다. Numpy 배열은 각 차원에서 동일한 수의 요소를 가져야하므로이 경우 그룹화를 다시해야합니다.

+0

아, 게시하기 전에 어떻게 든 보지 못했습니다. 나는'apply_along_axis'를 사용하는 것을 생각했지만, 테스트 해봤는데 훨씬 빠릅니다. – senderle

+0

'apply_along_axis'는 메모리를 적게 사용해야하므로 두 방법 모두 여전히 유용합니다! –

+0

감사! 매우 간결하면서도 유익합니다. 너무 빨리. – OneTrickyPony

0

가이 작업을 수행하는 여러 가지 방법이지만, 여기에 하나를 사용하여 지능형리스트입니다 :

거리 기능 :

In [35]: from numpy.linalg import norm 

In [36]: dist = lambda x,y:norm(x-y) 

입력 데이터 :

In [39]: GivenMatrix = scipy.rand(3, 5, 2) 

In [40]: GivenMatrix 
Out[40]: 
array([[[ 0.83798666, 0.90294439], 
     [ 0.8706959 , 0.88397176], 
     [ 0.91879085, 0.93512921], 
     [ 0.15989245, 0.57311869], 
     [ 0.82896003, 0.53589968]], 

     [[ 0.0207089 , 0.9521768 ], 
     [ 0.94523963, 0.31079109], 
     [ 0.41929482, 0.88559614], 
     [ 0.87885236, 0.45227422], 
     [ 0.58365369, 0.62095507]], 

     [[ 0.14757177, 0.86101539], 
     [ 0.58081214, 0.12632764], 
     [ 0.89958321, 0.73660852], 
     [ 0.3408943 , 0.45420989], 
     [ 0.42656333, 0.42770216]]]) 

In [41]: q = scipy.rand(2) 

In [42]: q 
Out[42]: array([ 0.03280889, 0.71057403]) 

계산 출력 거리 :

In [44]: distances = [[dist(x, q) for x in SubMatrix] 
         for SubMatrix in GivenMatrix] 

In [45]: distances 
Out[45]: 
[[0.82783910695733931, 
    0.85564093542511577, 
    0.91399620574915652, 
    0.18720096539588818, 
    0.81508758596405939], 
[0.24190557184498068, 
    0.99617079746515047, 
    0.42426891258164884, 
    0.88459501973012633, 
    0.55808740166908177], 
[0.18921712490174292, 
    0.80103146210692744, 
    0.86716521557255788, 
    0.40079819635686459, 
    0.48482888965287363]] 

각 행렬에 대한 결과 순위 :

In [46]: scipy.argsort(distances) 
Out[46]: 
array([[3, 4, 0, 1, 2], 
     [0, 2, 4, 3, 1], 
     [0, 3, 4, 1, 2]]) 

이 삭제에 관해서는, 내가 개인적으로 가장 쉬운 방법이라고 생각 다음 del를 사용하여 listGivenMatrix를 변환 :

>>> GivenList = GivenMatrix.tolist() 

>>> del GivenList[1][2] # delete third row from the second 5-by-2 submatrix 
1

질문을 올바르게 이해하면 apply_along_axis을 찾고 있다고 생각합니다.

>>> a - numpy.array([1989, 1332]) 
array([[[-285, -92], 
     [-244, -88], 
     [ -17, -42], 
     [ 140, 63], 
     [ 0, 0]], 

     [[-277, -86], 
     [-239, -86], 
     [ -25, -46], 
     [ 149, 67], 
     [ 0, 1]], 

     [[-268, -83], 
     [-233, -83], 
     [ -34, -49], 
     [ 156, 67], 
     [ 1, 1]]]) 

그런 다음 우리가 그것에 numpy.linalg.norm을 적용 할 수 있습니다 : 마지막으로

>>> dist = a - numpy.array([1989, 1332]) 
>>> numpy.apply_along_axis(numpy.linalg.norm, 2, dist) 
array([[ 299.48121811, 259.38388539, 45.31004304, 
     153.5219854 , 0.  ], 
     [ 290.04310025, 254.0019685 , 52.35456045, 
     163.37074401, 1.  ], 
     [ 280.55837182, 247.34186868, 59.6405902 , 
     169.77926846, 1.41421356]]) 

, 일부 부울 마스크 속임수, 함께 내장 된 방송 numpy 년대를 사용하여, 우리는 단순히 배열에서 포인트를 뺄 수 있습니다 몇 가지 reshape 전화 :

>>> a[normed != normed.min(axis=1).reshape((-1, 1))].reshape((3, 4, 2)) 
array([[[1704, 1240], 
     [1745, 1244], 
     [1972, 1290], 
     [2129, 1395]], 

     [[1712, 1246], 
     [1750, 1246], 
     [1964, 1286], 
     [2138, 1399]], 

     [[1721, 1249], 
     [1756, 1249], 
     [1955, 1283], 
     [2145, 1399]]]) 

조 킹턴의 대답은 빠릅니다. 오 잘. 나는 이것을 후세에 남겨 둘 것이다.

def joes(data, point): 
    dist = data.reshape((-1,2)) - point 
    dist = np.hypot(*dist.T) 
    dist = dist.reshape(data.shape[0], data.shape[1], 1) 
    mask = np.squeeze(dist) != dist.min(axis=1) 
    return data[mask].reshape((3, 4, 2)) 

def mine(a, point): 
    dist = a - point 
    normed = numpy.apply_along_axis(numpy.linalg.norm, 2, dist) 
    return a[normed != normed.min(axis=1).reshape((-1, 1))].reshape((3, 4, 2)) 

>>> %timeit mine(data, point) 
1000 loops, best of 3: 586 us per loop 
>>> %timeit joes(data, point) 
10000 loops, best of 3: 48.9 us per loop 
관련 문제