pandas チートシート
最終更新
DataFrame を作る
例やテスト、参照用テーブルのために手で作る小さな DataFrame です。
| やりたいこと | コード |
|---|---|
| pandas と NumPy をインポート | import pandas as pd
import numpy as np |
| 列の辞書から作成 | df = pd.DataFrame({"name": ["Ada", "Ben"], "age": [36, 28]}) |
| 行のリストから作成 | pd.DataFrame([{"name": "Ada", "age": 36}, {"name": "Ben", "age": 28}]) |
| NumPy 配列から作成 | pd.DataFrame(np.arange(6).reshape(3, 2), columns=["x", "y"]) |
| ラベル付きの Series | s = pd.Series([3, 5, 2], index=["a", "b", "c"]) |
| 日付の範囲 | pd.date_range("2026-01-01", periods=7, freq="D") |
ファイルの読み書き
1回の呼び出しでファイルを DataFrame に読み込み、1回の呼び出しで書き出せます。
| やりたいこと | コード |
|---|---|
| CSV ファイルを読み込む | df = pd.read_csv("sales.csv") |
| 一部の列だけ、日付は日付型で | pd.read_csv("sales.csv", usecols=["date", "city", "sales"], parse_dates=["date"]) |
| 列をインデックスにする | pd.read_csv("sales.csv", index_col="id") |
| タブなど別の区切り文字 | pd.read_csv("sales.tsv", sep="\t") |
| 特定の記号も欠損値として扱う | pd.read_csv("sales.csv", na_values=["n/a", "-"]) |
| 先頭の行だけ読み込む | pd.read_csv("sales.csv", nrows=1000) |
| Excel シートを読み込む (openpyxl が必要) | pd.read_excel("report.xlsx", sheet_name="2026") |
| JSON レコードを読み込む | pd.read_json("records.json") |
| SQL データベースから読み込む | pd.read_sql("SELECT * FROM orders", conn) |
| インデックスなしで CSV に書き出す | df.to_csv("clean.csv", index=False) |
| Excel や Parquet に書き出す | df.to_excel("clean.xlsx", index=False), df.to_parquet("clean.parquet") |
データを確認する
新しいデータセットを手にしたら、まず実行する呼び出しです。
| やりたいこと | コード |
|---|---|
| 先頭と末尾の行 | df.head(), df.tail(3) |
| 行数と列数 | df.shape # (6, 7) |
| 列の型と非欠損数 | df.info() |
| 数値列の要約統計量 | df.describe() |
| 全列の要約 | df.describe(include="all") |
| 列名と型 | df.columns, df.dtypes |
| 値ごとの件数 | df["city"].value_counts() |
| 値ごとの割合 | df["city"].value_counts(normalize=True) |
| ユニークな値とその数 | df["city"].unique(), df["city"].nunique() |
| 列ごとの欠損値の数 | df.isna().sum() |
| 行をランダムに抽出 | df.sample(3, random_state=0) |
| 数値列の相関 | df.corr(numeric_only=True) |
列と行を選択する
loc はラベルで選択し、スライスの終端を含みます。iloc は位置で選択し、終端を含みません。
| やりたいこと | コード |
|---|---|
| 1列を Series として | df["age"] |
| 複数列を DataFrame として | df[["name", "age"]] |
| ラベルで行と列を指定 | df.loc[0:2, ["name", "age"]] |
| 位置で行と列を指定 | df.iloc[0:2, 0:3] |
| 1つの値 | df.at[0, "age"], df.iat[0, 3] |
| 最後の行 | df.iloc[-1] |
| 特定の型の列 | df.select_dtypes(include="number") |
| 文字列の列 (pandas 3) | df.select_dtypes(include="str") |
| 列名のパターンで選択 | df.filter(like="sal"), df.filter(regex="^(age|salary)$") |
| 列の値で行を引く | df.set_index("name").loc["Ada", "salary"] |
| 0, 1, 2 のインデックスに戻す | df.reset_index(drop=True) |
| 列や行を削除 | df.drop(columns=["email"]), df.drop(index=[0, 1]) |
行をフィルタする
条件はそれぞれ括弧で囲み、& (かつ)、| (または)、~ (否定) で組み合わせます。
| やりたいこと | コード |
|---|---|
| 条件に合う行 | df[df["age"] > 30] |
| 両方の条件 | df[(df["age"] > 30) & (df["city"] == "Oslo")] |
| どちらかの条件 | df[(df["city"] == "Oslo") | (df["salary"] > 6000)] |
| 値がリストに含まれる | df[df["city"].isin(["Oslo", "Rome"])] |
| 値がリストに含まれない | df[~df["city"].isin(["Oslo", "Rome"])] |
| 2つの値の間 (両端を含む) | df[df["age"].between(30, 40)] |
| クエリ文字列でフィルタ | df.query("age > 30 and city == 'Oslo'") |
| クエリで変数を使う | min_age = 30
df.query("age > @min_age") |
| 文字列を含む | df[df["name"].str.contains("e", case=False)] |
| 欠損している値、していない値 | df[df["age"].isna()], df[df["age"].notna()] |
| 行を絞って列を選ぶ | df.loc[df["age"] > 30, ["name", "salary"]] |
| 上位または下位 n 行 | df.nlargest(3, "salary"), df.nsmallest(2, "age") |
| 重複する値を持つ行 | df[df.duplicated(subset=["city"], keep=False)] |
並べ替えと順位
| やりたいこと | コード |
|---|---|
| 列で並べ替え | df.sort_values("salary") |
| 大きい順 | df.sort_values("salary", ascending=False) |
| 複数列で並べ替え | df.sort_values(["city", "salary"], ascending=[True, False]) |
| 欠損値を先頭に | df.sort_values("age", na_position="first") |
| インデックスで並べ替え | df.sort_index() |
| 順位付け (最大値が1位) | df["salary"].rank(ascending=False) |
列の追加と変更
列全体をまとめて処理する操作は高速です。apply は組み込みメソッドで対応できないときだけ使いましょう。
| やりたいこと | コード |
|---|---|
| 他の列から新しい列 | df["bonus"] = df["salary"] * 0.1 |
| メソッドチェーンの中で列を追加 | df.assign(bonus=lambda d: d["salary"] * 0.1) |
| 条件で値を決める | df["level"] = np.where(df["age"] >= 40, "senior", "junior") |
| 複数の条件で値を決める | df["band"] = np.select([df["age"] < 30, df["age"] < 45], ["young", "mid"], default="senior") |
| 条件を満たす値を変更 | df.loc[df["city"] == "Lima", "salary"] = 4000 |
| 辞書で値を置き換え | df["country"] = df["city"].map({"Oslo": "NO", "Rome": "IT", "Lima": "PE"}) |
| 列に関数を適用 | df["salary"].apply(lambda x: round(x, -3)) |
| 全セルに関数を適用 | df[["age", "salary"]].map(lambda x: x / 1000) |
| 列名を変更 | df.rename(columns={"salary": "pay"}) |
| 列の型を変更 | df["salary"].astype("float64") |
| 文字列を数値に (不正値は NaN) | pd.to_numeric(s, errors="coerce") |
| 数値をラベル付きの区間に分ける | pd.cut(df["age"], bins=[0, 30, 45, 120], labels=["young", "mid", "senior"]) |
| 数値を同じサイズのグループに分ける | pd.qcut(df["salary"], q=4, labels=False) |
| 行をループ (遅いので最終手段) | for row in df.itertuples():
print(row.name, row.salary) |
欠損値とクリーニング
数値の欠損は NaN、日付の欠損は NaT と表示されます。どの呼び出しも新しいオブジェクトを返すので、結果を代入してください。
| やりたいこと | コード |
|---|---|
| 列ごとの欠損値の割合 | df.isna().mean() |
| 欠損値を含む行を削除 | df.dropna() |
| 重要な列が欠損した行を削除 | df.dropna(subset=["age"]) |
| 列ごとの値で埋める | df.fillna({"age": df["age"].median()}) |
| 前後の行の値で埋める | df["age"].ffill(), df["age"].bfill() |
| 補間で埋める | df["age"].interpolate() |
| 特定の記号を欠損値に変換 | df.replace(["n/a", "-", ""], np.nan) |
| 重複行を削除 | df.drop_duplicates() |
| キーごとに最後の行を残す | df.drop_duplicates(subset=["city"], keep="last") |
| 列名を整える | df.columns = df.columns.str.strip().str.lower().str.replace(" ", "_") |
| 外れ値を上限・下限で抑える | df["salary"].clip(lower=4000, upper=6000) |
| 繰り返しの多い文字列は category 型に | df["city"] = df["city"].astype("category") |
文字列の列 (.str)
pandas 3 では文字列の列がデフォルトで str dtype になります。.str メソッドは列全体に作用し、欠損値は欠損値のまま残ります。
| やりたいこと | コード |
|---|---|
| 大文字、小文字、先頭大文字 | df["name"].str.upper(), df["name"].str.lower(), df["name"].str.title() |
| 空白を除去 | df["name"].str.strip() |
| 文字列を置換 | df["email"].str.replace("mail.com", "example.com") |
| 正規表現で置換 | df["email"].str.replace(r"@.*", "", regex=True) |
| 含む、で始まる | df["name"].str.contains("a"), df["name"].str.startswith("E") |
| 各値の長さ | df["name"].str.len() |
| 先頭の数文字 | df["name"].str[:2] |
| 分割して列にする | df["email"].str.split("@", expand=True) |
| 正規表現のグループで抽出 | df["email"].str.extract(r"@(\w+)") |
| 文字列の列を連結 | df["name"] + " (" + df["city"] + ")" |
| 数値をゼロ埋め | df["salary"].astype("str").str.zfill(6) |
| 新しい文字列 dtype | df["name"].dtype # str |
日付と時刻
.dt アクセサは datetime 型の列で使えます。並べ替えた日付インデックス (下の ts) があれば、文字列でのスライスやリサンプリングができます。
| やりたいこと | コード |
|---|---|
| 列を datetime に変換 | df["date"] = pd.to_datetime(df["date"]) |
| 書式を指定して変換 | pd.to_datetime(["03/01/2026", "15/01/2026"], format="%d/%m/%Y") |
| 年、月、曜日名 | df["date"].dt.year, df["date"].dt.month, df["date"].dt.day_name() |
| 日付を月単位にまとめる | df["date"].dt.to_period("M") |
| 2つの日付の間の日数 | (pd.Timestamp("2026-12-31") - df["date"]).dt.days |
| 日数や月数を足す | df["date"] + pd.Timedelta(days=30), df["date"] + pd.DateOffset(months=1) |
| 期間内の行 | df[df["date"].between("2021-01-01", "2022-12-31")] |
| 日付インデックスを文字列でスライス | ts = df.set_index("date").sort_index()
ts.loc["2021":"2022"] |
| 月ごとの合計 | ts["salary"].resample("ME").sum() |
週ごとの平均 ("QE" は四半期、"YE" は年) | ts["salary"].resample("W").mean() |
| 移動平均 | ts["salary"].rolling(3).mean() |
| 前の行からの変化 | ts["salary"].diff(), ts["salary"].pct_change() |
| 値を1行下にずらす | ts["salary"].shift(1) |
| 累積合計 | ts["salary"].cumsum() |
| タイムゾーンの設定と変換 | ts.index.tz_localize("UTC").tz_convert("Europe/Oslo") |
グループ化と集計
groupby はキーで行を分割し、各グループに関数を適用して結果をまとめます。
| やりたいこと | コード |
|---|---|
| グループごとの平均 | df.groupby("city")["salary"].mean() |
| 複数の統計量を一度に | df.groupby("city")["salary"].agg(["mean", "max", "count"]) |
| 結果の列に名前を付ける | df.groupby("city").agg(avg_pay=("salary", "mean"), people=("name", "count")) |
| 2つの列でグループ化 | df.groupby(["city", "team"])["salary"].sum() |
| キーを列として残す | df.groupby("city", as_index=False)["salary"].mean() |
| グループごとの行数 | df.groupby("city").size() |
| グループの結果を全行に | df["city_avg"] = df.groupby("city")["salary"].transform("mean") |
| 一部のグループだけ残す | df.groupby("city").filter(lambda g: len(g) >= 2) |
| グループごとに最大値の行 | df.loc[df.groupby("city")["salary"].idxmax()] |
| グループごとの上位 n 行 | df.sort_values("salary", ascending=False).groupby("city").head(2) |
| グループ内で行に連番 | df.groupby("city").cumcount() |
| グループをループ | for city, group in df.groupby("city"):
print(city, len(group)) |
| フィルタ、集計、並べ替えを1つのチェーンで | (df.query("age > 30")
.groupby("city", as_index=False)
.agg(avg_pay=("salary", "mean"))
.sort_values("avg_pay", ascending=False)) |
ピボットと変形
縦長 (long) のデータは1観測につき1行です。横長 (wide) のデータは1つの変数を複数の列に広げます。
| やりたいこと | コード |
|---|---|
| ピボットテーブル | df.pivot_table(index="city", columns="team", values="salary", aggfunc="mean", fill_value=0) |
| 合計付きのピボットテーブル | df.pivot_table(index="city", values="salary", aggfunc="sum", margins=True) |
| 組み合わせを数える | pd.crosstab(df["city"], df["team"]) |
| 行ごとの割合 | pd.crosstab(df["city"], df["team"], normalize="index") |
| 横長から縦長へ | long = df.melt(id_vars="name", value_vars=["age", "salary"], var_name="field", value_name="value") |
| 縦長から横長へ | long.pivot(index="name", columns="field", values="value") |
| 内側のインデックスを列へ | df.groupby(["city", "team"])["salary"].sum().unstack(fill_value=0) |
| リストの要素ごとに1行 | pd.DataFrame({"id": [1, 2], "tags": [["a", "b"], ["c"]]}).explode("tags") |
| 列を one-hot エンコード | pd.get_dummies(df["team"], prefix="team") |
| 行と列を入れ替え | df.T |
DataFrame を結合する
concat はフレームを積み重ね、merge は SQL と同じようにキー列で結合します。
| やりたいこと | コード |
|---|---|
| 行を積み重ねる | pd.concat([df_2025, df_2026], ignore_index=True) |
| 横に並べる | pd.concat([left, right], axis=1) |
| キー列で結合 | orders.merge(customers, on="customer_id", how="left") |
| 結合の種類 | how="inner", "left", "right", "outer" |
| 名前の違うキー | orders.merge(users, left_on="customer_id", right_on="id") |
| 結合を検証し各行の出所を記録 | orders.merge(customers, on="customer_id", how="left", validate="many_to_one", indicator=True) |
| インデックスで結合 | left.join(right, how="inner") |
| 別のテーブルに一致しない行 | orders[~orders["customer_id"].isin(customers["customer_id"])] |
pandas でグラフを描く
pandas は Matplotlib で描画します。どのプロット呼び出しも Matplotlib の ax を返すので、そのまま見た目を調整できます。
| やりたいこと | コード |
|---|---|
| Series の折れ線グラフ | ts["salary"].plot() |
| 2つの列から折れ線グラフ | df.plot(x="date", y="salary") |
| 集計結果の棒グラフ | df.groupby("city")["salary"].mean().plot.bar() |
| 並べ替えた横棒グラフ | df["city"].value_counts().sort_values().plot.barh() |
| ヒストグラム | df["salary"].plot.hist(bins=20) |
| 散布図 | df.plot.scatter(x="age", y="salary") |
| グループごとの箱ひげ図 | df.boxplot(column="salary", by="city") |
| タイトルと軸ラベル | ax = df.plot(x="date", y="salary", title="Salary")
ax.set_ylabel("EUR") |
| グラフを表示または保存 | plt.show(), ax.figure.savefig("salary.png", dpi=150) |
pandas 3: 旧書式と今の書き方
古いチュートリアルからコピーしたコードは、pandas 3 ではエラーや警告になることがよくあります。代わりに pandas 3 の列の書き方を使いましょう。
| やりたいこと | pandas 3 | 旧書式 |
|---|---|---|
| 全セルに関数を適用 | df.map(f) | df.applymap(f) |
| 前の行の値で埋める | df.ffill() | df.fillna(method="ffill") |
| 行を追加 | pd.concat([df, new_rows]) | df.append(new_rows) |
| 月末でリサンプリング | ts["salary"].resample("ME").sum() | resample("M") |
| 1時間ごとの日付 | pd.date_range("2026-01-01", periods=24, freq="h") | freq="H" |
| 1つの値を設定 | df.loc[0, "age"] = 37 | df["age"][0] = 37 |
| フィルタした部分を変更 | high = df[df["salary"] > 5000]
high["salary"] = 0 | high = df[df["salary"] > 5000].copy() |
| 文字列の列かどうか | df["name"].dtype == "str" | df["name"].dtype == object |
データ分析の現場で毎日使う pandas のコードを、タスク別にまとめました。データの作成と読み込み、中身の確認、行の選択とフィルタ、列の追加、欠損値の処理、文字列と日付の操作、グループ集計、変形、結合、グラフ描画まで揃っています。各行は貼り付けてすぐ使える短いコードと、その動作を説明する一文で構成されています。
すべて Coddy で動いている pandas 3 向けに書いています。文字列の列には新しい str dtype が使われ、Copy-on-Write は常に有効です。applymap や fillna(method=...) のように削除された API は、旧書式の表にだけ載せています。例では name、city、team、age、salary、date、email の列を持つ DataFrame df を使います。Python 自体が初めての方は Python チートシート と Python プレイグラウンド から始めて、NumPy、Matplotlib、scikit-learn のチートシートもあわせて手元に置いておきましょう。
pandas チートシートのよくある質問
この pandas チートシートは無料ですか?
このチートシートはどの pandas バージョンに対応していますか?
str dtype が使われ、Copy-on-Write は常に有効です。pandas 3 で削除された呼び出し (applymap、fillna(method=...)、append、頻度エイリアスの M と H) は最後の表にだけ載せ、代わりの書き方と並べています。str dtype や Copy-on-Write に依存する行を除けば、ほぼすべてのコードは pandas 2.2 でも動きます。loc と iloc の違いは何ですか?
loc はラベル、つまりインデックスの値と列名で選択し、df.loc[0:2] のようなスライスは終端を含みます。iloc は Python のリストと同じく整数の位置で選択するので、df.iloc[0:2] は最初の2行を返し、終端は含みません。loc に条件を渡せば、行の絞り込みと列の選択を一度にできます: df.loc[df["age"] > 30, ["name"]]。複数の条件で DataFrame をフィルタするには?
&、またはは |、否定は ~ でつなぎます: df[(df["age"] > 30) & (df["city"] == "Oslo")]。Python の and と or は列全体には使えません。長い条件なら df.query("age > 30 and city == 'Oslo'") のほうが読みやすくなります。merge、join、concat の違いは何ですか?
merge は SQL の JOIN のようにキー列で2つの DataFrame を結合し、how="inner"、"left"、"right"、"outer" を指定できます。join はインデックスで結合するショートカットです。concat はキーをまったく照合せず、フレームを縦に積み重ねるか、axis=1 で横に並べます。代入しても DataFrame が変わらないのはなぜですか?
df["age"][0] = 37 のような連鎖代入は一時オブジェクトを変更するだけで、df はそのままです。代わりに loc の1回の呼び出しで書きましょう: df.loc[0, "age"] = 37。dropna や fillna などのメソッドも新しいオブジェクトを返すので、結果を代入してください。