Using Python
, given two data sets representing the positions of particles in 3D space taken at two time intervals, I'm looking for an elegant way to compute which 2 particles have traveled closer to one another relative to their previous state.
Here's a basic examples using 4 particles:
import numpy as np
points0 = np.array([[ 1, 0, 0],
[100, 100,0],
[ 0, 1, 0],
[ 0, 0, 0]])
points1 = np.array([[0.5, 0, 0],
[20 , 20, 0],
[ 0, 1, 0],
[ 0, 0, 0]])
In this examples, I can see in my samples that index 0
and index 3
, have moved to be the closest to one another, and that relative to their previous state they are now 50% closer
.
index 1
and index 3
did also move closer to one another. They are not the nearest, but relative to their previous state they are now 80% closer
.
index 1
and index 3
are the indices I am looking for.
QUESTION
Given two states between two substantially larger point clouds (1000 samples), what would be an elegant way to compute which particle pairs have moved closer relative to their previous state.
CodePudding user response:
I think this might be what you're after, but I'm not entirely sure:
In [2]: from scipy.spatial import distance
In [3]: d0 = distance.cdist(points0, points0)
In [4]: d1 = distance.cdist(points1, points1)
In [5]: relative_change = np.abs((d1 - d0) / (d0 1e-24))
In [6]: relative_change
Out[6]:
array([[0. , 0.80149414, 0.20943058, 0.5 ],
[0.80149414, 0. , 0.80395816, 0.8 ],
[0.20943058, 0.80395816, 0. , 0. ],
[0.5 , 0.8 , 0. , 0. ]])
In [7]: np.unravel_index(np.argmax(relative_change), relative_change.shape)
(1, 2)
Perhaps I'm misunderstanding how you're calculating it, but to me it looks like the particles at index 1 and index 2 had the largest relative change.
This seems reasonable to me, as the particle at index 2's magnitude didn't change, but the particle at index 1 had a very large change in magnitude. So the bulk of the relative change in their distance came from the change in particle 2's distance from the origin.
CodePudding user response:
You can compute the pairwise distances at each step and check whether they decreased.
from sklearn.metrics.pairwise import euclidean_distances
(euclidean_distances(points1, points1)
-euclidean_distances(points0, points0))<0
Output:
array([[False, True, True, True],
[ True, False, True, True],
[ True, True, False, False],
[ True, True, False, False]])
The diagonal are identities (point with itself), so always False. All points got closer to each other except (2,3).
If you want to see the ratios of the distances:
(euclidean_distances(points1, points1)
/euclidean_distances(points0, points0))
Output:
array([[ nan, 0.19850586, 0.79056942, 0.5 ],
[0.19850586, nan, 0.19604184, 0.2 ],
[0.79056942, 0.19604184, nan, 1. ],
[0.5 , 0.2 , 1. , nan]])
Again, the diagonal is NaN (division by zero), all combinations are lower than one (smaller distance) except for (2,3) where the distance is unchanged (=1).
CodePudding user response:
You're trying to maximize (d1-d2)/d1 = 1-d2/d1. Since the 1 is in common to all the pairs, you can just minimize d2/d1. You can get all the pairs from itertools:
import math
from itertools import combinations
def distance_ratio(pair):
return math.dist(points1[pair[0]], points1[pair[1]])/
math.dist(points0[pair[0]], points0[pair[1]])
most_decreased = min(combinations(len(points0),2), key = distance_ratio)