Pandas 4 methods to deal with conditions.
Intuition\nCreate 3 conditions that will match the specified requirements:\n- no children => Leaf\n- no parent => Root\n- rest => Inner\n\n# Approach\nCondition
# Intuition\nCreate 3 conditions that will match the specified requirements:\n- no children => Leaf\n- no parent => Root\n- rest => Inner\n\n# Approach\nConditions are very simple, so it is the best possibility to test 4 approaches:\n- pandas apply\n- nested numpy where\n- numpy select\n- preffered "Pandas Cookbook" vectorization \n\n# Complexity\n- Time complexity: All expect apply are very fast, becouse they rely on vectorization, apply is going row by row\n\n# Code\n1. First is least preferable, quite long and slow but WORKING .apply() method ( to be honest im not very good in using apply() becouse I use vectorization whenever possible ) but here it is:\n```\nimport pandas as pd\n\ndef tree_node(tree: pd.DataFrame) -> pd.DataFrame:\n\n    parents = [x for x in tree.p_id.to_list() if type(x) == int]\n    \n    def category_assign(row):\n        if str(row["p_id"]) == "<NA>":\n            return "Root"\n        elif row["id"] in parents:\n            return "Inner"\n        else:\n            return "Leaf"\n\n    tree["type"] = tree.apply(category_assign, axis = 1)\n    return tree[["id","type"]] \n```\n2. Second method - numpy select is first vectorized solution way faster, and very clean when we have many many coditions,here are only 2 (3rd is default):\n```\nimport pandas as pd\nimport numpy as np\n\ndef tree_node(tree: pd.DataFrame) -> pd.DataFrame:\n\n    conditions = [  tree["p_id"].isna() , \n                    ~tree["id"].isin(tree.p_id).astype(bool)]\n    choices =   [   "Root",\n                    "Leaf"]\n    tree["type"] = np.select(conditions, choices, default = "Inner")\n    return tree[["id","type"]]\n```\n3. Third is my favourite, nested numpy where method , it\'s really  perfect if we have only two conditions, but even when there are multiple, if you format it in right way, in my opinion it is the cleanest solution:\n```\nimport pandas as pd\nimport numpy as np\n\ndef tree_node(tree: pd.DataFrame) -> pd.DataFrame:\n    tree["type"] =  np.where( tree.p_id.isna(),         "Root",     #//1st condition -> result\n                    np.where(~tree.id.isin(tree.p_id),  "Leaf",     #//2nd condition -> result\n                                                        "Inner" ))  #//last one -> default result\n    return tree[["id","type"]] \n```\n4. Finally probably fastest and preffered as a default by pandas creators (check [pandas cookbook](https://pandas.pydata.org/docs/user_guide/cookbook.html) first few examples)\n```\nimport pandas as pd\n\ndef tree_node(tree: pd.DataFrame) -> pd.DataFrame:\n    tree["type"] = "Inner"\n    tree.loc[~tree["id"].isin(tree["p_id"]), "type"] = "Leaf"\n    tree.loc[tree["p_id"].isnull(), "type"] = "Root"\n    return tree[["id","type"]] \n```
['Pandas']