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.
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
An alternative approach:
First build a dataframe df_price
which maps price
s 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 .melt
ed 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
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.
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
An alternative approach:
First build a dataframe df_price
which maps price
s 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 .melt
ed 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