Try a pivot_table:
# Rename Columns
df.columns = df.columns.map(lambda x: f".{x.split('.')[-1]}" if '.' in x else x)
# Create Pivot Table
df = df.pivot_table(
index=['id', 'title', 'readyInMinutes'],
columns=['.title'],
values=['.amount',
'.percentOfDailyNeeds',
'.unit'],
aggfunc='first'
).reset_index() \
.swaplevel(0, 1, axis=1)
# Re-Order Columns So that nutrients.title are grouped
df = df.reindex(sorted(df.columns), axis=1)
# Reduce Levels by join
df.columns = df.columns.map(''.join)
print(df.to_string(index=False))
Output:
id readyInMinutes title Calories.amount Calories.percentOfDailyNeeds Calories.unit Carbohydrates.amount Carbohydrates.percentOfDailyNeeds Carbohydrates.unit Fat.amount Fat.percentOfDailyNeeds Fat.unit Net Carbohydrates.amount Net Carbohydrates.percentOfDailyNeeds Net Carbohydrates.unit Saturated Fat.amount Saturated Fat.percentOfDailyNeeds Saturated Fat.unit
1089577 120 Hungarian Goulash Stew 323.18 16.16 kcal 38.95 12.98 g 15.14 23.3 g 34.64 12.6 g 4.43 27.69 g
Steps with abridged outputs
- Change the Column Names:
print(df.columns.values)
# ['id' 'title' 'readyInMinutes' 'nutrients.amount' 'nutrients.name'
# 'nutrients.percentOfDailyNeeds' 'nutrients.title' 'nutrients.unit']
print(df.columns.map(lambda x: f".{x.split('.')[-1]}" if '.' in x else x).values)
# ['id' 'title' 'readyInMinutes' '.amount' '.name' '.percentOfDailyNeeds'
# '.title' '.unit']
- Pivot on multiple value columns with a single header column to create multi-level column index:
print(df.pivot_table(
index=['id', 'title', 'readyInMinutes'],
columns=['.title'],
values=['.amount',
'.percentOfDailyNeeds',
'.unit'],
aggfunc='first'
).to_string())
.amount
.title Calories Carbohydrates Fat Net Carbohydrates Saturated Fat
id title readyInMinutes
1089577 Hungarian Goulash Stew 120 323.18 38.95 15.14 34.64 4.43
- Fix index and swaplevels so that label comes on top (
Calories
, Carbohydrates
, etc.)
.reset_index().swaplevel(0, 1, axis=1)
.title Calories Carbohydrates Fat Net Carbohydrates Saturated Fat
id title readyInMinutes .amount .amount .amount .amount .amount
0 1089577 Hungarian Goulash Stew 120 323.18 38.95 15.14 34.64 4.43
- Sort Columns so labels are together:
df = df.reindex(sorted(df.columns), axis=1)
.title Calories Carbohydrates
id readyInMinutes title .amount .percentOfDailyNeeds .unit .amount .percentOfDailyNeeds .unit
0 1089577 120 Hungarian Goulash Stew 323.18 16.16 kcal 38.95 12.98 g
- Reduce levels using join (Create
Calories.amount
, Calories.unit
, etc)
df.columns = df.columns.map(''.join)
id readyInMinutes title Calories.amount Calories.percentOfDailyNeeds Calories.unit
0 1089577 120 Hungarian Goulash Stew 323.18 16.16 kcal