Python | ファイル・OS 操作:pandas の列操作

Python Python
スポンサーリンク

概要(pandas の列操作は「列名で考える」が合言葉)

pandas の列操作は「列名を軸」に発想すると迷いません。列の選択・追加・更新・削除・並べ替え・型変換・文字列処理・条件列の作成まで、ほぼ1〜2行で書けます。重要なのは「loc を使って明示的に列へ代入する」「型と欠損を最初に整える」「ベクトル化(配列計算)で速く書く」の3点です。これだけで、短く速く壊れない列操作が身につきます。


列の選択・追加・更新・削除(まずは核となる操作)

列の選択と複数列の取り出し

import pandas as pd

df = pd.DataFrame({"name": ["Alice", "Bob"], "age": [25, 30], "city": ["Tokyo", "Osaka"]})

df["age"]            # 1列(Series)
df[["name", "age"]]  # 複数列(DataFrame)
Python

1列は Series(縦ベクトル)、複数列は DataFrame(表)として返ります。後工程が何を期待するかに合わせて取り出します。

列の追加と更新(ベクトル計算で一発)

df["age_plus"] = df["age"] + 1              # 計算で新列
df["tag"] = "user"                          # 全行に同じ値
df["name"] = df["name"].str.strip()         # 文字列整形(前後空白除去)
Python

既存列からの計算・定数の挿入・文字列処理は“列全体”に対して一度に適用できます(ループ不要)。

列の削除・列名の変更・列順の並べ替え

df = df.drop(columns=["age_plus"])          # 列削除
df = df.rename(columns={"city": "pref"})    # 列名変更
df = df[["name", "age", "pref"]]            # 列順の固定
Python

前処理の早い段階で列順・名前を固定すると、下流のコードが安定します。


条件列・マッピング・複数列計算(よく使う“意味付け”)

条件列の追加(真偽・カテゴリ)

df["adult"] = df["age"] >= 20               # True/False
df["age_band"] = pd.cut(df["age"], bins=[0,20,30,100], labels=["<=20","20-30","30+"])
Python

条件から意味を持つ列(フラグや区分)を作るのが定番です。cut は連続値を区間へまとめます。

辞書マッピングで値を変換

map_city = {"Tokyo": "関東", "Osaka": "関西"}
df["region"] = df["pref"].map(map_city)     # 該当しない値は NaN
Python

マスタ変換は map が最短。未定義は NaN になるので必要なら fillna で補完します。

複数列からの計算(ベクトルで一気に)

sales = pd.DataFrame({"qty": [10, 8], "price": [350.0, 280.0]})
sales["amount"] = sales["qty"] * sales["price"]
Python

列同士の四則演算はベクトル化され、高速で安全です。


apply とベクトル化の使い分け(遅くしない書き方)

まずは「ベクトル化(配列計算)」で書く

df["name_len"] = df["name"].str.len()            # ベクトル化(速い)
Python

文字列・日付・数値の多くは Series のアクセサ(str/dt)や演算でベクトル化できます。速度・可読性が高く、最優先。

apply は“複雑なロジック”に限定

def label(row):
    if row["age"] >= 30 and row["pref"] == "Osaka":
        return "VIP"
    return "REG"

df["segment"] = df.apply(label, axis=1)          # 行単位(遅め)
Python

行単位の apply は柔軟ですが遅くなりがち。パターン化できるなら条件演算(& |)や np.where、map/cut を使ってベクトル化する方が良いです。


型と欠損(壊れない列操作の下地づくり)

型を固定して“曖昧さ”をなくす

df["age"] = df["age"].astype("Int64")      # 欠損対応の整数型(Pandas 独自)
df["name"] = df["name"].astype("string")   # 文字列型(新方式)
Python

Int64(頭大文字)は NaN を許容する整数型。型を決めると計算・比較の挙動が安定します。

不正値を安全に数値化(coerce で NaN)

import pandas as pd
raw = pd.DataFrame({"score": ["10", "20", "x"]})
raw["score"] = pd.to_numeric(raw["score"], errors="coerce")  # "x" → NaN
Python

to_numeric(errors=”coerce”) は“壊れた値”を NaN に落とし、次の処理へ進めます。

欠損の補完・除去の基本線

df["pref"] = df["pref"].fillna("不明")         # 補完
df = df.dropna(subset=["age"])                 # 必須列が欠損の行を落とす
Python

“どの列が必須か”をはっきり決め、補完か削除かの方針を最初に統一します。


安全な代入と落とし穴(SettingWithCopyWarning を避ける)

loc で「明示的に」列へ代入する

sub = df.loc[df["age"] >= 25, ["name", "age"]]  # ビュー/コピーの曖昧さがある
df.loc[df["age"] >= 25, "tag"] = "silver"       # 元の df へ明示代入(安全)
Python

“部分 DataFrame に代入”は警告の温床。元の df へ代入するなら df.loc[…] = … を使って明示してください。

連鎖インデックス(chained indexing)を避ける

# 悪い例:df[df["age"]>=25]["tag"] = "silver"  ← 警告・反映されないことも
# 良い例:
df.loc[df["age"]>=25, "tag"] = "silver"
Python

「条件で絞って、さらに列へ代入」を1行でやると曖昧になります。必ず loc で一発指定します。


例題で身につける(定番から一歩先まで)

例題1:列追加→整形→並べ替え

import pandas as pd
df = pd.DataFrame({"name": [" Alice ", "Bob", "Cathy"], "age": [25, 30, 22], "city": ["Tokyo", "Osaka", "Tokyo"]})

df["name"] = df["name"].str.strip()        # 空白除去
df["adult"] = df["age"] >= 20              # フラグ列
df = df.sort_values(by=["age"], ascending=False)
print(df)
Python

例題2:辞書マップ+カテゴリ化で意味づけ

import pandas as pd
df = pd.DataFrame({"city": ["Tokyo","Osaka","Nagoya"]})

region = {"Tokyo": "関東", "Osaka": "関西"}
df["region"] = df["city"].map(region).fillna("その他")
df["region"] = df["region"].astype("category")   # カテゴリ型(軽量・集計向き)
print(df)
Python

例題3:複数列の条件でセグメント列を作る(ベクトル化)

import numpy as np, pandas as pd
df = pd.DataFrame({"age":[18,25,35], "city":["Tokyo","Osaka","Tokyo"]})

df["seg"] = np.where((df["age"]>=30) & (df["city"]=="Tokyo"), "VIP", "REG")
print(df)
Python

例題4:型と欠損を整えて安全に計算

import pandas as pd
df = pd.DataFrame({"qty": ["10", "x", "5"], "price": [350.0, 280.0, None]})

df["qty"] = pd.to_numeric(df["qty"], errors="coerce")      # 不正値→NaN
df["price"] = pd.to_numeric(df["price"], errors="coerce")  # None→NaN
df["amount"] = df["qty"] * df["price"]                     # 欠損があれば NaN
df["amount"] = df["amount"].fillna(0.0)                    # 補完ポリシー
print(df)
Python

まとめ

pandas の列操作は「列名で考える」「loc で明示代入する」「型と欠損を先に整える」が基本線です。追加・更新・削除・並べ替えは1〜2行、条件列・マッピング・区分化は map / cut / np.where でベクトル化し、apply は本当に複雑なときだけ。SettingWithCopyWarning を避けるには chained indexing をやめて loc を使う。Int64/string/category などの型で曖昧さを減らせば、初心者でも短く・速く・壊れない列操作が自然に書けるようになります。

タイトルとURLをコピーしました