Eu tenho dois pontos em 3D:
(xa, ya, za)
(xb, yb, zb)
E eu quero calcular a distância:
dist = sqrt((xa-xb)^2 + (ya-yb)^2 + (za-zb)^2)
Qual é a melhor maneira de fazer isso com o NumPy ou com o Python em geral? Eu tenho:
import numpy
a = numpy.array((xa ,ya, za))
b = numpy.array((xb, yb, zb))
python
numpy
euclidean-distance
Nathan Fellman
fonte
fonte
Existe uma função para isso no SciPy. É chamado euclidiano .
Exemplo:
fonte
Para qualquer pessoa interessada em calcular várias distâncias de uma só vez, fiz uma pequena comparação usando o perfplot (um pequeno projeto meu).
O primeiro conselho é organizar seus dados de forma que as matrizes tenham dimensão
(3, n)
(e sejam C-contíguas, obviamente). Se a adição ocorrer na primeira dimensão contígua, as coisas serão mais rápidas e não importará muito se você usarsqrt-sum
comaxis=0
,linalg.norm
comaxis=0
ouque é, por uma ligeira margem, a variante mais rápida. (Isso também é válido para apenas uma linha.)
As variantes nas quais você resume o segundo eixo
axis=1
, são todas substancialmente mais lentas.Código para reproduzir o gráfico:
fonte
i,i->
data
tem que parecer?Quero expor a resposta simples com várias notas de desempenho. O np.linalg.norm fará talvez mais do que você precisa:
Em primeiro lugar - esta função foi projetada para trabalhar em uma lista e retornar todos os valores, por exemplo, para comparar a distância do
pA
conjunto de pontossP
:Lembre-se de várias coisas:
assim
não é tão inocente quanto parece.
Primeiramente - toda vez que chamamos, temos que fazer uma pesquisa global para "np", uma pesquisa com escopo para "linalg" e uma pesquisa com escopo para "norma", e a sobrecarga de simplesmente chamar a função pode equivaler a dezenas de python instruções.
Por fim, desperdiçamos duas operações para armazenar o resultado e recarregá-lo para retorno ...
Primeira passagem na melhoria: agilize a pesquisa, pule a loja
Ficamos muito mais simplificados:
A sobrecarga de chamada de função ainda equivale a algum trabalho, no entanto. E você desejará fazer benchmarks para determinar se é melhor fazer as contas sozinho:
Em algumas plataformas,
**0.5
é mais rápido quemath.sqrt
. Sua milhagem pode variar.**** Notas de desempenho avançadas.
Por que você está calculando a distância? Se o único objetivo é exibi-lo,
seguir em frente. Mas se você estiver comparando distâncias, verificando o alcance etc., gostaria de adicionar algumas observações úteis sobre o desempenho.
Vamos considerar dois casos: classificação por distância ou seleção de uma lista de itens que atendem a uma restrição de intervalo.
A primeira coisa que precisamos lembrar é que estamos usando Pitágoras para calcular a distância (
dist = sqrt(x^2 + y^2 + z^2)
), por isso estamos fazendo muitassqrt
ligações. Math 101:Em resumo: até exigirmos a distância em uma unidade de X em vez de X ^ 2, podemos eliminar a parte mais difícil dos cálculos.
Ótimo, ambas as funções não têm mais raízes quadradas caras. Isso será muito mais rápido. Também podemos melhorar o in_range convertendo-o em um gerador:
Isso tem benefícios especiais se você estiver fazendo algo como:
Mas se a próxima coisa que você fizer exigir uma distância,
considere produzir tuplas:
Isso pode ser especialmente útil se você puder encadear verificações de alcance ('encontre coisas próximas de X e dentro de Nm de Y', pois você não precisa calcular a distância novamente).
Mas e se estamos pesquisando uma lista realmente grande de
things
e antecipamos que muitos deles não valem a pena ser considerados?Na verdade, existe uma otimização muito simples:
Se isso é útil, dependerá do tamanho das 'coisas'.
E, novamente, considere render o dist_sq. Nosso exemplo de cachorro-quente passa a ser:
fonte
pointZ
que não existia. Acho que você quis dizer com dois pontos no espaço tridimensional e editei de acordo. Se eu estava errado, por favor me avise.Outra instância deste método de solução de problemas :
fonte
norm = lambda x: N.sqrt(N.square(x).sum())
;norm(x-y)
numpy.linalg.norm(x-y)
Iniciando
Python 3.8
, omath
módulo fornece diretamente adist
função, que retorna a distância euclidiana entre dois pontos (dados como tuplas ou listas de coordenadas):E se você estiver trabalhando com listas:
fonte
Isso pode ser feito da seguinte maneira. Não sei o quão rápido é, mas não está usando o NumPy.
fonte
for a, b in zip(a, b)
. Mas útil, no entanto.Eu encontro uma função 'dist' no matplotlib.mlab, mas não acho que seja útil o suficiente.
Estou postando aqui apenas para referência.
fonte
Eu gosto
np.dot
(produto escalar):fonte
Um bom one-liner:
No entanto, se a velocidade é uma preocupação, recomendo experimentar na sua máquina. Descobri que o uso de
math
bibliotecassqrt
com o**
operador para o quadrado é muito mais rápido na minha máquina do que a solução NumPy de uma linha.Eu executei meus testes usando este programa simples:
Na minha máquina,
math_calc_dist
roda muito mais rápido quenumpy_calc_dist
: 1,5 segundos versus 23,5 segundos.Para obter uma diferença mensurável entre
fastest_calc_dist
emath_calc_dist
eu tive que chegarTOTAL_LOCATIONS
a 6000. Depoisfastest_calc_dist
leva ~ 50 segundos enquantomath_calc_dist
leva ~ 60 segundos.Você também pode experimentar
numpy.sqrt
e,numpy.square
embora ambos sejam mais lentos que asmath
alternativas na minha máquina.Meus testes foram executados com o Python 2.6.6.
fonte
scipy.spatial.distance.cdist(p1, p2).sum()
,. É isso.numpy.linalg.norm(p1-p2).sum()
para obter a soma entre cada ponto em p1 e o ponto correspondente em p2 (ou seja, nem todos os pontos em p1 e todos os pontos em p2). E se você quiser todos os pontos da p1 a todos os pontos da p2 e não quiser usar o scipy, como no meu comentário anterior, use np.apply_along_axis junto com numpy.linalg.norm para fazer isso muito, muito mais rapidamente então sua solução "mais rápida".Você pode apenas subtrair os vetores e depois produzir o produto interno.
Seguindo o seu exemplo,
fonte
Tendo
a
eb
como você os definiu, você também pode usar:fonte
Com o Python 3.8, é muito fácil.
https://docs.python.org/3/library/math.html#math.dist
fonte
Aqui está um código conciso para a distância euclidiana no Python, com dois pontos representados como listas no Python.
fonte
Desde o Python 3.8
Desde Python 3.8 do
math
módulo inclui a funçãomath.dist()
.Veja aqui https://docs.python.org/3.8/library/math.html#math.dist .
fonte
Calcule a distância euclidiana para o espaço multidimensional:
fonte
fonte
fonte
Você pode facilmente usar a fórmula
que na verdade nada mais é do que usar o teorema de Pitágoras para calcular a distância, adicionando os quadrados de Δx, Δy e Δz e enraizando o resultado.
fonte
Encontre a diferença de duas matrizes primeiro. Em seguida, aplique a multiplicação por elementos com o comando multiplicar do numpy. Depois disso, encontre a soma do elemento nova matriz multiplicada. Finalmente, encontre a raiz quadrada do somatório.
fonte
Você primeira lista mudança de matriz numpy e fazer assim:
print(np.linalg.norm(np.array(a) - np.array(b)))
. Segundo método diretamente da lista python como:print(np.linalg.norm(np.subtract(a,b)))
fonte