Unit 8 • Lesson 4

Wide to Long with melt

Overview

Turning a column per month into a column that says which month.

Intermediate 20–25 min

What You Will Learn in This Lesson

By the end of this lesson, you will be able to:

  • Say what wide and long mean.
  • Melt a set of columns down into two.
  • Choose what stays put with id_vars.
  • Predict the row count after a melt.

Why This Matters

A spreadsheet is usually wide — a column per month — because that is readable. Every pandas operation you have learned wants long: one row per observation, with the thing that varies in a column of its own. You cannot group by month when month is twelve column headings.

Step 1: Why long is easier to work with

In a wide table the month is metadata — it lives in the column name, where no operation can reach it. In a long table it is data.

1

The same numbers, two shapes

Wide is easier to read; long is the only one you can group, filter or plot by month.

import pandas as pd

wide = pd.DataFrame({"name": ["Ada", "Bo"], "jan": [90, 70], "feb": [80, 60]})
print(wide)
print()
print(wide.melt(id_vars=["name"], var_name="month", value_name="score"))
2

And now the question is answerable

Grouping by month is impossible in the wide shape and one line in the long one.

import pandas as pd

wide = pd.DataFrame({"name": ["Ada", "Bo"], "jan": [90, 70], "feb": [80, 60]})
long = wide.melt(id_vars=["name"], var_name="month", value_name="score")
print(long.groupby("month")["score"].mean())

Mini Practice #1: Melt and group

Try It Yourself

Melt this table and then take the mean score per month — the question the wide shape cannot answer.

Press Run to see output

Step 2: id_vars are what stays put

Everything named in id_vars is repeated down the rows; everything else is folded into the two new columns.

1

Naming the new columns

var_name is where the old column headings go; value_name is where their values go. Naming both is worth the keystrokes.

import pandas as pd

wide = pd.DataFrame({"name": ["Ada"], "jan": [90], "feb": [80]})
print(wide.melt(id_vars=["name"]))
print()
print(wide.melt(id_vars=["name"], var_name="month", value_name="score"))
2

The row count is predictable

Rows times melted columns. Checking it catches an id_vars list that accidentally left something out.

import pandas as pd

wide = pd.DataFrame({"name": ["Ada", "Bo"], "jan": [90, 70], "feb": [80, 60]})
long = wide.melt(id_vars=["name"], var_name="month", value_name="score")
print(len(wide), "rows x 2 months =", len(long))

Forget to list a column in id_vars and it gets melted too, which usually shows up as a row count twice what you predicted.

Mini Practice #2: Predict the row count

Try It Yourself

Three people, four months. Say how many rows the melt gives before you run it.

Press Run to see output

Step 3: When to Use It

A column per period

Spreadsheets with jan, feb, mar columns become one month column and one value column.

df.melt(id_vars=["name"], var_name="month", value_name="score")

Before grouping or charting

Long tables group, filter and plot directly; wide ones need a column per operation.

When Not to Use It

Do not melt the identifying columns. Anything that says which row this is belongs in id_vars, or it is turned into values and lost.

End-of-Lesson Exercises

Exercise 1: Melt the months down

Write to_long(df) that melts a table with a name column and one column per month into columns name, month, score, and returns the row count.

id_vars=["name"] keeps the name and folds every other column down. The row count is people times months.

Press Run to try it, then Check my work to mark it.

Exercise 2: The best month, once it is a column

Write best_month(df) that melts a wide table with name and a column per month, and returns the month with the highest mean score. This is the question the wide shape cannot answer at all.

Melt with id_vars=["name"], group by the month column, take the mean of the score column, then idxmax for the label.

Press Run to try it, then Check my work to mark it.