pandas チートシート - DataFrame のデータ加工方法まとめ

DataFrame 加工のチートシート

作成/追加
df["列"] = スカラー値新しいカラムの作成(すべて同じ値)
df["列"] = シリーズ
df.assign(列=シリーズ)
新しいカラムの作成(Series の代入)
df2 = df.copy() # shallow copy
df2 = df.copy(deep=True)
DataFrame のコピー
df["列2"] = df["列1"] + 10
df["列2"] = df.apply(lambda r: r["列1"] + 10, axis=1)
既存カラムの値を使って新しいカラムを作成
df2 = df[["列1", "列2", "列3"]]カラムの抽出
結合 (concat, merge)
new_df = pd.concat([df1, df2])複数の DataFrame を縦結合
new_df = pd.merge(df1, df2, on="列", how="inner")2 つの DataFrame を横結合
削除 (drop, drop_duplicates)
df2 = df.drop(columns="列")
df2 = df.drop("列", axis=1)
指定したカラムを削除
df.drop(columns="列", inplace=True)
df.drop("列", axis=1, inplace=True)
del df["列"] ※非推奨
df.pop("列")
指定したカラムを削除(自分自身を変更)
df2 = df.drop(index="行")
df2 = df.drop("行", axis=0)
指定した行を削除
df.drop(index="行", inplace=True)
df.drop("行", axis=0, inplace=True)
指定した行を削除(自分自身を変更)
df2 = df[df["列"] != 値]条件に一致する行を削除
df.drop_duplicates()重複する行を削除
df.drop_duplicates(keep="last")重複する行を削除(最初ではなく最後の行を残す)
df.drop_duplicates(subset=["X1", "X2"])重複する行を削除(指定列の値が等しい行を削除)
置換 (replace)
df["列"].replace(置換前の値, 置換後の値)
df["列"].replace([前1, 前2, 前3], [後1, 後2, 後3])
値の置換
ソート (sort_values)
df2 = pd.sort_values(by="列")特定のカラムでソート(昇順)
df2 = df.sort_values(by="列", ascending=False)特定のカラムでソート(降順)
カテゴリ変数 (get_dummies)
new_df = df.select_dtypes(include="object")カテゴリ変数を抽出した DataFrame を作成
new_df = df.select_dtypes(exclude="object")カテゴリ変数を削除した DataFrame を作成
df2 = pd.get_dummies(df)
df2 = pd.get_dummies(df, columns=["列1", "列2"])
名義カテゴリ特徴量をワンホットエンコードする
カラム名/インデックス名 (columns, index, rename)
df.columns = [...]
df2 = df.rename(colums={...})
カラム名の変更
df.index = [...]
df2 = df.rename(index={...})
インデックス名の変更
データ型 (astype)
df.loc[:, "列1"] = df.loc[:, "列1].astype(float)
df["列1"] = df["列1"].astype(float)
列1のデータ型を変更
df2 = df.astype({"列1": "int64", "列2": "float64"})列1と列2のデータ型を変更
数値変換いろいろ
y = y.astype("float32") / 255.00〜255 (int) の値を 0.0〜1.0 (float) に正規化
y = (y > 0.5).astype(int)閾値を基準にして 0 or 1 の数値に変換
X -= X.mean(axis=0)平均値が 0 になるよう値を平行移動

新しいカラムの作成(あるいは上書き)

# 値が 0 の新しい列 X1 を作成する(あるいは上書き)
df["X1"] = 0

# 列 X1 の値をもとに新しい列 X2 を作成する(あるいは上書き)
df["X2"] = df["X1"] + 100           # 既存の DataFrame を変更する場合
df2 = df.assign(X2=df["X1"] + 100)  # 新しい DataFrame を作る場合

# 列 X1 と X2 の値をもとに新しい列 X3 を作成する(あるいは上書き)
df["X3"] = df["X1"] + df["X2"]     # 既存の DataFrame を変更する場合
df.assign(X3=df["X1"] + df["X2"])  # 新しい DataFrame を作る場合

# 任意の変換関数を適用する(下記は np.sqrt 関数で平方根を生成する例)
df["X2"] = df["X1"].apply(np.sqrt)

複数の DataFrame を縦結合する (pd.concat)

複数の DataFrame を縦方向に結合する(行を増やす)には、pd.concat() 関数に DataFrame のリストを渡します。

import pandas as pd

# テストデータ
df1 = pd.DataFrame({"col1": [1, 2, 3], "col2": [4, 5, 6]})
df2 = pd.DataFrame({"col1": [7, 8, 9], "col3": [10, 11, 12]})

# DataFrame を連結する
new_df = pd.concat([df1, df2])
print(new_df)
実行結果
   col1  col2  col3
0     1   4.0   NaN
1     2   5.0   NaN
2     3   6.0   NaN
0     7   NaN  10.0
1     8   NaN  11.0
2     9   NaN  12.0

片方の DataFrame にしか存在しないカラムの値には NaN が設定されます。

デフォルトでは上記のように、それぞれの DataFrame のもとのインデックス名が保持されます。 インデックス名を振り直すには、ignore_index=True オプションを指定します。

# インデックスを振り直す場合
new_df = pd.concat([df1, df2], ignore_index=True)
print(new_df)
実行結果
   col1  col2  col3
0     1   4.0   NaN
1     2   5.0   NaN
2     3   6.0   NaN
3     7   NaN  10.0
4     8   NaN  11.0
5     9   NaN  12.0

複数の DataFrame を横結合する (pd.merge)

複数の DataFrame を横方向に結合する(列を増やす)には、pd.merge() 関数を使用します。 引数として、どの列の値で対応づけるか (on) と、どのような結合アルゴリズムを使うか (how) を指定する必要があります。 結合アルゴリズムには次のようなものを指定できます。

  • 内部結合 (how="inner") (デフォルト)
    • 両方に同じ値が含まれる行のみを残します(AND のイメージ)。例えば、2 つの DataFrame において、商品 ID が一致する行があれば、その行だけをマージして新しいデータを作成します。
  • 完全外部結合 (how="outer")
    • 両方に同じ値が含まれる行があれば、それらは 1 つの行としてマージされ、その他の行はそのまま残されます(OR のイメージ)。片方にしか存在しない項目は欠損値 (NaN) で埋められます。
  • 左外部結合 (how="left")
    • 左側(第 1 引数)で指定した DataFrame の行だけが残されます。
  • 右外部結合 (how="right")
    • 右側(第 2 引数)で指定した DataFrame の行だけが残されます。

下記のサンプルコードでは、それぞれの結合アルゴリズムでどのような結果になるかを確認しています。

import pandas as pd

# サンプルデータ
df1 = pd.DataFrame({"Id": [1, 2, 3], "Name": ["Alice", "Bob", "Charlie"]})
df2 = pd.DataFrame({"Id": [2, 3, 4], "Age": [25, 30, 35]})

print("=== INNER JOIN ===")
result_inner = pd.merge(df1, df2, on="Id", how="inner")
print(result_inner)

print("\n=== OUTER JOIN ===")
result_outer = pd.merge(df1, df2, on="Id", how="outer")
print(result_outer)

print("\n=== LEFT JOIN ===")
result_left = pd.merge(df1, df2, on="Id", how="left")
print(result_left)

print("\n=== RIGHT JOIN ===")
result_right = pd.merge(df1, df2, on="Id", how="right")
print(result_right)
実行結果
=== INNER JOIN ===
   Id     Name  Age
0   2      Bob   25
1   3  Charlie   30

=== OUTER JOIN ===
   Id     Name   Age
0   1    Alice   NaN
1   2      Bob  25.0
2   3  Charlie  30.0
3   4      NaN  35.0

=== LEFT JOIN ===
   Id     Name   Age
0   1    Alice   NaN
1   2      Bob  25.0
2   3  Charlie  30.0

=== RIGHT JOIN ===
   Id     Name  Age
0   2      Bob   25
1   3  Charlie   30
2   4      NaN   35

一致する値を置換する (replace)

Series あるいは DataFrame オブジェクトの replace() メソッドを使うと、値の一括置換を行えます。 通常は DataFrame には列ごとに性質の異なるデータが格納されているはずなので、値の置換を行う場合は Series オブジェクト(列)単位で置換します。 次の例では、Class 列の "A""B" という値を、それぞれ 01 に置換しています。

import pandas as pd

# サンプルデータ
df = pd.DataFrame({
    "Price": [100, 200, 300, 400],
    "Class": ["A", "B", "A", "B"]
})

# Class 列のカテゴリ変数 (A, B) を数値 (0, 1) に置き換え
df["Class"].replace(["A", "B"], [0, 1], inplace=True)
print(df)
実行結果
   Price  Type
0    100     0
1    200     1
2    300     0
3    400     1

replace() メソッドで regex=True フラグを指定すると、正規表現 を使った置換が可能です。 次の例では、電話番号を表すフィールドから数値以外の文字を削除しています。

import pandas as pd

# サンプルデータ
df = pd.DataFrame({
    "Name": ["Alice", "Bob", "Charlie"],
    "Phone": ["123-4567-8901", "(0120) 111-2222", "111 2222 3333"]
})

# 数値以外の文字 (`\D`) をすべて削除する
df["Phone"].replace(r"\D", "", regex=True, inplace=True)
print(df)
実行結果
      Name        Phone
0    Alice  12345678901
1      Bob  01201112222
2  Charlie  11122223333

既存カラムの値を使って新しいカラムを作成

既存のカラムのデータ (Series) に対して演算を行うことで、新しいカラム用のデータを作成することができます。 次の例では、 カラムと カラムの値をくっつけた 氏名 カラムを作成しています。

import pandas as pd

# サンプルデータ
df = pd.DataFrame({
    "姓": ["佐藤", "鈴木", "田中"],
    "名": ["太郎", "花子", "次郎"]
})

# "姓" と "名" を結合した "氏名" 列を作成
df["氏名"] = df["姓"] + df["名"]

print(df)
実行結果
    姓   名    氏名
0  佐藤  太郎  佐藤太郎
1  鈴木  花子  鈴木花子
2  田中  次郎  田中次郎

上記のように、+- を使ったブロードキャスト演算で新しいカラムを作成してしまうのが一番簡単ですが、より複雑な加工処理を行いたい時は df.apply() メソッドに加工処理を行う関数を渡します(行ごとに処理することを示す axis=1 オプションも付けてください)。 次の例では、メールアドレス(mail カラム)からドメイン部分を抽出した domain カラムを作成しています。 ここでは値の加工に str#split() メソッドを使用しているので、ブロードキャスト演算が使えません。

import pandas as pd

# サンプルデータ
df = pd.DataFrame({
    "mail": ["host@example.com", "host@test.org", "host@sample.net"]
})

# "mail" 列からドメイン部分を抽出して新しい列 "domain" を作成する
df["domain"] = df.apply(lambda r: r["mail"].split("@")[1], axis=1)

print(df)
実行結果
               mail       domain
0  host@example.com  example.com
1     host@test.org     test.org
2   host@sample.net   sample.net

特定の列だけを抜き出した DataFrame を作成する

ある DataFrame から特定の列だけを抽出した DataFrame を作成したいときは次のようにします。

df2 = df[["列1", "列2", "列3"]]

メモリ効率のため、データの実体は共有されることに注意してください(df2 側で値を変更すると、df にも影響します)。 新しいメモリ領域にコピーする場合は、copy() を組み合わせて使用します。

df2 = df[["列1", "列2", "列3"]].copy()

カラムの削除 (drop, del, pop)

df.drop() メソッドを使うと、指定したカラムを削除した新しい DataFrame を取得できます。

drop によるカラムの削除
import pandas as pd

# テストデータ
df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6], "C": [7, 8, 9]})

