Matching column values with elements in a list of lists of lists and adding corresponding values from another list

Question:

assets = [[['Ferrari', 'BMW', 'Suzuki'], ['Ducati', 'Honda']], [['Apple', 'Samsung', 'Oppo']]]
price = [[[853600, 462300, 118900], [96500, 16700]], [[1260, 750, 340]]]

I have a dataframe as follows :

Car Bike Phone
BMW Ducati Apple
Ferrari Honda Oppo

Looking for code to get the Total_Cost , i.e 462300 + 96500 + 1260 = 560060

Car Bike Phone Total Cost
BMW Ducati Apple 560060
Ferrari Honda Oppo 870640

I tried the for loop and succeeded, I want the advanced code if any.

Asked By: Avijit Das

||

Answers:

Here is a possible solution:

asset_price = {asset: price[a][b][c] 
                for a, asset_list in enumerate(assets) 
                for b, asset_sub_list in enumerate(asset_list) 
                for c, asset in enumerate(asset_sub_list)
}

df = pd.DataFrame({'Car': ['BMW'], 'Bike': ['Ducati'], 'Phone': ['Apple']})
df['Total_Cost'] = sum(df[col].map(asset_price).sum() for col in df.columns)
print(df)

   Car    Bike  Phone  Total_Cost
0  BMW  Ducati  Apple      560060
Answered By: Jamiu S.

An alternative approach:

First build a dataframe df_price which maps prices onto the assets and the classification (Car, Bike, and Phone):

df_price = (
    pd.DataFrame({"assets": assets, "price": price}).explode(["assets", "price"])
    .assign(cols=["Car", "Bike", "Phone"]).explode(["assets", "price"])
)

Result:

    assets   price   cols
0  Ferrari  853600    Car
0      BMW  462300    Car
0   Suzuki  118900    Car
0   Ducati   96500   Bike
0    Honda   16700   Bike
1    Apple    1260  Phone
1  Samsung     750  Phone
1     Oppo     340  Phone

(I have inserted the classification here due to the comment on the other answer: "… But if the nested lists of asset is having common name (say : Honda in place if Suzuki ) then Honda car and Honda Bike will take one price".

Then join the prices onto the .melted main dataframe df, .pivot (using the auxilliary column idx), sum up the prices in the rows, and bring the result in shape.

res = (
    df.melt(var_name="cols", value_name="assets", ignore_index=False)
    .merge(df_price, on=["cols", "assets"])
    .assign(idx=lambda df: df.groupby("cols").cumcount())
    .pivot(index="idx", columns="cols")
    .assign(total=lambda df: df.loc[:, "price"].sum(axis=1))
    .loc[:, ["assets", "total"]]
    .droplevel(0, axis=1).rename(columns={"": "Total_Costs"})
)

Result:

cols    Bike      Car  Phone  Total_Costs
idx                                      
0     Ducati      BMW  Apple     560060.0
1      Honda  Ferrari   Oppo     870640.0
Answered By: Timus
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.