유클리드 거리는 NumPy로 어떻게 계산될 수 있나요?
3D 공간에는 두 가지 포인트가 있습니다.
a = (ax, ay, az)
b = (bx, by, bz)
이들 사이의 거리를 계산하고 싶습니다.
dist = sqrt((ax-bx)^2 + (ay-by)^2 + (az-bz)^2)
NumPy로 어떻게 해야 하나요?다음과 같은 것이 있습니다.
import numpy
a = numpy.array((ax, ay, az))
b = numpy.array((bx, by, bz))
사용방법:
dist = numpy.linalg.norm(a-b)
이것은 유클리드 거리가 l2 노름이기 때문에, 그리고 에 있는 매개변수의 디폴트 값이기 때문에 작동합니다.numpy.linalg.norm
자세한 내용은 데이터 마이닝의 개요를 참조해 주십시오.
사용방법:
from scipy.spatial import distance
a = (1, 2, 3)
b = (4, 5, 6)
dst = distance.euclidean(a, b)
한 번에 여러 거리를 계산하는 데 관심이 있는 사람들을 위해 성능표(작은 프로젝트)를 사용하여 약간의 비교를 해봤습니다.
이 차원이 입니다.(3, n)
(C-internal-internal-internal-internal)된 첫, 1을 가 되지 .sqrt-sum
axis=0
,linalg.norm
axis=0
「」
a_min_b = a - b
numpy.sqrt(numpy.einsum('ij,ij->j', a_min_b, a_min_b))
이는 근소한 차이로 가장 빠른 변형입니다.(실제로 한 줄에도 해당됩니다.)
축에 요약하는 입니다.axis=1
모두 상당히 느립니다.
플롯을 재현하는 코드:
import numpy
import perfplot
from scipy.spatial import distance
def linalg_norm(data):
a, b = data[0]
return numpy.linalg.norm(a - b, axis=1)
def linalg_norm_T(data):
a, b = data[1]
return numpy.linalg.norm(a - b, axis=0)
def sqrt_sum(data):
a, b = data[0]
return numpy.sqrt(numpy.sum((a - b) ** 2, axis=1))
def sqrt_sum_T(data):
a, b = data[1]
return numpy.sqrt(numpy.sum((a - b) ** 2, axis=0))
def scipy_distance(data):
a, b = data[0]
return list(map(distance.euclidean, a, b))
def sqrt_einsum(data):
a, b = data[0]
a_min_b = a - b
return numpy.sqrt(numpy.einsum("ij,ij->i", a_min_b, a_min_b))
def sqrt_einsum_T(data):
a, b = data[1]
a_min_b = a - b
return numpy.sqrt(numpy.einsum("ij,ij->j", a_min_b, a_min_b))
def setup(n):
a = numpy.random.rand(n, 3)
b = numpy.random.rand(n, 3)
out0 = numpy.array([a, b])
out1 = numpy.array([a.T, b.T])
return out0, out1
b = perfplot.bench(
setup=setup,
n_range=[2 ** k for k in range(22)],
kernels=[
linalg_norm,
linalg_norm_T,
scipy_distance,
sqrt_sum,
sqrt_sum_T,
sqrt_einsum,
sqrt_einsum_T,
],
xlabel="len(x), len(y)",
)
b.save("norm.png")
다양한 퍼포먼스 노트와 함께 심플한 답변에 대해 자세히 설명하겠습니다.np.linalg.norm은 아마 필요한 것보다 더 많은 것을 할 수 있을 것입니다.
dist = numpy.linalg.norm(a-b)
- 이 , 이, 이, 이, 이, 이, (의 하도록 설계되어 .pA
sP
:
sP = set(points)
pA = point
distances = np.linalg.norm(sP - pA, ord=2, axis=1.) # 'distances' is a list
몇 가지 점에 주의해 주십시오.
- Python 함수 호출은 비싸다.
- [통상] Python은 이름 조회를 캐시하지 않습니다.
그렇게
def distance(pointA, pointB):
dist = np.linalg.norm(pointA - pointB)
return dist
보이는 것만큼 순진하지 않아요
>>> dis.dis(distance)
2 0 LOAD_GLOBAL 0 (np)
2 LOAD_ATTR 1 (linalg)
4 LOAD_ATTR 2 (norm)
6 LOAD_FAST 0 (pointA)
8 LOAD_FAST 1 (pointB)
10 BINARY_SUBTRACT
12 CALL_FUNCTION 1
14 STORE_FAST 2 (dist)
3 16 LOAD_FAST 2 (dist)
18 RETURN_VALUE
우선 호출할 때마다 "np"에 대한 글로벌 룩업, "linalg"에 대한 스코프 룩업, "norm"에 대한 스코프 룩업을 수행해야 하며 단순히 함수를 호출하는 오버헤드는 수십 개의 python 명령과 동일할 수 있습니다.
마지막으로 결과를 저장하고 다시 로드하여 반환하기 위해 두 번의 작업을 낭비했습니다.
개선의 첫 번째 경로: 검색 속도를 높이고 스토어를 건너뜁니다.
def distance(pointA, pointB, _norm=np.linalg.norm):
return _norm(pointA - pointB)
한층 더 합리화됩니다.
>>> dis.dis(distance)
2 0 LOAD_FAST 2 (_norm)
2 LOAD_FAST 0 (pointA)
4 LOAD_FAST 1 (pointB)
6 BINARY_SUBTRACT
8 CALL_FUNCTION 1
10 RETURN_VALUE
그러나 함수 호출 오버헤드는 여전히 일부 작업에 해당합니다.또한 벤치마크를 통해 직접 계산을 수행하는 것이 더 나은지 여부를 판단할 수 있습니다.
def distance(pointA, pointB):
return (
((pointA.x - pointB.x) ** 2) +
((pointA.y - pointB.y) ** 2) +
((pointA.z - pointB.z) ** 2)
) ** 0.5 # fast sqrt
, 「」가 됩니다.**0.5
math.sqrt
마일리지가 다를 수 있습니다.
**** 상세 퍼포먼스 노트
왜 거리를 계산해요?그걸 전시하는 게 유일한 목적이라면
print("The target is %.2fm away" % (distance(a, b)))
앞으로 나아가다하지만 거리 비교, 거리 확인 등을 할 경우 유용한 성능 관찰을 추가하고 싶습니다.
거리별로 정렬하거나 범위 제약을 충족하는 항목으로 목록을 추출하는 두 가지 경우를 살펴보겠습니다.
# Ultra naive implementations. Hold onto your hat.
def sort_things_by_distance(origin, things):
return things.sort(key=lambda thing: distance(origin, thing))
def in_range(origin, range, things):
things_in_range = []
for thing in things:
if distance(origin, thing) <= range:
things_in_range.append(thing)
우리가 기억해야 할 첫 번째 것은 거리를 계산하기 위해 피타고라스를 사용하고 있다는 것이다.dist = sqrt(x^2 + y^2 + z^2)
sqrt
101 네. § 101:
dist = root ( x^2 + y^2 + z^2 )
:.
dist^2 = x^2 + y^2 + z^2
and
sq(N) < sq(M) iff M > N
and
sq(N) > sq(M) iff N > M
and
sq(N) = sq(M) iff N == M
즉, 실제로 X^2가 아닌 X 단위로 거리를 요구할 때까지 계산의 가장 어려운 부분을 제거할 수 있습니다.
# Still naive, but much faster.
def distance_sq(left, right):
""" Returns the square of the distance between left and right. """
return (
((left.x - right.x) ** 2) +
((left.y - right.y) ** 2) +
((left.z - right.z) ** 2)
)
def sort_things_by_distance(origin, things):
return things.sort(key=lambda thing: distance_sq(origin, thing))
def in_range(origin, range, things):
things_in_range = []
# Remember that sqrt(N)**2 == N, so if we square
# range, we don't need to root the distances.
range_sq = range**2
for thing in things:
if distance_sq(origin, thing) <= range_sq:
things_in_range.append(thing)
좋아요, 두 기능 모두 값비싼 제곱근은 더 이상 할 수 없어요.그게 훨씬 빠를 거야.또한 제너레이터로 변환하여 in_range를 개선할 수 있습니다.
def in_range(origin, range, things):
range_sq = range**2
yield from (thing for thing in things
if distance_sq(origin, thing) <= range_sq)
다음과 같은 작업을 수행하는 경우 특히 유용합니다.
if any(in_range(origin, max_dist, things)):
...
하지만 다음 번에 할 일이 거리를 필요로 한다면
for nearby in in_range(origin, walking_distance, hotdog_stands):
print("%s %.2fm" % (nearby.name, distance(origin, nearby)))
튜플 산출 고려:
def in_range_with_dist_sq(origin, range, things):
range_sq = range**2
for thing in things:
dist_sq = distance_sq(origin, thing)
if dist_sq <= range_sq: yield (thing, dist_sq)
이것은 범위 체크를 체인할 수 있는 경우(거리를 다시 계산할 필요가 없기 때문에 X에 가깝고 Y의 Nm 이내에 있는 것을 찾을 수 있음) 특히 유용합니다.
정말요?things
그 중 상당수는 고려할 가치가 없을 것으로 예상되나?
실제로는 매우 간단한 최적화가 있습니다.
def in_range_all_the_things(origin, range, things):
range_sq = range**2
for thing in things:
dist_sq = (origin.x - thing.x) ** 2
if dist_sq <= range_sq:
dist_sq += (origin.y - thing.y) ** 2
if dist_sq <= range_sq:
dist_sq += (origin.z - thing.z) ** 2
if dist_sq <= range_sq:
yield thing
이것이 유용한지는 '물건'의 크기에 따라 달라집니다.
def in_range_all_the_things(origin, range, things):
range_sq = range**2
if len(things) >= 4096:
for thing in things:
dist_sq = (origin.x - thing.x) ** 2
if dist_sq <= range_sq:
dist_sq += (origin.y - thing.y) ** 2
if dist_sq <= range_sq:
dist_sq += (origin.z - thing.z) ** 2
if dist_sq <= range_sq:
yield thing
elif len(things) > 32:
for things in things:
dist_sq = (origin.x - thing.x) ** 2
if dist_sq <= range_sq:
dist_sq += (origin.y - thing.y) ** 2 + (origin.z - thing.z) ** 2
if dist_sq <= range_sq:
yield thing
else:
... just calculate distance and range-check it ...
다시 dist_sq의 산출을 검토합니다.다음으로 핫도그의 예를 제시하겠습니다.
# Chaining generators
info = in_range_with_dist_sq(origin, walking_distance, hotdog_stands)
info = (stand, dist_sq**0.5 for stand, dist_sq in info)
for stand, dist in info:
print("%s %.2fm" % (stand, dist))
이 문제 해결 방법의 또 다른 예는 다음과 같습니다.
def dist(x,y):
return numpy.sqrt(numpy.sum((x-y)**2))
a = numpy.array((xa,ya,za))
b = numpy.array((xb,yb,zb))
dist_a_b = dist(a,b)
★★★★★Python 3.8
모듈은 두 점 사이의 유클리드 거리(튜플 또는 좌표 목록으로 지정)를 반환하는 함수를 직접 제공합니다.
from math import dist
dist((1, 2, 6), (-2, 3, 2)) # 5.0990195135927845
목록을 사용하는 경우:
dist([1, 2, 6], [-2, 3, 2]) # 5.0990195135927845
다음과 같이 할 수 있습니다.얼마나 빠른지는 모르겠지만, NumPy를 사용하지 않습니다.
from math import sqrt
a = (1, 2, 3) # Data point 1
b = (4, 5, 6) # Data point 2
print sqrt(sum( (a - b)**2 for a, b in zip(a, b)))
멋진 원라이너:
dist = numpy.linalg.norm(a-b)
하지만 속도가 걱정된다면 당신의 기계로 실험해 볼 것을 권합니다.나는 그것을 발견하였습니다.math
이 library library librarysqrt
**
네모난 연산자가 원라이너 NumPy 솔루션보다 훨씬 빠릅니다.
이 간단한 프로그램을 사용하여 테스트를 실행했습니다.
#!/usr/bin/python
import math
import numpy
from random import uniform
def fastest_calc_dist(p1,p2):
return math.sqrt((p2[0] - p1[0]) ** 2 +
(p2[1] - p1[1]) ** 2 +
(p2[2] - p1[2]) ** 2)
def math_calc_dist(p1,p2):
return math.sqrt(math.pow((p2[0] - p1[0]), 2) +
math.pow((p2[1] - p1[1]), 2) +
math.pow((p2[2] - p1[2]), 2))
def numpy_calc_dist(p1,p2):
return numpy.linalg.norm(numpy.array(p1)-numpy.array(p2))
TOTAL_LOCATIONS = 1000
p1 = dict()
p2 = dict()
for i in range(0, TOTAL_LOCATIONS):
p1[i] = (uniform(0,1000),uniform(0,1000),uniform(0,1000))
p2[i] = (uniform(0,1000),uniform(0,1000),uniform(0,1000))
total_dist = 0
for i in range(0, TOTAL_LOCATIONS):
for j in range(0, TOTAL_LOCATIONS):
dist = fastest_calc_dist(p1[i], p2[j]) #change this line for testing
total_dist += dist
print total_dist
★★★★★★★★★★★★★★★★★★★★★★.math_calc_dist
빨리 달리다numpy_calc_dist
1대 23 23.5초.
를 얻기 fastest_calc_dist
★★★★★★★★★★★★★★★★★」math_calc_dist
했다TOTAL_LOCATIONS
1994로 합니다. ★★★★★★★★★★★★★★★.fastest_calc_dist
걸리는 동안 50초 정도 걸립니다.math_calc_dist
60달러입니다.
'어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어, 어.numpy.sqrt
★★★★★★★★★★★★★★★★★」numpy.square
다 math
이치노
내 테스트는 Python 2.6.6으로 실행되었다.
matplotlib.mlab에 'dist' 함수가 있는데, 충분히 편리하지 않은 것 같아요.
참고용으로 여기에 올립니다.
import numpy as np
import matplotlib as plt
a = np.array([1, 2, 3])
b = np.array([2, 3, 4])
# Distance between a and b
dis = plt.mlab.dist(a, b)
벡터를 뺀 다음 내적만 빼면 됩니다.
당신의 예를 따라,
a = numpy.array((xa, ya, za))
b = numpy.array((xb, yb, zb))
tmp = a - b
sum_squared = numpy.dot(tmp.T, tmp)
result = numpy.sqrt(sum_squared)
는 아요를 좋아한다.np.dot
(음악) :
a = numpy.array((xa,ya,za))
b = numpy.array((xb,yb,zb))
distance = (np.dot(a-b,a-b))**.5
Python 3.8 이후
3.8 Python 3.8 이후math
에는 "Module"이라는 함수가 포함되어 있습니다.math.dist()
.
https://docs.python.org/3.8/library/math.html#math.dist 를 참조해 주세요.
math.dist(p1, p2)
각각 좌표의 시퀀스(또는 반복 가능)로 주어진 두 점 p1과 p2 사이의 유클리드 거리를 반환합니다.
import math
print( math.dist( (0,0), (1,1) )) # sqrt(2) -> 1.4142
print( math.dist( (0,0,0), (1,1,1) )) # sqrt(3) -> 1.7321
Python 3.8에서는 매우 간단합니다.
https://docs.python.org/3/library/math.html#math.dist
math.dist(p, q)
각각 좌표의 시퀀스(또는 반복 가능)로 주어진 두 점 p와 q 사이의 유클리드 거리를 반환합니다.두 점은 치수가 같아야 합니다.
대략 다음과 같습니다.
sqrt(sum((px - qx) ** 2.0 for px, qx in zip(p, q)))
있다a
★★★★★★★★★★★★★★★★★」b
정의한 대로, 다음의 것도 사용할 수 있습니다.
distance = np.sqrt(np.sum((a-b)**2))
다음은 Python에서 목록으로 표현되는 두 개의 포인트가 주어진 Python에서 유클리드 거리에 대한 간결한 코드입니다.
def distance(v1,v2):
return sum([(x-y)**2 for (x,y) in zip(v1,v2)])**(0.5)
import math
dist = math.hypot(math.hypot(xa-xb, ya-yb), za-zb)
다차원 공간에 대한 유클리드 거리 계산:
import math
x = [1, 2, 6]
y = [-2, 3, 2]
dist = math.sqrt(sum([(xi-yi)**2 for xi,yi in zip(x, y)]))
5.0990195135927845
import numpy as np
from scipy.spatial import distance
input_arr = np.array([[0,3,0],[2,0,0],[0,1,3],[0,1,2],[-1,0,1],[1,1,1]])
test_case = np.array([0,0,0])
dst=[]
for i in range(0,6):
temp = distance.euclidean(test_case,input_arr[i])
dst.append(temp)
print(dst)
공식을 쉽게 사용할 수 있습니다.
distance = np.sqrt(np.sum(np.square(a-b)))
이것은 실제로 거리를 계산하기 위해 피타고라스의 정리를 사용하는 것 이상도 이하도 아니다. δx, δy, δz의 제곱을 더하고 그 결과를 루팅한다.
import numpy as np
# any two python array as two points
a = [0, 0]
b = [3, 4]
먼저 목록을 numpy 배열로 변경하고 다음과 같이 수행합니다.print(np.linalg.norm(np.array(a) - np.array(b)))
두 번째 : . python 목목음음음음음음음음음음음 음음음음음음 음음음음음 . 。print(np.linalg.norm(np.subtract(a,b)))
다른 응답은 부동소수점 번호에 대해 작동하지만 오버플로우 및 언더플로우의 영향을 받는 정수 d타입에 대해서는 거리를 올바르게 계산하지 않습니다., 이 경우에도 주의해 주십시오.scipy.distance.euclidean
에는 다음 문제가 있습니다.
>>> a1 = np.array([1], dtype='uint8')
>>> a2 = np.array([2], dtype='uint8')
>>> a1 - a2
array([255], dtype=uint8)
>>> np.linalg.norm(a1 - a2)
255.0
>>> from scipy.spatial import distance
>>> distance.euclidean(a1, a2)
255.0
이는 많은 이미지 라이브러리가 dtype="uint8"을 사용하여 이미지를 ndarray로 표시하기 때문에 일반적입니다., 매우 어두운 픽셀(에 색상이 있다고 )로 (모든 픽셀에 색상이 있습니다).#000001
흑색 이미지)에 대해 #000000
로 수 .x-y
로로 consist consist consist consist consist로 255
서로 매우 멀리 떨어져 있는 두 개의 이미지로 등록됩니다.부호 없는 정수 유형(예: uint8)의 경우 다음과 같이 numpy 단위의 거리를 안전하게 계산할 수 있습니다.
np.linalg.norm(np.maximum(x, y) - np.minimum(x, y))
부호 있는 정수 유형의 경우 먼저 플로트에 캐스트할 수 있습니다.
np.linalg.norm(x.astype("float") - y.astype("float"))
특히 영상 데이터의 경우 opencv의 표준 방법을 사용할 수 있습니다.
import cv2
cv2.norm(x, y, cv2.NORM_L2)
먼저 두 행렬의 차이를 찾아라.그런 다음 numpy의 곱셈 명령을 사용하여 요소별 곱셈을 적용합니다.그런 다음 요소별 합계를 구합니다.마지막으로, 합계의 제곱근을 구하세요.
def findEuclideanDistance(a, b):
euclidean_distance = a - b
euclidean_distance = np.sum(np.multiply(euclidean_distance, euclidean_distance))
euclidean_distance = np.sqrt(euclidean_distance)
return euclidean_distance
NumPy 또는 일반적인 Python을 사용하는 가장 좋은 방법은 무엇입니까?다음과 같은 것이 있습니다.
가장 안전하고 빠른 방법이겠죠
나는 언더플로우 및 오버플로우 가능성을 위한 신뢰할 수 있는 결과를 위해 저가의 사용을 제안합니다 sqroot 계산기를 쓰는 것에 비해 매우 적습니다.
vs 바닐라 ".hypot, np.hypot vs "를 해 주세요.np.sqrt(np.sum((np.array([i, j, k])) ** 2, axis=1))
i, j, k = 1e+200, 1e+200, 1e+200
math.hypot(i, j, k)
# 1.7320508075688773e+200
np.sqrt(np.sum((np.array([i, j, k])) ** 2))
# RuntimeWarning: overflow encountered in square
빠른 수학.하이팟이 더 좋아 보인다.
%%timeit
math.hypot(i, j, k)
# 100 ns ± 1.05 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
%%timeit
np.sqrt(np.sum((np.array([i, j, k])) ** 2))
# 6.41 µs ± 33.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
언더플로우
i, j = 1e-200, 1e-200
np.sqrt(i**2+j**2)
# 0.0
오버플로
i, j = 1e+200, 1e+200
np.sqrt(i**2+j**2)
# inf
언더플로우 없음
i, j = 1e-200, 1e-200
np.hypot(i, j)
# 1.414213562373095e-200
오버플로 없음
i, j = 1e+200, 1e+200
np.hypot(i, j)
# 1.414213562373095e+200
언급URL : https://stackoverflow.com/questions/1401712/how-can-the-euclidean-distance-be-calculated-with-numpy
'programing' 카테고리의 다른 글
뷰를 사용하여 현재 Laravel 버전을 php로 에코하려면 어떻게 해야 합니까? (0) | 2022.11.05 |
---|---|
.vue 파일에서 NPM 패키지를 작성하는 방법 (0) | 2022.11.05 |
Angular 2 옵션루트 파라미터 (0) | 2022.11.05 |
ES6(ECMAScript 6)에 변수 없이 x회 루프하는 메커니즘이 있습니까? (0) | 2022.10.27 |
Mixin 렌더 함수 구성 (0) | 2022.10.27 |