# A カラムを削除
df2 = df.drop(columns="A")
df2 = df.drop("A", axis=1)  # 同上

# A カラムと B カラムを削除
df2 = df.drop(columns=["A", "B"])
df2 = df.drop(["A", "B"], axis=1)  # 同上

Python のリスト API である delpop でもカラムの削除を行うことができますが、これらは元の DataFrame を変更します(破壊的操作)。 pop は削除した列を Series として返します。

del と pop によるカラムの削除
# A カラムを削除 (df 自身を変更)
del df["A"]

# 同上だが削除したカラムを Series として返す
series = df.pop("A")
☝️ pop の使用例

pop によるカラムの削除は、機械学習用のデータセットから正解ラベルを分離するときに使われたりします。

# 正解ラベルの列 Price を分離
train_X = train.copy()
train_y = train_X.pop("Price")

df.drop() はデフォルトでは新しい DataFrame を返しますが、inplace=True を指定すれば、元の DataFrame を変更できます。 この場合、戻り値は None になります。

# 元の DataFrame 自身を変更する
df.drop(columns=["A", "B"], inplace=True)

行の削除 (drop)

指定した行を削除

drop による行の削除
import pandas as pd

# テストデータ
df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6], "C": [7, 8, 9]})

# 先頭行を削除(インデックスラベルが設定されてない場合)
df2 = df.drop(0)
df2 = df.drop(0, axis=0)  # 同上
df2 = df.drop(index=0)    # 同上

