Let’s not forget math.hypot:
dist = math.hypot(x2-x1, y2-y1)
Here’s hypot as part of a snippet to compute the length of a path defined by a list of (x, y) tuples:
from math import hypot
pts = [
(10,10),
(10,11),
(20,11),
(20,10),
(10,10),
]
# Py2 syntax - no longer allowed in Py3
# ptdiff = lambda (p1,p2): (p1[0]-p2[0], p1[1]-p2[1])
ptdiff = lambda p1, p2: (p1[0]-p2[0], p1[1]-p2[1])
diffs = (ptdiff(p1, p2) for p1, p2 in zip (pts, pts[1:]))
path = sum(hypot(*d) for d in diffs)
print(path)
In this tutorial, we will look at how to calculate the distance between two points in Python with the help of some examples.
If you prefer video over text, check out the following video detailing the steps in this tutorial –
There are a number of ways to compute the distance between two points in Python. You can compute the distance directly or use methods from libraries like math
, scipy
, numpy
, etc.
We generally refer to the Euclidean distance when talking about the distance between two points. To calculate the Euclidean distance between the points (x1, y1) and (x2, y2) you can use the formula:
For example, the distance between points (2, 3) and (5, 7) is 5. Note that the above formula can be extended to n-dimensions.
Euclidean distance in Python
Now that we know how the distance between two points is computed mathematically, we can proceed to compute it in Python.
Python has a number of libraries that help you compute distances between two points, each represented by a sequence of coordinates. Before we proceed to use off-the-shelf methods, let’s directly compute the distance between points (x1, y1) and (x2, y2).
# point a x1 = 2 y1 = 3 # point b x2 = 5 y2 = 7 # distance b/w a and b distance = ((x1 - x2)**2 + (y1 - y2)**2)**0.5 # display the result print("Distance between points ({}, {}) and ({}, {}) is {}".format(x1,y1,x2,y2,distance))
Output:
Distance between points (2, 3) and (5, 7) is 5.0
You can see that we get the distance between the points (2, 3) and (5, 7) as 5. Note that the above formula works only for points in two dimensions.
Let’s now write a generalized function that can handle points with any number of dimensions.
def get_distance(p, q): """ Return euclidean distance between points p and q assuming both to have the same number of dimensions """ # sum of squared difference between coordinates s_sq_difference = 0 for p_i,q_i in zip(p,q): s_sq_difference += (p_i - q_i)**2 # take sq root of sum of squared difference distance = s_sq_difference**0.5 return distance # check the function a = (2, 3, 6) b = (5, 7, 1) # distance b/w a and b d = get_distance(a, b) # display the result print(d)
Output:
7.0710678118654755
You can see that we used the function to get distance between two points with three dimensions each. We can now use this function to calculate distances between two points with any dimensions.
Note that the above function can further be improved by using vectorization to calculate the difference between the coordinates.
Euclidean distance using math
library
You can use the math.dist()
function to get the Euclidean distance between two points in Python. For example, let’s use it the get the distance between two 3-dimensional points each represented by a tuple.
import math # two points a = (2, 3, 6) b = (5, 7, 1) # distance b/w a and b d = math.dist(a, b) # display the result print(d)
Output:
7.0710678118654755
We get the same value as above.
Euclidean distance using numpy
library
The Euclidean distance is equivalent to the l2 norm of the difference between the two points which can be calculated in numpy using the numpy.linalg.norm()
function.
import numpy as np # two points a = np.array((2, 3, 6)) b = np.array((5, 7, 1)) # distance b/w a and b d = np.linalg.norm(a-b) # display the result print(d)
Output:
7.0710678118654755
We get the same result as above. Note that, here, we pass the difference between points a and b as a numpy array to the the np.linalg.norm()
function.
Euclidean distance using scipy
library
The scipy
library contains a number of useful functions of scientific computation in Python. Use the distance.euclidean()
function available in scipy.spatial
to calculate the Euclidean distance between two points in Python.
from scipy.spatial import distance # two points a = (2, 3, 6) b = (5, 7, 1) # distance b/w a and b d = distance.euclidean(a, b) # display the result print(d)
Output:
7.0710678118654755
We get the same result as above. For more on the distance function, refer to its documentation.
With this, we come to the end of this tutorial. The code examples and results presented in this tutorial have been implemented in a Jupyter Notebook with a python (version 3.8.3) kernel having numpy version 1.18.5 and pandas version 1.0.5
Subscribe to our newsletter for more informative guides and tutorials.
We do not spam and you can opt out any time.
-
Piyush is a data professional passionate about using data to understand things better and make informed decisions. He has experience working as a Data Scientist in the consulting domain and holds an engineering degree from IIT Roorkee. His hobbies include watching cricket, reading, and working on side projects.
View all posts
Время на прочтение
5 мин
Количество просмотров 28K
В этом руководстве мы рассмотрим, как рассчитать евклидово расстояние между двумя точками в Python с помощью Numpy.
Что такое евклидово расстояние?
Евклидово расстояние — это фундаментальная метрика расстояния, относящаяся к системам в евклидовом пространстве.
-
Евклидово пространство — это классическое геометрическое пространство, с которым вы знакомитесь на уроке математики, обычно связанное с 3 измерениями. Хотя его также можно приписать к любой неотрицательной целочисленной размерности.
-
Евклидово расстояние — кратчайшая прямая между двумя точками в евклидовом пространстве.
Название происходит от Евклида, который широко известен как «отец геометрии», так как это было единственное пространство, которое люди в то время обычно задумывали. Со временем в физике и математике наблюдались различные типы пространства, такие как пространство Аффин.
-
В 3-мерном евклидовом пространстве кратчайшая прямая между двумя точками всегда будет прямой линией между ними.
Учитывая этот факт, евклидово расстояние не всегда является наиболее полезной метрикой для отслеживания при работе со многими размерностями, мы сосредоточимся на 2D и 3D евклидовом пространстве для расчета евклидова расстояния.
Вообще говоря, евклидова расстояние широко используется в разработке 3D-миров, а также алгоритмов машинного обучения, которые включают в себя метрики расстояния, такие как K-ближайшие соседи. Как правило, евклидово расстояние будет представлять, насколько похожи две точки данных, предполагая, что некоторая кластеризация на основе других данных уже была выполнена.
Математическая формула
Математическая формула расчета евклидова расстояния между 2 точками в 2D пространстве:
Формула легко адаптируется к 3D-пространство, а также к любому размеру:
Общая формула может быть упрощена до:
Острый глаз может заметить сходство между евклидовым расстоянием и теоремой Пифагора:
На самом деле существует связь между ними — евклидовое расстояние рассчитывается с помощью теоремы Пифагора, учитывая декартовы координаты двух точек.
Из-за этого евклидова расстояние иногда называют расстоянием Пифагора, хотя прежнее название гораздо более известно.
Примечание: Две точки являются векторами, но выход должен быть скалярным.
Мы будем использовать NumPy для расчета этого расстояния для двух точек, и один и тот же подход используется для 2D и 3D пространств:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection = '3d')
ax.scatter(0, 0, 0)
ax.scatter(3, 3, 3)
plt.show()
Расчет евклидова расстояния в Python с помощью NumPy
Во-первых, нам нужно будет установить библиотеку NumPy:
$ pip install numpy
Теперь давайте импортируем его и настроим две наши точки с декартовыми координатами (0, 0, 0) и (3, 3, 3):
import numpy as np
# Initializing the points
point_1 = np.array((0, 0, 0))
point_2 = np.array((3, 3, 3))
Вместо того, чтобы выполнять расчет вручную, мы будем использовать вспомогательные методы NumPy, чтобы сделать его еще проще!
np.sqrt() и np.sum()
Операции и математические функции, необходимые для расчета евклидова расстояния, довольно просты: сложение, вычитание, а также функция квадратного корня. Несколько слагаемых также можно заменить суммой:
NumPy предоставляет нам функцию np.sqrt(), представляющую функцию квадратного корня, а также функцию np.sum(), которая представляет собой сумму. При этом расчет евклидова расстояния в Python прост и интуитивно понятен:
# Get the square of the difference of the 2 vectors
square = np.square(point_1 - point_2)
# Get the sum of the square
sum_square = np.sum(square)
Данная формула дает нам довольно простой результат:
(0-3)^2 + (0-3)^2 + (0-3)^2
Что равно 27. Осталось все, что получить квадратный корень из этого числа:
# The last step is to get the square root and print the Euclidean distance
distance = np.sqrt(sum_square)
print(distance)
Это приводит к:
5.196152422706632
В истинном питоновом духе это можно сократить до одной строки:
И вы даже можете вместо этого использовать встроенные методы pow() и sum() математического модуля Python, хотя они требуют, чтобы вы немного поработали с вводом, который удобно абстрагируется с помощью NumPy, так как функция pow() работает только со скалярами (каждый элемент в массиве индивидуально) и принимает аргумент — в какой степени вы увеличиваете число.
Этот подход, однако, интуитивно больше похож на формулу, которую мы использовали раньше:
from math import *
distance = np.sqrt(sum(pow(a-b, 2) for a, b in zip(point_1, point_2)))
print(distance)
Это также приводит к:
5.196152422706632
np.linalg.norm()
Функция np.linalg.norm() представляет математическую норму. По сути, нормой вектора является его длина. Эта длина не обязательно должна быть евклидовым расстоянием, а может быть и другими расстояниями. Евклидово расстояние-это норма L2 вектора (иногда известная как евклидова норма), и по умолчанию функция norm() использует L2 — параметр ord имеет значение 2.
Если бы вы установили для параметра ord какое-то другое значение p, вы бы рассчитали другие p-нормы. Например, норма L1 вектора-это расстояние Манхэттена!
Имея это в виду, мы можем использовать функцию np.linalg.norm() для легкого и гораздо более чистого вычисления евклидова расстояния, чем использование других функций:
distance = np.linalg.norm(point_1-point_2)
print(distance)
Это приводит к печати расстояния L2/евклида:
5.196152422706632
Нормализация L2 и нормализация L1 широко используются в машинном обучении для нормализации входных данных.
np.dot()
Мы также можем использовать точечное произведение для расчета евклидова расстояния. В математике точечное произведение является результатом умножения двух векторов равной длины, а результатом является единственное число — скалярное значение. Из-за возвращаемого типа его иногда также называют «скалярным продуктом». Эту операцию часто называют внутренним произведением для двух векторов.
Для расчета точечного произведения между 2 векторами вы можете использовать следующую формулу:
С помощью NumPy мы можем использовать функцию np.dot(), передавая два вектора.
Если мы вычислим точечное произведение разницы между обеими точками с той же разницей — мы получим число, которое находится в зависимости от евклидова расстояния между этими двумя векторами. Извлечение квадратного корня из этого числа дает нам расстояние, которое мы ищем:
# Take the difference between the 2 points
diff = point_1 - point_2
# Perform the dot product on the point with itself to get the sum of the squares
sum_square = np.dot(diff, diff)
# Get the square root of the result
distance = np.sqrt(sum_square)
print(distance)
Конечно, вы также можете сократить это до однострочного:
distance = np.sqrt(np.dot(point_1-point_2, point_1-point_2))
print(distance)
5.196152422706632
Использование встроенной системы math.dist()
В Python есть встроенный метод в математическом модуле, который вычисляет расстояние между 2 точками в трехмерном пространстве. Однако это работает только с Python 3.8 или более поздней версии.
math.dist()принимает два параметра, которые являются двумя точками, и возвращает евклидово расстояние между этими точками.
Примечание: Обратите внимание, что две точки должны иметь одинаковые размеры (т.е. оба в 2d или 3d пространстве).
Теперь, чтобы вычислить Евклидово расстояние между этими двумя точками, мы просто заправляем их в метод thedistdist():
import math
distance = math.dist(point_1, point_2)
print(distance)
5.196152422706632
Заключение
Данная метрика используется во многих контекстах в интеллектуальном анализе данных, машинном обучении и ряде других областей и является одной из фундаментальных метрик расстояния.
В этом уроке мы обсудим различные методы, с помощью которых пользователь может рассчитать расстояние между двумя местами на Земле. geopy – это библиотека Python, которая помогает рассчитать географическое расстояние.
Сначала нужно установить geopy с помощью следующей команды:
pip install geopy
После успешной установки мы готовы к работе с библиотекой geopy.
Вычисление расстояния между двумя точками
Ниже приведены важные методы, которые мы будем использовать, чтобы рассчитать расстояние между двумя точками с помощью GEOPY в Python:
- Метод 1: с использованием геодезического расстояния
Геодезическое расстояние – это длина кратчайшего пути между двумя точками на любой поверхности Земли. В следующем примере мы покажем, как пользователь может вычислить геодезическое расстояние на основе данных широты и долготы.
Пример:
# First, import the geodesic module from the geopy library from geopy.distance import geodesic as GD # Then, load the latitude and longitude data for New York & Texas New_York = (40.7128, 74.0060) Texas = (31.9686, 99.9018) # At last, print the distance between two points calculated in kilo-metre print ("The distance between New York and Texas is: ", GD(New_York, Texas).km)
Выход:
The distance between New York and Texas is: 2507.14797665193
- Метод 2: с использованием расстояния по большому кругу
Расстояние по большому кругу – это кратчайший путь между двумя точками на сфере. В этом случае мы предположим, что Земля – это идеальная сфера. В следующем примере показано, как пользователь может рассчитать расстояние по большому кругу, используя данные долготы и широты двух точек.
Пример:
# First, import the great_circle module from the geopy library from geopy.distance import great_circle as GC # Then, load the latitude and longitude data for New York & Texas New_York = (40.7128, 74.0060) Texas = (31.9686, 99.9018) # At last, print the distance between two points calculated in kilo-metre print ("The distance between New York and Texas is: ", GC(New_York, Texas).km)
Выход:
The distance between New York and Texas is: 2503.045970189156
- Метод 3: с использованием формулы гаверсинуса
Ортодромическое расстояние используется для вычисления кратчайшего расстояния между двумя точками широты и долготы на поверхности земли.
Используя этот метод, пользователю необходимо иметь координаты двух точек (P и Q).
Сначала нужно преобразовать значения точек широты и долготы из десятичных градусов в радианы, а затем разделить значения широты и долготы на (180 / π). Пользователь должен использовать значение «π = 22/7». Тогда значение (180 / π) будет «57,29577». Если пользователь хочет рассчитать расстояние в милях, он может использовать значение радиуса Земли, то есть «3963», а если в километрах – использовать значение «6,378,80».
Формулы:
How to calculate the value of latitude in radians: The value of Latitude in Radian: Latitude (La1) = La1 / (180/?) OR The value of Latitude in Radian: Latitude (La1) = La1 / 57.29577 How to calculate the value of longitude in radians: The value of Longitude in Radian: Longitude (Lo1) = Lo1 / (180/?) OR The value of Longitude in Radian: Longitude (Lo1) = Lo1 / 57.29577
Пользователю нужны координаты точки P и точки Q с точки зрения долготы и широты, а затем необходимо использовать приведенную выше формулу для преобразования их в радианы.
Теперь рассчитаем расстояние между двумя точками по следующей формуле.
Формула:
Для миль:
Distance (D) = 3963.0 * arccos[(sin(La1) * sin(La2)) + cos(La1) * cos(La2) * cos(Lo2 - Lo1)]
Для километров:
Distance (D) = 3963.0 * arccos[(sin(La1) * sin(La2)) + cos(La1) * cos(La2) * cos(Lo2 - Lo1)]
Таким образом, пользователь может рассчитать кратчайшее расстояние между двумя заданными точками на Земле с помощью формулы гаверсинуса.
Пример:
from math import radians, cos, sin, asin, sqrt # For calculating the distance in Kilometres def distance_1(La1, La2, Lo1, Lo2): # The math module contains the function name "radians" which is used for converting the degrees value into radians. Lo1 = radians(Lo1) Lo2 = radians(Lo2) La1 = radians(La1) La2 = radians(La2) # Using the "Haversine formula" D_Lo = Lo2 - Lo1 D_La = La2 - La1 P = sin(D_La / 2)**2 + cos(La1) * cos(La2) * sin(D_Lo / 2)**2 Q = 2 * asin(sqrt(P)) # The radius of earth in kilometres. R_km = 6371 # Then, we will calculate the result return(Q * R_km) # driver code La1 = 40.7128 La2 = 31.9686 Lo1 = -74.0060 Lo2 = -99.9018 print ("The distance between New York and Texas is: ", distance_1(La1, La2, Lo1, Lo2), "K.M") # For calculating the distance in Miles def distance_2(La1, La2, Lo1, Lo2): # The math module contains the function name "radians" which is used for converting the degrees value into radians. Lo1 = radians(Lo1) Lo2 = radians(Lo2) La1 = radians(La1) La2 = radians(La2) # Using the "Haversine formula" D_Lo = Lo2 - Lo1 D_La = La2 - La1 P = sin(D_La / 2)**2 + cos(La1) * cos(La2) * sin(D_Lo / 2)**2 Q = 2 * asin(sqrt(P)) # The radius of earth in Miles. R_Mi = 3963 # Then, we will calculate the result return(Q * R_Mi) print ("The distance between New York and Texas is: ", distance_2(La1, La2, Lo1, Lo2), "Miles")
Выход:
The distance between New York and Texas is: 2503.04243426357 K.M The distance between New York and Texas is: 1556.985899699659 Miles
В этом уроке мы обсудили различные методы расчета расстояния между двумя точками на поверхности земли с помощью библиотеки geopy и показали примеры каждого метода.
Изучаю Python вместе с вами, читаю, собираю и записываю информацию опытных программистов.
Edit: here’s a simple notebook example
A general approach, assuming that you have a DataFrame column containing points, and you want to calculate distances between all of them (If you have separate columns, first combine them into (lon, lat)
tuples, for instance). Name the new column coords
.
import pandas as pd
import numpy as np
from geopy.distance import vincenty
# assumes your DataFrame is named df, and its lon and lat columns are named lon and lat. Adjust as needed.
df['coords'] = zip(df.lat, df.lon)
# first, let's create a square DataFrame (think of it as a matrix if you like)
square = pd.DataFrame(
np.zeros(len(df) ** 2).reshape(len(df), len(df)),
index=df.index, columns=df.index)
This function looks up our ‘end’ coordinates from the df
DataFrame using the input column name, then applies the geopy vincenty()
function to each row in the input column, using the square.coords
column as the first argument. This works because the function is applied column-wise from right to left.
def get_distance(col):
end = df.ix[col.name]['coords']
return df['coords'].apply(vincenty, args=(end,), ellipsoid='WGS-84')
Now we’re ready to calculate all the distances.
We’re transposing the DataFrame (.T
), because the loc[]
method we’ll be using to retrieve distances refers to index label, row label. However, our inner apply function (see above) populates a column with retrieved values
distances = square.apply(get_distance, axis=1).T
Your geopy
values are (IIRC) returned in kilometres, so you may need to convert these to whatever unit you want to use using .meters
, .miles
etc.
Something like the following should work:
def units(input_instance):
return input_instance.meters
distances_meters = distances.applymap(units)
You can now index into your distance matrix using e.g. loc[row_index, column_index]
.
You should be able to adapt the above fairly easily. You might have to adjust the apply
call in the get_distance
function to ensure you’re passing the correct values to great_circle
. The pandas apply
docs might be useful, in particular with regard to passing positional arguments using args
(you’ll need a recent pandas version for this to work).
This code hasn’t been profiled, and there are probably much faster ways to do it, but it should be fairly quick for 400k distance calculations.
Oh and also
I can’t remember whether geopy expects coordinates as (lon, lat)
or (lat, lon)
. I bet it’s the latter (sigh).
Update
Here’s a working script as of May 2021.
import geopy.distance
# geopy DOES use latlon configuration
df['latlon'] = list(zip(df['lat'], df['lon']))
square = pd.DataFrame(
np.zeros((df.shape[0], df.shape[0])),
index=df.index, columns=df.index
)
# replacing distance.vicenty with distance.distance
def get_distance(col):
end = df.loc[col.name, 'latlon']
return df['latlon'].apply(geopy.distance.distance,
args=(end,),
ellipsoid='WGS-84'
)
distances = square.apply(get_distance, axis=1).T