データ分析を劇的に改善!Pandasの`rank(method="dense")`と`factorize`で実現する「見やすい連番」作成術
はじめに
データ分析をしていると、「もっとこの識別子が見やすければ…」「カテゴリごとに連番を振って比較したい…」と感じることはありませんか? 私自身、Pandasのある機能を活用することで、分析作業が格段に効率化した経験があります。
それは、rank(method="dense")
や pd.factorize
を使って、データに 「dense(密な)連番」 を付与するというテクニックです。
「denseな連番」とは、簡単に言うと1から始まる重複なし・抜けなしの綺麗な通し番号のことです。元のデータが飛び飛びの数値だったり、長い文字列だったりしても、これらの機能を使えば、分析しやすいシンプルな連番に変換できます。
今回は、この「denseな連番」を特定の列(ここでは例としてインデックスキー
という名前の列を扱います)に対して作成し、さらにグループを示す情報(例:グループ名
)と組み合わせることで、より便利な分析キーを作成する方法を2つご紹介します。
なぜ「denseな連番」が便利なのか?
連番を振りたい元の列(例えば商品コード、ユーザー識別子など)の値が、以下のような場合に「denseな連番」が役立ちます。
- 値が飛び飛びの数値や長い文字列: 「ID: 105」と「ID: 203」、「商品コード: XYZ001」と「商品コード: ABC999」など、そのままでは比較や並び替えがしにくい。
- グループごとの集計・可視化: カテゴリごとにデータを見たいとき、元の識別子が不規則だとグラフの軸が見づらかったり、集計結果の解釈が難しくなったりする。
- 直感的な理解: 単純な「1, 2, 3...」という連番は、誰にとっても分かりやすい。
「denseな連番」は、これらの問題を解決し、分析の効率と分かりやすさを向上させます。
rank(method="dense")
を使う(元の列が数値比較可能な場合)
方法1: 連番を振りたい対象の列(コード例では インデックスキー
列)が数値や日付など、大小比較が意味を持つデータの場合に有効な方法です。rank()
メソッドに method="dense"
を指定すると、同じ値には同じランク(番号)を振りつつ、次の異なる値には連番(ランク+1)を振ってくれます。
コード例:
import pandas as pd
# 'インデックスキー' は連番を振りたい元の列、'グループ名' はカテゴリを示す列とする
data = {'インデックスキー': [10, 20, 10, 30, 20],
'グループ名': ['チームA', 'チームA', 'チームB', 'チームA', 'チームB']}
df = pd.DataFrame(data)
print("--- 元データ ---")
print(df)
# 1. 'インデックスキー' 列に対して、dense rank を求める (1始まり)
# 小さい値から順に 1, 2, 3... と番号が付く
df["dense_index"] = df["インデックスキー"].rank(method="dense").astype(int)
# 2. 作成した dense_index と グループ名 を連結して新しいカラムを作成
# 文字列として連結するために .astype(str) を使用
df["連番とグループ名"] = df["dense_index"].astype(str) + "_" + df["グループ名"].astype(str)
# 結果を表示
print("\n--- rank(method=\"dense\") 適用後 ---")
print(df)
実行結果例:
--- 元データ ---
インデックスキー グループ名
0 10 チームA
1 20 チームA
2 10 チームB
3 30 チームA
4 20 チームB
--- rank(method="dense") 適用後 ---
インデックスキー グループ名 dense_index 連番とグループ名
0 10 チームA 1 1_チームA
1 20 チームA 2 2_チームA
2 10 チームB 1 1_チームB
3 30 チームA 3 3_チームA
4 20 チームB 2 2_チームB
この例では、元の インデックスキー
列の値 (10, 20, 30) に基づいて、dense_index
列に (1, 2, 3) という連番が振られています。そして、それを グループ名
と連結して、"1_チームA"
のような分かりやすいキーを作成しています。(新しい列名は 連番とグループ名
に変更しました)
pd.factorize()
を使う(元の列が文字列やカテゴリ値にも有効)
方法2: 連番を振りたい対象の列(コード例では インデックスキー
列)が文字列の場合や、大小比較に意味がない(出現順などで連番を振りたい)場合に非常に便利なのが pd.factorize()
です。これは、列に含まれるユニークな値に対して、最初に出現したものから順に 0, 1, 2... と整数を割り当てます。
コード例:
import pandas as pd
# 'インデックスキー' は連番を振りたい元の列、'グループ名' はカテゴリを示す列とする
data = {'インデックスキー': ["apple", "orange", "apple", "banana", "orange"],
'グループ名': ['果物セットX', '果物セットX', '果物セットY', '果物セットX', '果物セットY']}
df = pd.DataFrame(data)
print("--- 元データ ---")
print(df)
# 1. 'インデックスキー' 列の固有の値に対して、出現順に dense な番号を割り当てる
# pd.factorize は (整数配列, ユニーク値配列) のタプルを返すため [0] で整数配列を取得
# 0始まりなので +1 して 1始まりにする
df["dense_index"] = pd.factorize(df["インデックスキー"])[0] + 1
# 2. 作成した dense_index と グループ名 を連結して新しいカラムを作成
df["連番とグループ名"] = df["dense_index"].astype(str) + "_" + df["グループ名"].astype(str)
# 結果を表示
print("\n--- pd.factorize 適用後 ---")
print(df)
実行結果例:
--- 元データ ---
インデックスキー グループ名
0 apple 果物セットX
1 orange 果物セットX
2 apple 果物セットY
3 banana 果物セットX
4 orange 果物セットY
--- pd.factorize 適用後 ---
インデックスキー グループ名 dense_index 連番とグループ名
0 apple 果物セットX 1 1_果物セットX
1 orange 果物セットX 2 2_果物セットX
2 apple 果物セットY 1 1_果物セットY
3 banana 果物セットX 3 3_果物セットX
4 orange 果物セットY 2 2_果物セットY
こちらでは、インデックスキー
列の文字列 ("apple", "orange", "banana") に対して、出現順に dense_index
として (1, 2, 3) が割り当てられています。文字列に対しても簡単に連番が振れ、それを グループ名
と組み合わせることで、"1_果物セットX"
のような直感的なキーが作れます。
おわりに
- 元の列の値の大小に基づいて連番を振りたい場合 →
rank(method="dense")
- 元の列が文字列やカテゴリ値で、出現順などに基づいて連番を振りたい場合 →
pd.factorize()
どちらの方法でも、作成した dense_index
(1から始まる連番)と、既存の「グループ名」(などのカテゴリを示す列)を astype(str)
で文字列に変換し、+ "_" +
のように連結すれば、"1_チームA"
, "2_果物セットX"
のような非常に見やすい複合キーを作成できます。
この「denseな連番」と「複合キー」を活用することで、データのグループ化、集計、可視化などが格段にやりやすくなります。もし、扱いにくい識別子やIDを持つデータで分析に手間取っているなら、ぜひこの方法を試してみてください。きっと「データ分析が非常にしやすくなった!」と感じていただけると思います!
参考
Discussion