# 先頭行を削除(インデックスラベルが設定されている場合)
df2 = df.index = ["idx1", "idx2", "idx3"]
df2 = df.drop("idx1")
df2 = df.drop("idx1", axis=0)  # 同上
df2 = df.drop(index="idx1")    # 同上

# 複数の行をまとめて削除することも可能
df2 = df.drop(index=[0, 1, 2])
df2 = df.drop(index=["idx1", "idx2", "idx3"])

df.drop() はデフォルトでは新しい DataFrame を返しますが、inplace=True を指定すると元の DataFrame を変更できます。 この場合、戻り値は None になります。

# 先頭の行を削除 (元の df 自身を変更)
df.drop(index=0, inplace=True)

重複する行を削除

DataFrame#drop_duplicates() メソッドを使うと、同じデータを持つ行を取り除いた DataFrame を作成することができます。 次の例では、1 行目と 3 行目のデータが (100, "x", 500) で完全に一致しているので、3 行目が削除されています。

import pandas as pd

df = pd.DataFrame({
    "A": [100, 100, 100, 200, 300],
    "B": ["x", "y", "x", "y", "x"],
    "C": [500, 600, 500, 600, 700],
})

new_df = df.drop_duplicates()
print(new_df)
実行結果
     A  B    C
0  100  x  500
1  100  y  600
3  200  y  600
4  300  x  700

