pandas の melt で縦持ち・横持ちを変換する

データの形式には「縦持ち」と「横持ち」があります。pandas の melt を使うと、横持ちのデータを縦持ちに変換できます。これは pivot の逆操作にあたります。

縦持ちと横持ちの違い

まず、2 つの形式の違いを確認しましょう。

横持ち(ワイド形式)

1 行に複数の測定値が並ぶ。人間が見やすい形式。Excel のような表計算ソフトでよく使われる。

縦持ち(ロング形式)

1 行に 1 つの測定値。列数が少なく、行数が多い。統計処理や可視化ライブラリで扱いやすい。

たとえば、テストの点数データを考えてみます。

import pandas as pd

# 横持ち
df_wide = pd.DataFrame({
    'name': ['Alice', 'Bob'],
    'math': [80, 70],
    'english': [90, 85]
})
print(df_wide)

これを縦持ちに変換すると、以下のようになります。

# 縦持ち
df_long = pd.DataFrame({
    'name': ['Alice', 'Alice', 'Bob', 'Bob'],
    'subject': ['math', 'english', 'math', 'english'],
    'score': [80, 90, 70, 85]
})
print(df_long)

melt の基本的な使い方

melt を使って横持ちから縦持ちに変換します。

df_wide = pd.DataFrame({
    'name': ['Alice', 'Bob'],
    'math': [80, 70],
    'english': [90, 85]
})

df_long = pd.melt(df_wide, id_vars=['name'], var_name='subject', value_name='score')
print(df_long)

主要なパラメータは以下の通りです。

パラメータ説明
id_varsそのまま残す列
var_name変換後の列名(元の列名が値になる)
value_name変換後の値の列名

複数の識別列を指定する

id_vars には複数の列を指定できます。

df = pd.DataFrame({
    'year': [2023, 2024],
    'name': ['Alice', 'Bob'],
    'q1': [100, 150],
    'q2': [120, 180]
})

df_long = pd.melt(df, id_vars=['year', 'name'], var_name='quarter', value_name='sales')

year と name はそのまま残り、q1 と q2 が縦に展開されます。

特定の列だけを変換する

value_vars を指定すると、変換する列を限定できます。

df = pd.DataFrame({
    'name': ['Alice'],
    'math': [80],
    'english': [90],
    'note': ['Good']
})

# math と english だけを変換、note は無視
df_long = pd.melt(df, id_vars=['name'], value_vars=['math', 'english'],
                  var_name='subject', value_name='score')

pivot で元に戻す

縦持ちから横持ちに戻すには pivot を使います。

df_long = pd.DataFrame({
    'name': ['Alice', 'Alice', 'Bob', 'Bob'],
    'subject': ['math', 'english', 'math', 'english'],
    'score': [80, 90, 70, 85]
})

df_wide = df_long.pivot(index='name', columns='subject', values='score')
df_wide = df_wide.reset_index()  # インデックスを列に戻す

melt と pivot は互いに逆の操作になります。データの形式を変換する必要があるときは、この 2 つを使い分けてください。可視化ライブラリの seaborn などは縦持ちのデータを好むことが多いので、melt で変換してからグラフを描くことがよくあります。