My data looks like the following :
source target
time
0.5 96253 94861
1.0 96652 95091
1.5 94861 95091
2.5 95091 95409
3.5 95409 97221
4.5 97221 96781
5.5 96781 97707
6.5 97707 98191
7.5 98191 99096
8.5 99096 100016
8.5 99096 100013
9.5 100013 98663
9.5 100016 98658
10.5 98658 99573
10.5 98663 99589
11.5 99589 100506
11.5 99573 100490
source
and target
columns reference a spots. time
index refers to the time point in which the link can be found. A smart algorithm would be to found all the possible trajectories contained inside the dataset.
For example in the previous example, 4 trajectories exist :
[96253, 94861, 95091, 95409, 97221, 97221, 96781, 97707, 98191, 99096, 100016, 98658, 99573, 100490]
[96652, 95091, 95409, 97221, 97221, 96781, 97707, 98191, 99096, 100016, 98658, 99573, 100490]
[96253, 94861, 95091, 95409, 97221, 97221, 96781, 97707, 98191, 99096, 100013, 98663, 99589, 100506]
[96652, 95091, 95409, 97221, 97221, 96781, 97707, 98191, 99096, 100013, 98663, 99589, 100506]
This problem can be resumed as a graph theory problem. See the below graph which corresponds to the data showed at the beginning.
The idea would be to find all possible paths in this graph with a constraint respecting time logic : a trajectory is an ordered list of spots (nodes) which can only go from t
to t+1
(can't go in past).
The algorithm will be implemented in Python. So any Python tricks are allowed :-)
Applying graph theory algorithm seems to be the smart way to resolve this. I used networkx
python library.
print(spot_ids)
output :
source target
time
0.5 96253 94861
1.0 96652 95091
1.5 94861 95091
2.5 95091 95409
3.5 95409 97221
4.5 97221 96781
5.5 96781 97707
6.5 97707 98191
7.5 98191 99096
8.5 99096 100016
8.5 99096 100013
9.5 100013 98663
9.5 100016 98658
10.5 98658 99573
10.5 98663 99589
11.5 99589 100506
11.5 99573 100490
The algorithm :
import itertools
import networkx as nx
# Build graph
graph = nx.Graph()
for t, spot in spot_ids.iterrows():
graph.add_edge(int(spot['source']), int(spot['target']), attr_dict=dict(t=t))
# Find graph extremities by checking if number of neighbors is equal to 1
tracks_extremities = [node for node in graph.nodes() if len(graph.neighbors(node)) == 1]
tracks_extremities
paths = []
# Find all possible paths between extremities
for source, target in itertools.combinations(tracks_extremities, 2):
# Find all path between two nodes
for path in nx.all_simple_paths(graph, source=source, target=target):
# Now we need to check wether this path respect the time logic contraint
# edges can only go in one direction of the time
# Build times vector according to path
t = []
for i, node_srce in enumerate(path[:-1]):
node_trgt = path[i+1]
t.append(graph.edge[node_srce][node_trgt]['t'])
# Will be equal to 1 if going to one time direction
if len(np.unique(np.sign(np.diff(t)))) == 1:
paths.append(path)
for path in paths:
print(path)
output :
[100490, 99573, 98658, 100016, 99096, 98191, 97707, 96781, 97221, 95409, 95091, 96652]
[100490, 99573, 98658, 100016, 99096, 98191, 97707, 96781, 97221, 95409, 95091, 94861, 96253]
[96652, 95091, 95409, 97221, 96781, 97707, 98191, 99096, 100013, 98663, 99589, 100506]
[100506, 99589, 98663, 100013, 99096, 98191, 97707, 96781, 97221, 95409, 95091, 94861, 96253]
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.