特定のカラムだけに着目して重複行を判断したいときは、subset=[列, 列, ...] オプションを指定します。 次の例では、少なくとも B 列と C 列の値が等しい行を重複行として取り除いています(部分的に一致する行を削除します)。

new_df = df.drop_duplicates(subset=["B", "C"])
print(new_df)
実行結果
     A  B    C
0  100  x  500
1  100  y  600
4  300  x  700
☝️ 重複している行を確認する

df.duplicated() で各行が重複しているかを示すフラグ (True/False) の Series オブジェクトを取得できます。 これを使って元のデータフレームをフィルタすると、重複している行だけを抽出 することができます。

import pandas as pd

df = pd.DataFrame({
    "A": [100, 100, 100, 200, 300],
    "B": ["x", "x", "x", "y", "z"],
})

dup_df = df[df.duplicated(keep=False)]
print(dup_df)

このコードを実行すると、最初の 3 つの行が重複していることを確認できます。

     A  B
0  100  x
1  100  x
2  100  x

df.duplicated() の戻り値は、デフォルトでは削除すべき行だけが True となります。 例えば、3 つの行が重複している場合、削除すべき 2 つの行のみ True になります。 上記コードのように、df.duplicated()keep=False オプションを付けることで、3 つの行すべてを True にすることができます。

