I have a tree of categories setup as follows. The top level is defined by parent_id = -1 (in this case I have two nodes (i.e. Linear Asset and Point Asset) at the top level.
asset_tree = [
{'id': 1, 'name': 'Linear Asset', 'parent_id': -1},
{'id': 2, 'name': 'Lateral', 'parent_id': 1},
{'id': 3, 'name': 'Main', 'parent_id': 1},
{'id': 4, 'name': 'Point Asset', 'parent_id': -1},
{'id': 5, 'name': 'Fountain', 'parent_id': 4},
{'id': 6, 'name': 'Hydrant', 'parent_id': 4}
]
I also have a dataframe of assets defined as this:
import pandas as pd
df = pd.DataFrame({
'name': ['pipe_1','pipe_2','pipe_3','hydrant_1', 'hydrant_2', 'fountain_1', 'fountain_2'],
'level_1': ['Linear Asset','Linear Asset','Linear Asset','Point Asset','Point Asset','Point Asset','Point Asset'],
'level_2': ['Main','Lateral','Lateral','Hydrant','Hydrant','Fountain','Fountain']
})
and thus the dataframe looks like this:
name level_1 level_2
0 pipe_1 Linear Asset Main
1 pipe_2 Linear Asset Lateral
2 pipe_3 Linear Asset Lateral
3 hydrant_1 Point Asset Hydrant
4 hydrant_2 Point Asset Hydrant
5 fountain_1 Point Asset Fountain
6 fountain_2 Point Asset Fountain
I want a function that will lookup the id of lowest level of the tree (in the example case, level_2). For my example code, my dataframe output would be as follows. Also, I would like the function to work if I had 1, 2, or 3 levels.
name level_1 level_2 tree_id
0 pipe_1 Linear Asset Main 3
1 pipe_2 Linear Asset Lateral 2
2 pipe_3 Linear Asset Lateral 2
3 hydrant_1 Point Asset Hydrant 6
4 hydrant_2 Point Asset Hydrant 6
5 fountain_1 Point Asset Fountain 5
6 fountain_2 Point Asset Fountain 5
I thought of the following function, but there are a few problems:
- it does not work (it gives me the level_1 id, not the level_2)
- ideally, if I had three levels (i.e. level_1, level_2, and level_3) instead of just two, it would work with a more complex tree.
def find_tree_id(branches, tree):
tree_id = None
number_of_branches = len(branches)
parent_id = -99
for i in range(0,number_of_branches):
for j in range(0,len(tree)):
if i == 0 and branches[i] == tree[j]['name']:
parent_id = tree[j]['parent_id']
tree_id = tree[j]['id']
if parent_id == -1:
return tree_id
return tree_id
tree_ids = []
for i, row in df.iterrows():
tree_id = find_tree_id([row['level_1'], row['level_2']], asset_tree)
tree_ids.append(tree_id)
df['tree_id'] = tree_ids
print(df)
The erroneous output is:
name level_1 level_2 tree_id
0 pipe_1 Linear Asset Main 1
1 pipe_2 Linear Asset Lateral 1
2 pipe_3 Linear Asset Lateral 1
3 hydrant_1 Point Asset Hydrant 4
4 hydrant_2 Point Asset Hydrant 4
5 fountain_1 Point Asset Fountain 4
6 fountain_2 Point Asset Fountain 4