HOWTO · NumPy
Python에서 유클리드 거리 계산
이 튜토리얼은 파이썬에서 유클리드 거리를 계산하는 방법을 보여줍니다.
이 페이지의 내용
같은 수의 좌표를 가진 점을 나타내는 두 NumPy 배열의 유클리드 거리는 np.linalg.norm(point_a - point_b)로 계산합니다. 뺄셈이 좌표 차이를 만들고 벡터의 L2 노름이 그 차이를 하나의 음이 아닌 거리로 줄입니다.
유클리드 거리 공식을 이해하기
점 (a=(a_1,\ldots,a_n))와 (b=(b_1,\ldots,b_n))의 유클리드 거리는 좌표 차이 제곱의 합에 대한 제곱근입니다:
NumPy에서 np.linalg.norm(a - b)는 이 정의를 직접 나타냅니다. 일차원 차이 배열에 ord 인수를 지정하지 않으면 np.linalg.norm은 2-노름을 계산합니다. 뺄셈이 의도한 의미를 갖도록 두 입력은 호환되는 차원의 점을 설명해야 합니다.
입력 좌표 준비하기
좌표 위치는 같은 축을 같은 순서로 설명해야 합니다. 한 점의 첫 좌표를 다른 점의 첫 좌표와 비교하는 식입니다. 점 하나는 (coordinates,) 형태의 일차원 배열로 나타냅니다. 예를 들어 (3,) 형태의 배열 두 개는 같은 3차원 좌표계의 두 점을 나타내며, 독립된 거리 세 개를 뜻하지는 않습니다.
튜플과 리스트는 뺄셈 전에 np.asarray(values, dtype=float)로 변환할 수 있습니다. 부동 소수점 형식은 정수나 소수 좌표를 받고 한 좌표가 대응 좌표보다 작을 때 부호 없는 정수의 래핑을 피합니다. 입력이 이미 적절한 부동 소수점 NumPy 배열이면 변환은 필요 없습니다. 형태를 맞추기 위해 임의의 다차원 데이터를 평탄화하지 마세요. 입력 구조 오류를 고치기보다 숨길 수 있습니다.
아래 예제는 Python 3.14.7, NumPy 2.5.3 및 SciPy 1.18.1에서 실행했습니다. 제시한 API는 확립된 인터페이스이지만 애플리케이션은 지원하는 Python 환경과 호환되는 버전을 사용해야 합니다. SciPy 메서드나 쌍별 거리 도구를 사용하지 않는다면 SciPy는 선택 사항입니다.
두 점 사이의 거리 계산하기
다음 검증 예제는 권장 노름 표현식, 명시적 공식, 내적 공식, 표준 라이브러리의 math.dist, 그리고 SciPy의 scipy.spatial.distance.euclidean를 비교합니다. 다섯 계산은 이 점 쌍에서 같은 결과를 냅니다.
"""Verify equivalent Euclidean-distance APIs for one pair of points."""
import math
import numpy as np
from scipy.spatial import distance
point_a = np.array([1.0, 2.0, 3.0])
point_b = np.array([4.0, 5.0, 6.0])
print(f"np.linalg.norm: {np.linalg.norm(point_a - point_b)}")
print(f"formula: {np.sqrt(np.sum((point_a - point_b) ** 2))}")
delta = point_a - point_b
print(f"dot product: {np.sqrt(np.dot(delta, delta))}")
print(f"math.dist: {math.dist(point_a, point_b)}")
print(f"distance.euclidean: {distance.euclidean(point_a, point_b)}")
np.linalg.norm: 5.196152422706632
formula: 5.196152422706632
dot product: 5.196152422706632
math.dist: 5.196152422706632
distance.euclidean: 5.196152422706632
명시적 공식은 개념적으로 NumPy의 요소별 제곱 뒤에 합계와 제곱근을 사용합니다. 예제의 지수 형태는 전체 계산을 하나의 식에 유지합니다. np.dot(delta, delta)가 대응하는 차이를 곱해 더하므로 내적 변형도 같은 제곱합을 계산합니다.
점이 이미 배열이거나 더 큰 NumPy 계산의 일부라면 np.linalg.norm을 사용하세요. 축약 과정을 풀어 쓰지 않고도 벡터 연산을 명확히 전달합니다.
axis=1로 행별 거리 계산하기
2차원 배열의 행으로 저장된 여러 점에는 기준점 하나를 빼고 axis=1을 설정합니다. NumPy는 기준 배열을 행 전체로 브로드캐스트하고, axis=1은 np.linalg.norm에 전체 행렬의 노름 하나 대신 행마다 노름 하나를 반환하도록 지시합니다.
"""Verify row-wise distances from several points to one reference point."""
import numpy as np
points = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
reference = np.array([1.0, 2.0, 3.0])
print(np.linalg.norm(points - reference, axis=1))
[0. 5.19615242]
첫 행은 기준점과 같으므로 거리가 0입니다. 두 번째 결과는 한 쌍 예제에서 계산한 거리입니다. 이 패턴은 일대다 거리를 다룹니다. 두 컬렉션의 모든 쌍별 거리에는 메모리 사용을 고려하지 않은 큰 브로드캐스트 중간 배열 대신 scipy.spatial.distance.cdist 같은 전용 루틴을 사용하세요.
NumPy, math.dist, SciPy 중 선택하기
가장 좋은 방법은 보편적인 속도 주장보다 주변 코드에 따라 달라집니다:
- NumPy 배열, 벡터화된 작업 흐름,
axis를 사용한 행별 계산에는np.linalg.norm(a - b)를 사용합니다. - 다른 곳에서 NumPy가 필요하지 않은 일반 Python 좌표 이터러블 한 쌍에는
math.dist(a, b)를 사용합니다. - SciPy가 이미 의존성이거나 계산이 SciPy의 더 넓은 거리 도구에 속하면
scipy.spatial.distance.euclidean(a, b)를 사용합니다. - 기초 계산을 가르치거나 검토하거나 조정할 때는 명시적 제곱합 공식이나 내적을 사용합니다. 이들은 노름 표현식보다 결과를 더 유클리드적으로 만들지는 않습니다.
Python 리스트는 요소별 뺄셈을 지원하지 않으므로 NumPy 뺄셈 전에 np.asarray(..., dtype=float)로 변환하는 것이 유용합니다. math.dist는 길이가 같은 좌표 이터러블을 직접 받고, NumPy와 SciPy 선택지는 각각의 패키지가 설치되어 있어야 합니다.
호환되지 않는 형태와 숫자 데이터 형식 다루기
개별 점 두 개는 같은 수의 좌표를 가져야 합니다. 호환되지 않는 일차원 형태는 함께 브로드캐스트할 수 없으므로 NumPy는 거리를 계산하기 전에 ValueError를 발생시킵니다.
"""Capture the diagnostic for points with incompatible dimensions."""
import numpy as np
point_a = np.array([1.0, 2.0])
point_b = np.array([3.0, 4.0, 5.0])
try:
np.linalg.norm(point_a - point_b)
except ValueError as error:
print(f"ValueError: {error}".rstrip())
ValueError: operands could not be broadcast together with shapes (2,) (3,)
차원이 사용자 입력이나 외부 데이터에서 오면 뺄셈 전에 형태를 확인하세요. 행별 거리에서 (rows, coordinates) 형태의 점 배열은 (coordinates,) 형태의 기준점과 호환됩니다. 다른 형태는 의도하지 않게 브로드캐스트되거나 실패할 수 있습니다.
또한 뺄셈 전에 부호 없는 정수 좌표를 부호 있는 형식이나 부동 소수점 형식으로 변환하세요. 부호 없는 뺄셈은 음의 좌표 차이를 나타내는 대신 래핑될 수 있어 이후 노름을 부정확하게 만듭니다. 예제의 부동 소수점 배열은 이 문제를 피하고 정수가 아닌 좌표도 지원합니다.
차원이 같은 NumPy 점 한 쌍에는 np.linalg.norm(point_a - point_b)가 간결한 기본값입니다. 행별 거리에는 axis=1을 추가하고 입력 구조가 보장되지 않을 때마다 형태와 데이터 형식을 검증하세요.