条件に一致する行を削除

これは発想の転換ですが、「ある列の値が A 以外である行を抽出する」という操作は、「ある列の値が A である行を削除する」という操作になります。

import pandas as pd

# テストデータ
df = pd.DataFrame({
    "grade": ["A", "B", "C", "B", "A", "B"],
    "point": [100, 80, 50, 70, 90, 75]
})

# grade 列が A であるものを削除 (= A でないものを抽出する)
new_df = df[df["grade"] != "A"]
print(new_df)
実行結果
  grade  point
1     B     80
2     C     50
3     B     70
5     B     75

特定のカラムでソート

テストデータ
import numpy as np
import pandas as pd
df = pd.DataFrame({
    'grade': ['C', 'A', 'B', np.nan, 'B', 'A'],
    'price': [50, 100, 150, 70, 30, 200]
})
grade カラムでソート
>>> df.sort_values(by="grade")
  grade  price
1     A    100
5     A    200
2     B    150
4     B     30
0     C     50
3   NaN     70
欠損値 (NaN) を先頭に持ってくる
>>> df.sort_values(by="grade", na_position="first")
  grade  price
3   NaN     70
1     A    100
5     A    200
2     B    150
4     B     30
0     C     50
price カラムで降順ソート
>>> df.sort_values(by="price", ascending=False)
  grade  price
5     A    200
2     B    150
1     A    100
3   NaN     70
0     C     50
4     B     30
複数カラムでソート
>>> df.sort_values(by=["grade", "price"], ascending=[True, False])
  grade  price
5     A    200
1     A    100
2     B    150
4     B     30
0     C     50
3   NaN     70
ソート後にインデックス (0, 1, 2, ...) を振り直す
>>> df.sort_values(by="price").reset_index()
   index grade  price
0      4     B     30
1      0     C     50
2      3   NaN     70
3      1     A    100
4      2     B    150
5      5     A    200

元のインデックスは index という新規カラムに格納されます。 index カラムが不要な場合は reset_index() メソッドに drop=True を指定します。

カテゴリ変数を抽出/取り除いて DataFrame を作成

df.select_dtypes() を使って、カテゴリ変数の列のみを抽出した DataFrame を作成することができます。 NaN はカテゴリ変数とはみなされません。

import pandas as df

# テストデータ
df = pd.DataFrame({
    "col1": ["AAA", "BBB", "CCC", "DDD"],
    "col2": ["X", "Y", "Z", np.nan],
    "col3": [100, 200, 300, 400],
    "col4": [1.0, 2.0, 3.0, np.nan],
})

# カテゴリ変数だけの DataFrame を作成
new_df = df.select_dtypes(include=["object"])
print(new_df)
print(new_df.columns.to_list())
実行結果
  col1 col2
0  AAA    X
1  BBB    Y
2  CCC    Z
3  DDD  NaN

['col1', 'col2']

include パラメーターの代わりに、exclude パラメーターを使うと、指定したタイプの列だけを取り除くことができます。 次の例では、上記の例とは逆に、カテゴリ変数を取り除いた(数値変数のみの)DataFrameを作成しています。

# カテゴリ変数を取り除いた DataFrame を作成
new_df = df.select_dtypes(exclude=["object"])
print(new_df)
print(new_df.columns.to_list())
実行結果
   col3  col4
0   100   1.0
1   200   2.0
2   300   3.0
3   400   NaN

['col3', 'col4']