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.0 | 0〜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)
片方の DataFrame
にしか存在しないカラムの値には NaN
が設定されます。
デフォルトでは上記のように、それぞれの DataFrame
のもとのインデックス名が保持されます。
インデックス名を振り直すには、ignore_index=True
オプションを指定します。
# インデックスを振り直す場合
new_df = pd.concat([df1, df2], ignore_index=True)
print(new_df)
複数の DataFrame を横結合する (pd.merge)
複数の DataFrame
を横方向に結合する(列を増やす)には、pd.merge()
関数を使用します。
引数として、どの列の値で対応づけるか (on
) と、どのような結合アルゴリズムを使うか (how
) を指定する必要があります。
結合アルゴリズムには次のようなものを指定できます。
- 内部結合 (
how="inner"
) (デフォルト)- 両方に同じ値が含まれる行のみを残します(AND のイメージ)。例えば、2 つの
DataFrame
において、商品 ID が一致する行があれば、その行だけをマージして新しいデータを作成します。
- 両方に同じ値が含まれる行のみを残します(AND のイメージ)。例えば、2 つの
- 完全外部結合 (
how="outer"
)- 両方に同じ値が含まれる行があれば、それらは 1 つの行としてマージされ、その他の行はそのまま残されます(OR のイメージ)。片方にしか存在しない項目は欠損値 (NaN) で埋められます。
- 左外部結合 (
how="left"
)- 左側(第 1 引数)で指定した
DataFrame
の行だけが残されます。
- 左側(第 1 引数)で指定した
- 右外部結合 (
how="right"
)- 右側(第 2 引数)で指定した
DataFrame
の行だけが残されます。
- 右側(第 2 引数)で指定した
下記のサンプルコードでは、それぞれの結合アルゴリズムでどのような結果になるかを確認しています。
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)
一致する値を置換する (replace)
Series
あるいは DataFrame
オブジェクトの replace()
メソッドを使うと、値の一括置換を行えます。
通常は DataFrame
には列ごとに性質の異なるデータが格納されているはずなので、値の置換を行う場合は Series
オブジェクト(列)単位で置換します。
次の例では、Class
列の "A"
と "B"
という値を、それぞれ 0
と 1
に置換しています。
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)
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)
既存カラムの値を使って新しいカラムを作成
既存のカラムのデータ (Series
) に対して演算を行うことで、新しいカラム用のデータを作成することができます。
次の例では、姓
カラムと 名
カラムの値をくっつけた 氏名
カラムを作成しています。
上記のように、+
や -
を使ったブロードキャスト演算で新しいカラムを作成してしまうのが一番簡単ですが、より複雑な加工処理を行いたい時は df.apply()
メソッドに加工処理を行う関数を渡します(行ごとに処理することを示す axis=1
オプションも付けてください)。
次の例では、メールアドレス(mail
カラム)からドメイン部分を抽出した domain
カラムを作成しています。
ここでは値の加工に str#split()
メソッドを使用しているので、ブロードキャスト演算が使えません。
特定の列だけを抜き出した DataFrame を作成する
ある DataFrame
から特定の列だけを抽出した DataFrame
を作成したいときは次のようにします。
df2 = df[["列1", "列2", "列3"]]
メモリ効率のため、データの実体は共有されることに注意してください(df2
側で値を変更すると、df
にも影響します)。
新しいメモリ領域にコピーする場合は、copy()
を組み合わせて使用します。
df2 = df[["列1", "列2", "列3"]].copy()
カラムの削除 (drop, del, pop)
df.drop()
メソッドを使うと、指定したカラムを削除した新しい DataFrame
を取得できます。
Python のリスト API である del
や pop
でもカラムの削除を行うことができますが、これらは元の DataFrame
を変更します(破壊的操作)。
pop
は削除した列を Series
として返します。
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)
指定した行を削除
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)
特定のカラムだけに着目して重複行を判断したいときは、subset=[列, 列, ...]
オプションを指定します。
次の例では、少なくとも B
列と C
列の値が等しい行を重複行として取り除いています(部分的に一致する行を削除します)。
new_df = df.drop_duplicates(subset=["B", "C"])
print(new_df)
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)
特定のカラムでソート
元のインデックスは index
という新規カラムに格納されます。
index
カラムが不要な場合は reset_index()
メソッドに drop=True
を指定します。
カテゴリ変数を抽出/取り除いて DataFrame を作成
df.select_dtypes()
を使って、カテゴリ変数の列のみを抽出した DataFrame
を作成することができます。
NaN はカテゴリ変数とはみなされません。
include
パラメーターの代わりに、exclude
パラメーターを使うと、指定したタイプの列だけを取り除くことができます。
次の例では、上記の例とは逆に、カテゴリ変数を取り除いた(数値変数のみの)DataFrame
を作成しています。