Pythonでデータ分析を行う際、「データの形(構造)」を柔軟に変換するスキルは、非常によく使うテクニックの一つです。
本記事では、Pandasのmelt()とpivot()を使って、横持ち(wide形式)のデータと縦持ち(long形式)のデータを相互に再構築する方法を、具体的なサンプル付きで解説します。
横持ち・縦持ちのデータとは
まず、前提として横持ち・縦持ちのデータとは、次に説明するようなデータを指します。
ここでは、生徒と成績のデータを例に、それぞれのデータを見ていきましょう。
横持ち(wide形式)とは
横持ちとは、「1つの行に対して複数の列が属性として並ぶデータ形式」を指します。
具体的なデータを見てみましょう。
# サンプルデータの生成
import pandas as pd
df = pd.DataFrame({
'生徒': ['A', 'B'],
'数学': [80, 60],
'英語': [70, 85],
'理科': [90, 75]
})
print(df)
Python生徒 | 数学 | 英語 | 理科 | |
---|---|---|---|---|
0 | A | 80 | 70 | 90 |
1 | B | 60 | 85 | 75 |
このように、生徒ごとに1行で完結しており、各教科が列として展開されています。
見た目にも直感的でわかりやすいのが横持ち形式の特徴です。
縦持ち(long形式)とは
一方で、縦持ちとは、「1つの測定値を1行にまとめ、列数を減らして行数を増やす」形式です。先ほどのデータを縦持ちにすると以下のようになります。
生徒 | 教科 | 点数 | |
---|---|---|---|
0 | A | 数学 | 80 |
1 | A | 英語 | 70 |
2 | A | 理科 | 90 |
3 | B | 数学 | 60 |
4 | B | 英語 | 85 |
5 | B | 理科 | 75 |
この形式は、グラフ化や集計処理において非常に扱いやすいという利点があります。たとえば、教科ごとの平均点を求めるときや、生徒別にグループ集計する場合に便利です。
横持ちと縦持ちの変換
横持ちと縦持ちにはそれぞれの形式に特徴や利点がありますが、データ分析を行うためには、適切な形式を選択する必要があります。
これからご紹介するmelt()とpivot()を使えば、それぞれのデータ形式を切り替えることが可能です。
melt():横持ち→縦持ち
Pandasのmelt()を使うと、横持ちデータを縦持ちに変換することができます。
基本的な構文
pd.melt(
df,
id_vars=None,
value_vars=None,
var_name=None,
value_name='value'
)
Python- id_vars:固定する列(そのまま残したい列)
- value_vars:縦持ちに変換したい列
- var_name:カテゴリ列の名前(列名がここに入る)
- value_name:値列の名前
実践
では、先ほどの成績の横持ちデータを、縦持ちに変換してみましょう。
df_melted = pd.melt(
df,
id_vars='生徒',
var_name='教科',
value_name='点数'
)
print(df_melted)
Python生徒 | 教科 | 点数 | |
---|---|---|---|
0 | A | 数学 | 80 |
1 | A | 英語 | 70 |
2 | A | 理科 | 90 |
3 | B | 数学 | 60 |
4 | B | 英語 | 85 |
5 | B | 理科 | 75 |
まず、横持ちのデータのうち、残したい列をid_varsとして指定します。
今回は「生徒」の列をそのまま使いたいのでこちらを指定しています。
尚、複数の列を残したい場合は、リスト形式で指定します(例えばid_vars=[’ID’, ’生徒’ ]など)。
次に特定の列を縦持ちにしたい場合は、value_varsを指定します。
今回のようにid_varsで指名した列以外のすべてを縦持ちにする場合は特に指定不要ですが、例えば「数学と理科だけを縦持ちにしたい」などの場合には、こちらで指定が可能です(複数の場合はこちらもリスト形式で指定)。
最後にvar_nameとvalue_nameでカテゴリになる列の名前と値になる列の名前を指定すれば、縦持ちへの変換が可能です。
pivot():縦持ち→横持ちに変換
Pandasのpivot()を使うと、横持ちデータを縦持ちに変換することができます。
基本的な構文
df.pivot(
index=列名,
columns=列名,
values=列名
)
Python- index:行インデックスにしたい列
- columns:列ラベルとして展開する列
- values:セルの値にする列
実践
それでは、先ほど縦持ちに変換したデータを、元の横持ちに戻してみましょう。
df_pivoted = df_melted.pivot(
index='生徒',
columns='教科',
values='点数'
)
print(df_pivoted)
Python教科 | 英語 | 数学 | 理科 |
---|---|---|---|
生徒 | |||
A | 70 | 80 | 90 |
B | 85 | 60 | 75 |
まず、縦持ちのデータのうち、そのまま残したい列をindexとして指定します。
今回は「生徒」の列をそのまま使いたいのでこちらを指定しています。
尚、複数の列を残したい場合は、リスト形式で指定します(例えばindex=[’ID’, ’生徒’ ]など)。
次に横持ちにしたときに列ラベルとして展開したい列をcolumns、そのセルの値となる列をvaluesとして指定すれば横持ちへの変換が可能です。
尚、横持ちへの変換自体は問題なく出来ていますが、列ラベルが2行ある、少し不思議な形となってしまっています。
完全に元の形にしたい場合は、以下のコードを追加してください。
df_pivoted = df_melted.pivot(
index='生徒',
columns='教科',
values='点数'
)
df_pivoted = df_pivoted.reset_index()
df_pivoted.columns.name = None
print(df_pivoted)
Python生徒 | 数学 | 英語 | 理科 | |
---|---|---|---|---|
0 | A | 80 | 70 | 90 |
1 | B | 60 | 85 | 75 |
こちらで最初の形式に戻すことができました。
注意点
pivot()は便利な関数ですが、使用する際には以下のような注意点があります。
- pivot()では、index × columnsの組み合わせがユニーク(一意)でなければなりません。
- 複数の値が存在する場合にはエラーになります。
このような場合は、代わりにpivot_table()の使用がおすすめです。
まとめ
本記事では、Pandasの melt() とpivot() を使って、データの「縦持ち」「横持ち」を相互に変換する方法を詳しく解説しました。
これらの関数は、日々のデータ加工や可視化の前処理として非常に重要な役割を果たします。
ぜひご自身のプロジェクトや業務の中でも活用してみてください。