- 技術 💻
pandasの使い方 逆引き81選|pandas 3.0の実行結果つき
pandasとは、表形式のデータ(DataFrame)を読み込み・抽出・集計・結合するためのPythonのライブラリです。Excelでやっている「絞り込み」「並べ替え」「ピボット」を、数行のコードで何度でも同じように再現できます。
この記事は、「やりたいこと」から引ける逆引き81項目です。すべて同じ6行のサンプルデータで実際に実行し、出力をコードのすぐ下に # コメントで載せています(そのまま貼っても動きます)。検証は pandas 3.0.6 / Python 3.13.7 です。2026年1月に出た pandas 3.0 で変わった点(Copy-on-Writeが既定になった、文字列が str 型になった、append がない)も、実際のエラー文・警告文と置き換え表でまとめました。
pandas逆引き 早見表
| やりたいこと | 主なコード | No. |
|---|---|---|
| CSV・Excelを読む/書く | pd.read_csv to_csv(index=False) pd.read_excel pd.ExcelWriter |
1〜7 |
| 文字化けを防ぐ | 読む encoding="cp932"/Excel向けに書く encoding="utf-8-sig" |
1, 4 |
| 中身をざっと見る | head tail shape columns value_counts |
8〜10 |
| 列・行を選ぶ | df["列"] df[["列1","列2"]] loc(名前)iloc(番号)at drop rename |
11〜17 |
| 条件で絞る・書き換える | df[条件] & | ~ isin between query str.contains loc[条件, 列] = |
18〜24 |
| 並べ替える・上位N件 | sort_values nlargest nsmallest |
25〜27 |
| 欠損値を扱う | isna().sum() dropna(subset=) fillna({列: 値}) ffill |
28〜32 |
| 型を変える | astype astype("Int64") pd.to_numeric(errors="coerce") |
33〜35 |
| 列を足す・計算する | df["新列"] = 式 assign pd.col np.where np.select map cut |
36〜42 |
| 文字列を加工する | str.strip str.split(expand=True) str.replace str.extract str.zfill |
43〜47 |
| 日付を扱う | pd.to_datetime .dt.year .dt.day_name() pd.Timedelta resample |
48〜52 |
| 集計する | groupby().agg() 名前=("列","関数") transform size nunique |
53〜58 |
| 縦横を変える | pivot_table crosstab melt pivot |
59〜62 |
| 表をつなぐ | merge(on=, how=) pd.concat |
63〜65 |
| 重複を扱う | duplicated drop_duplicates(subset=, keep=) |
66〜68 |
| 順位・前行との差・移動平均 | rank cumcount shift diff rolling cumsum |
69〜75 |
| 関数を当てる・変換する | apply(axis=1) DataFrame.map itertuples pipe to_dict to_sql |
76〜81 |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「pandasの使い方 逆引き81選|pandas 3.0の実行結果つき」
動かす前の準備(バージョンとサンプルデータ)
pandasは pip install pandas で入ります。Excelを扱うときは openpyxl も入れます。
pip install pandas openpyxl
python -c "import pandas as pd; print(pd.__version__)"
# 3.0.6
pandas 3.0 は Python 3.11 以上が必要です。以降のコードは、すべて次のサンプル(注文データ6行、qty に欠損が1つ)を作った直後から実行しています。各コードブロックは、このサンプルを作り直してから実行した結果です。
import pandas as pd
import numpy as np
df = pd.DataFrame({
"order_id": [101, 102, 103, 104, 105, 106],
"date": ["2026-04-01", "2026-04-01", "2026-04-02",
"2026-04-03", "2026-04-03", "2026-04-05"],
"member": ["sato", "suzuki", "sato", "takahashi", "suzuki", "tanaka"],
"item": ["note", "pen", "pen", "file", "note", "pen"],
"qty": [3, 10, 5, np.nan, 2, 8],
"price": [120, 80, 80, 300, 120, 80],
})
print(df)
# order_id date member item qty price
# 0 101 2026-04-01 sato note 3.0 120
# 1 102 2026-04-01 suzuki pen 10.0 80
# 2 103 2026-04-02 sato pen 5.0 80
# 3 104 2026-04-03 takahashi file NaN 300
# 4 105 2026-04-03 suzuki note 2.0 120
# 5 106 2026-04-05 tanaka pen 8.0 80
pandas 3.0で変わった書き方(置き換え表と実際の警告)
pandas 2.x 向けに書かれたコードが動かないときは、まずこの表を確認してください。左の書き方は pandas 3.0.6 で実行すると右のエラー・結果になります。
| 以前の書き方 | pandas 3.0での結果 | 置き換え |
|---|---|---|
df.append(行) |
AttributeError(2.0で削除) |
pd.concat([df, new], ignore_index=True)(No.65) |
df.applymap(f) |
AttributeError |
df.map(f)(No.77) |
df.fillna(method="ffill") |
TypeError(引数がない) |
df.ffill() / df.bfill() |
df[条件]["列"] = 値(連鎖代入) |
ChainedAssignmentError 警告、元は変わらない |
df.loc[条件, "列"] = 値(No.24) |
df["列"].fillna(0, inplace=True) |
同じ警告、元は変わらない | df["列"] = df["列"].fillna(0) |
s = df["列"]; s.iloc[0] = 99 |
元の df は変わらない(2.xでは変わった) | df.loc[0, "列"] = 99 |
文字列の列の型 object |
str 型になる |
判定は pd.api.types.is_string_dtype |
groupby(..., axis=1) |
TypeError |
df.T.groupby(...) などで向きを変える |
実際に動かした結果です。
import pandas as pd
import numpy as np
df = pd.DataFrame({"item": ["note", "pen", "file"], "qty": [3, 10, np.nan]})
try:
df.append({"item": "pen", "qty": 1}, ignore_index=True)
except AttributeError as e:
print("AttributeError:", e)
df[df["item"] == "pen"]["qty"] = 0 # 連鎖代入
print(df["qty"].tolist())
AttributeError: 'DataFrame' object has no attribute 'append'
dep2.py:11: ChainedAssignmentError: A value is being set on a copy of a DataFrame or Series through chained assignment.
Such chained assignment never works to update the original DataFrame or Series, because the intermediate object on which we are setting values always behaves as a copy (due to Copy-on-Write).
Try using '.loc[row_indexer, col_indexer] = value' instead, to perform the assignment in a single step.
See the documentation for a more detailed explanation: https://pandas.pydata.org/pandas-docs/stable/user_guide/copy_on_write.html#chained-assignment
df[df["item"] == "pen"]["qty"] = 0 # 連鎖代入
[3.0, 10.0, nan]
(ファイルのパスだけ短くしています。)
qty は10のままです。pandas 2.x では同じコードで SettingWithCopyWarning が出ていましたが、3.0 では Copy-on-Write(取り出した一部は常に「コピー」として振る舞い、書き換えが元に伝わらない仕組み)が既定になり、警告名も変わりました。値を書き換えるときは df.loc[行, 列] = 値 の1回で書くのが正解です。
同じコードを pandas 2.3.3 と 3.0.6 で比べると、違いがはっきりします。
df = pd.DataFrame({"item": ["note", "pen", "file"], "qty": [3, 10, np.nan]})
print(df.dtypes.astype(str).to_dict())
s = df["qty"]
s.iloc[0] = 99
print(df["qty"].tolist())
try:
df.loc[0, "item"] = 123
print("代入できた")
except TypeError as e:
print("TypeError:", e)
| 出力 | pandas 2.3.3 | pandas 3.0.6 |
|---|---|---|
| 文字列列の型 | {'item': 'object', ...} |
{'item': 'str', ...} |
s.iloc[0] = 99 のあとの df["qty"] |
SettingWithCopyWarning が出て [99.0, 10.0, nan](元も変わる) |
[3.0, 10.0, nan](元は変わらない) |
str 列に数値を代入 |
代入できた |
TypeError: Invalid value '123' for dtype 'str'. Value should be a string or missing value, got 'int' instead. |
str 型の列には文字列と欠損値しか入りません。数値も入れたいときは df["item"] = df["item"].astype(object) で型を戻すか、str(123) で文字列にしてから入れます。なお str 型は PyArrow が入っていればPyArrow、なければPythonの文字列で保持されます(今回の環境は後者で StringDtype(storage='python') と表示されます)。
読み込み・書き出し(CSV・Excel・文字コード)
# ▼1. CSVに書き出す(Excel向けBOM付き)
df.to_csv("orders.csv", index=False, encoding="utf-8-sig")
# ▼2. CSVを読み込む
orders = pd.read_csv("orders.csv")
print(orders.head(2))
# order_id date member item qty price
# 0 101 2026-04-01 sato note 3.0 120
# 1 102 2026-04-01 suzuki pen 10.0 80
# ▼3. 列・型・日付を指定して読む
orders = pd.read_csv("orders.csv", usecols=["order_id", "date", "qty"],
dtype={"order_id": "string"}, parse_dates=["date"])
print(orders.dtypes.astype(str).to_dict())
# {'order_id': 'string', 'date': 'datetime64[us]', 'qty': 'float64'}
# ▼4. Shift_JIS(cp932)のCSVを読み書き
jp = pd.DataFrame({"品名": ["ノート", "ペン"], "数量": [3, 10]})
jp.to_csv("jp.csv", index=False, encoding="cp932")
try:
pd.read_csv("jp.csv") # 既定はUTF-8
except UnicodeDecodeError as e:
print("UnicodeDecodeError:", str(e)[:48])
print(pd.read_csv("jp.csv", encoding="cp932"))
# UnicodeDecodeError: 'utf-8' codec can't decode byte 0x95 in position
# 品名 数量
# 0 ノート 3
# 1 ペン 10
# ▼5. Excelに複数シートで書き出す
with pd.ExcelWriter("orders.xlsx") as w: # 要 openpyxl
df.to_excel(w, sheet_name="orders", index=False)
df.groupby("item")["qty"].sum().to_excel(w, sheet_name="by_item")
# ▼6. Excelをシート指定で読む
print(pd.read_excel("orders.xlsx", sheet_name=None).keys())
# dict_keys(['orders', 'by_item'])
# ▼7. 大きいCSVを分けて読む
for chunk in pd.read_csv("orders.csv", chunksize=4):
print(len(chunk), chunk["order_id"].tolist())
# 4 [101, 102, 103, 104]
# 2 [105, 106]
データの中身を確認する
# ▼8. 先頭・末尾を見る
print(df.tail(1))
# order_id date member item qty price
# 5 106 2026-04-05 tanaka pen 8.0 80
# ▼9. 行数・列数・列名
print(df.shape, df.columns.tolist())
# (6, 6) ['order_id', 'date', 'member', 'item', 'qty', 'price']
# ▼10. 値ごとの件数
print(df["item"].value_counts().to_dict())
# {'pen': 3, 'note': 2, 'file': 1}
行・列を選択する
loc は名前(行ラベル・列名)、iloc は番号で選びます。
# ▼11. 1列(Series)
print(df["member"].head(2))
# 0 sato
# 1 suzuki
# Name: member, dtype: str
# ▼12. 複数列(DataFrame)
print(df[["member", "qty"]].head(2))
# member qty
# 0 sato 3.0
# 1 suzuki 10.0
# ▼13. 行番号で選ぶ
print(df.iloc[1:3, 0:3])
# order_id date member
# 1 102 2026-04-01 suzuki
# 2 103 2026-04-02 sato
# ▼14. ラベルで選ぶ
print(df.loc[[0, 2], ["order_id", "item"]])
# order_id item
# 0 101 note
# 2 103 pen
# ▼15. 1セルの値
print(df.at[1, "member"], df.iat[1, 4])
# suzuki 10.0
# ▼16. 列を削除
print(df.drop(columns=["date", "price"]).columns.tolist())
# ['order_id', 'member', 'item', 'qty']
# ▼17. 列名を変更
print(df.rename(columns={"qty": "数量"}).columns.tolist())
# ['order_id', 'date', 'member', 'item', '数量', 'price']
条件で抽出する
条件を &(かつ)|(または)でつなぐときは、1つずつ括弧で囲みます。and or は使えません。
# ▼18. 条件1つ
print(df[df["qty"] >= 5][["order_id", "member", "qty"]])
# order_id member qty
# 1 102 suzuki 10.0
# 2 103 sato 5.0
# 5 106 tanaka 8.0
# ▼19. AND・OR・NOT
print(df[(df["item"] == "pen") & (df["qty"] > 5)]["order_id"].tolist())
print(df[(df["item"] == "file") | ~(df["price"] < 120)]["order_id"].tolist())
# [102, 106]
# [101, 104, 105]
# ▼20. いずれかに一致(IN)
print(df[df["member"].isin(["sato", "tanaka"])]["order_id"].tolist())
# [101, 103, 106]
# ▼21. 範囲(BETWEEN)
print(df[df["qty"].between(3, 8)]["order_id"].tolist())
# [101, 103, 106]
# ▼22. 文字列で条件を書く
limit = 5
print(df.query("item == 'pen' and qty >= @limit")["order_id"].tolist())
# [102, 103, 106]
# ▼23. 部分一致(LIKE)
print(df[df["member"].str.contains("su")]["order_id"].tolist())
# [102, 105]
# ▼24. 条件に合う行の値を書き換える
df.loc[df["item"] == "pen", "price"] = 90
print(df["price"].tolist())
# [120, 90, 90, 300, 120, 90]
並び替え・上位N件
# ▼25. 降順に並べ替え
print(df.sort_values("qty", ascending=False)[["order_id", "qty"]].head(2))
# order_id qty
# 1 102 10.0
# 5 106 8.0
# ▼26. 複数列で並べ替え
print(df.sort_values(["item", "qty"], ascending=[True, False])["order_id"].tolist())
# [104, 101, 105, 102, 106, 103]
# ▼27. 上位N件・下位N件
print(df.nlargest(2, "qty")["order_id"].tolist(), df.nsmallest(1, "qty")["order_id"].tolist())
# [102, 106] [105]
欠損値(NaN)を扱う
まず isna().sum() で欠損の数を見てから、削除するか埋めるかを決めます。
# ▼28. 列ごとの欠損数
print(df.isna().sum().to_dict())
# {'order_id': 0, 'date': 0, 'member': 0, 'item': 0, 'qty': 1, 'price': 0}
# ▼29. 欠損のある行を抽出
print(df[df["qty"].isna()])
# order_id date member item qty price
# 3 104 2026-04-03 takahashi file NaN 300
# ▼30. 欠損のある行を削除
print(df.dropna(subset=["qty"]).shape)
# (5, 6)
# ▼31. 列ごとに値で埋める
print(df.fillna({"qty": 0})["qty"].tolist())
# [3.0, 10.0, 5.0, 0.0, 2.0, 8.0]
# ▼32. 平均・前の値で埋める
print(df["qty"].fillna(df["qty"].mean()).tolist())
print(df["qty"].ffill().tolist())
# [3.0, 10.0, 5.0, 5.6, 2.0, 8.0]
# [3.0, 10.0, 5.0, 5.0, 2.0, 8.0]
型を変換する
# ▼33. 型を変える
print(df["order_id"].astype(str).dtype, df["price"].astype(float).dtype)
# str float64
# ▼34. 欠損を含む整数列
print(df["qty"].astype("Int64").tolist())
# [3, 10, 5, <NA>, 2, 8]
# ▼35. 変換できない値はNaNにする
print(pd.to_numeric(pd.Series(["10", "abc", ""]), errors="coerce").tolist())
# [10.0, nan, nan]
列を追加・計算する
# ▼36. 列同士の計算で列を追加
df["amount"] = df["qty"] * df["price"]
print(df[["qty", "price", "amount"]].head(2))
# qty price amount
# 0 3.0 120 360.0
# 1 10.0 80 800.0
# ▼37. 元を変えずに列を追加
print(df.assign(tax=lambda d: d["price"] * 0.1)["tax"].tolist())
# [12.0, 8.0, 8.0, 30.0, 12.0, 8.0]
# ▼38. pd.colで列を追加(3.0+)
print(df.assign(t=pd.col("qty") * pd.col("price"))["t"].tolist())
# [360.0, 800.0, 400.0, nan, 240.0, 640.0]
# ▼39. 条件で2つに振り分け(IF)
print(np.where(df["qty"] >= 5, "L", "S").tolist())
# ['S', 'L', 'L', 'S', 'S', 'L']
# ▼40. 3つ以上に振り分け(CASE WHEN)
print(np.select([df["qty"] >= 8, df["qty"] >= 3], ["A", "B"], default="C").tolist())
# ['B', 'A', 'B', 'C', 'C', 'A']
# ▼41. 辞書で値を置き換え
print(df["item"].map({"note": "ノート", "pen": "ペン", "file": "ファイル"}).tolist())
print(df["item"].replace({"pen": "ballpen"}).tolist())
# ['ノート', 'ペン', 'ペン', 'ファイル', 'ノート', 'ペン']
# ['note', 'ballpen', 'ballpen', 'file', 'note', 'ballpen']
# ▼42. 数値を区間に分ける
print(pd.cut(df["qty"], bins=[0, 3, 6, 10], labels=["少", "中", "多"]).tolist())
# ['少', '多', '中', nan, '少', '多']
文字列を操作する
# ▼43. 前後の空白削除・小文字化
print(pd.Series([" Note ", "PEN"]).str.strip().str.lower().tolist())
# ['note', 'pen']
# ▼44. 区切って列に分ける
print(df["date"].str.split("-", expand=True).head(2))
# 0 1 2
# 0 2026 04 01
# 1 2026 04 01
# ▼45. 置換(正規表現も可)
print(pd.Series(["A-01", "B-12"]).str.replace(r"\d+", "#", regex=True).tolist())
# ['A-#', 'B-#']
# ▼46. 正規表現で取り出す
print(pd.Series(["A-01", "B-12"]).str.extract(r"([A-Z])-(\d+)"))
# 0 1
# 0 A 01
# 1 B 12
# ▼47. 列をつなげる・ゼロ埋め
print((df["member"] + ":" + df["item"]).head(2).tolist())
print(df["order_id"].astype(str).str.zfill(6).head(2).tolist())
# ['sato:note', 'suzuki:pen']
# ['000101', '000102']
日付を扱う
# ▼48. 文字列を日付型に
df["date"] = pd.to_datetime(df["date"])
print(df["date"].dtype)
# datetime64[us]
# ▼49. 年・月・曜日を取り出す
print(df["date"].dt.month.tolist(), df["date"].dt.day_name().head(2).tolist())
# [4, 4, 4, 4, 4, 4] ['Wednesday', 'Wednesday']
# ▼50. 期間で絞り込む
print(df[(df["date"] >= "2026-04-02") & (df["date"] < "2026-04-04")]["order_id"].tolist())
# [103, 104, 105]
# ▼51. 日付の差・日数を足す
print((df["date"] - df["date"].min()).dt.days.tolist())
print((df["date"] + pd.Timedelta(days=7)).dt.strftime("%m/%d").head(2).tolist())
# [0, 0, 1, 2, 2, 4]
# ['04/08', '04/08']
# ▼52. 日ごとに集計(抜けた日も出す)
print(df.set_index("date").resample("D")["qty"].sum())
# date
# 2026-04-01 13.0
# 2026-04-02 5.0
# 2026-04-03 2.0
# 2026-04-04 0.0
# 2026-04-05 8.0
# Freq: D, Name: qty, dtype: float64
集計する(groupby・agg)
# ▼53. グループごとの合計
print(df.groupby("item")["qty"].sum().to_dict())
# {'file': 0.0, 'note': 5.0, 'pen': 23.0}
# ▼54. 複数の集計を一度に
print(df.groupby("item")["qty"].agg(["sum", "mean", "count"]).round(1))
# sum mean count
# item
# file 0.0 NaN 0
# note 5.0 2.5 2
# pen 23.0 7.7 3
# ▼55. 集計列に名前を付ける
print(df.groupby("member", as_index=False).agg(
orders=("order_id", "count"), qty_total=("qty", "sum")))
# member orders qty_total
# 0 sato 2 8.0
# 1 suzuki 2 12.0
# 2 takahashi 1 0.0
# 3 tanaka 1 8.0
# ▼56. 件数・ユニーク数
print(df.groupby("item").size().to_dict(), df.groupby("item")["member"].nunique().to_dict())
# {'file': 1, 'note': 2, 'pen': 3} {'file': 1, 'note': 2, 'pen': 3}
# ▼57. 集計値を元の行に戻す
df["share"] = (df["qty"] / df.groupby("item")["qty"].transform("sum")).round(2)
print(df[["item", "qty", "share"]].head(3))
# item qty share
# 0 note 3.0 0.60
# 1 pen 10.0 0.43
# 2 pen 5.0 0.22
# ▼58. 集計後に絞る(HAVING)
g = df.groupby("member")["qty"].sum()
print(g[g >= 8].to_dict())
# {'sato': 8.0, 'suzuki': 12.0, 'tanaka': 8.0}
ピボット・縦横変換
# ▼59. ピボットテーブル
print(df.pivot_table(index="member", columns="item", values="qty",
aggfunc="sum", fill_value=0))
# item file note pen
# member
# sato 0.0 3.0 5.0
# suzuki 0.0 2.0 10.0
# takahashi 0.0 0.0 0.0
# tanaka 0.0 0.0 8.0
# ▼60. クロス集計(件数)
print(pd.crosstab(df["member"], df["item"]).head(2))
# item file note pen
# member
# sato 0 1 1
# suzuki 0 1 1
# ▼61. 横持ち→縦持ち
wide = pd.DataFrame({"member": ["sato", "suzuki"], "4月": [3, 12], "5月": [5, 0]})
long = wide.melt(id_vars="member", var_name="month", value_name="qty")
print(long)
# member month qty
# 0 sato 4月 3
# 1 suzuki 4月 12
# 2 sato 5月 5
# 3 suzuki 5月 0
# ▼62. 縦持ち→横持ち
print(long.pivot(index="member", columns="month", values="qty"))
# month 4月 5月
# member
# sato 3 5
# suzuki 12 0
結合する(merge・concat)
indicator=True を付けると、結合できなかった行(left_only)がすぐわかります。
teams = pd.DataFrame({"member": ["sato", "suzuki", "yamada"], "team": ["A", "B", "C"]})
# ▼63. キーで内部結合(INNER JOIN)
print(df.merge(teams, on="member")[["order_id", "member", "team"]].head(3))
# order_id member team
# 0 101 sato A
# 1 102 suzuki B
# 2 103 sato A
# ▼64. 左外部結合+結合結果の確認
m = df.merge(teams, on="member", how="left", indicator=True)
print(m[["order_id", "team", "_merge"]].tail(3))
# order_id team _merge
# 3 104 NaN left_only
# 4 105 B both
# 5 106 NaN left_only
# ▼65. 行を追加(appendの代わり)
new = pd.DataFrame([{"order_id": 107, "member": "sato", "item": "file", "qty": 1, "price": 300}])
print(pd.concat([df, new], ignore_index=True).tail(2))
# order_id date member item qty price
# 5 106 2026-04-05 tanaka pen 8.0 80
# 6 107 NaN sato file 1.0 300
重複を扱う
# ▼66. 重複を見つける
print(df.duplicated(subset=["member"]).tolist())
# [False, False, True, False, True, False]
# ▼67. 重複をすべて表示
print(df[df.duplicated(subset=["member"], keep=False)]["order_id"].tolist())
# [101, 102, 103, 105]
# ▼68. 重複を削除(最後を残す)
print(df.drop_duplicates(subset=["member"], keep="last")["order_id"].tolist())
# [103, 104, 105, 106]
ランキング・ウィンドウ関数
# ▼69. 順位(RANK)
print(df["qty"].rank(ascending=False, method="min").tolist())
# [4.0, 1.0, 3.0, nan, 5.0, 2.0]
# ▼70. グループ内連番(ROW_NUMBER)
print((df.groupby("item").cumcount() + 1).tolist())
# [1, 1, 2, 1, 2, 3]
# ▼71. グループ内順位
print(df.groupby("item")["qty"].rank(ascending=False).tolist())
# [1.0, 1.0, 3.0, nan, 2.0, 2.0]
# ▼72. グループごとに上位1件
print(df.sort_values("qty", ascending=False).groupby("item").head(1)[["item", "order_id", "qty"]])
# item order_id qty
# 1 pen 102 10.0
# 0 note 101 3.0
# 3 file 104 NaN
# ▼73. 移動平均
print(df["price"].rolling(window=3).mean().round(1).tolist())
# [nan, nan, 93.3, 153.3, 166.7, 166.7]
# ▼74. 前の行との差・増減率(LAG)
s = pd.Series([100, 120, 90, 135])
print(pd.DataFrame({"v": s, "prev": s.shift(1), "diff": s.diff(), "pct": s.pct_change().round(2)}))
# v prev diff pct
# 0 100 NaN NaN NaN
# 1 120 100.0 20.0 0.20
# 2 90 120.0 -30.0 -0.25
# 3 135 90.0 45.0 0.50
# ▼75. グループごとの累積和
print(df.groupby("member")["qty"].cumsum().tolist())
# [3.0, 10.0, 8.0, nan, 12.0, 8.0]
apply・ループ・変換
# ▼76. 行ごとに関数を適用
print(df.apply(lambda r: f"{r['member']}-{r['item']}", axis=1).head(2).tolist())
# ['sato-note', 'suzuki-pen']
# ▼77. 全セルに関数を適用
print(df[["qty", "price"]].map(lambda v: f"{v:,.0f}").head(2))
# qty price
# 0 3 120
# 1 10 80
# ▼78. 1行ずつループ
for row in df.head(2).itertuples(index=False):
print(row.order_id, row.member, row.qty)
# 101 sato 3.0
# 102 suzuki 10.0
# ▼79. 処理をつなげる
def add_amount(d):
return d.assign(amount=d["qty"] * d["price"])
print(df.pipe(add_amount).dropna().groupby("item")["amount"].sum().to_dict())
# {'note': 600.0, 'pen': 1840.0}
# ▼80. 辞書のリスト・リストに変換
print(df.head(2)[["order_id", "qty"]].to_dict(orient="records"))
print(df["item"].unique().tolist())
# [{'order_id': 101, 'qty': 3.0}, {'order_id': 102, 'qty': 10.0}]
# ['note', 'pen', 'file']
# ▼81. SQLで読む・テーブルに書く
import sqlite3
con = sqlite3.connect(":memory:")
df.to_sql("orders", con, index=False)
print(pd.read_sql("SELECT item, SUM(qty) AS qty FROM orders GROUP BY item", con))
# item qty
# 0 file NaN
# 1 note 5.0
# 2 pen 23.0
SQLとpandasの対応表
SQLに慣れている人は、この表で対応を探すと早いです。
| SQL | pandas | No. |
|---|---|---|
SELECT a, b |
df[["a", "b"]] |
12 |
WHERE qty >= 5 AND ... |
df[(条件1) & (条件2)] / df.query("...") |
18, 19, 22 |
WHERE x IN (...) / BETWEEN / LIKE |
isin / between / str.contains |
20, 21, 23 |
ORDER BY qty DESC |
sort_values("qty", ascending=False) |
25 |
LIMIT 2 |
head(2) / nlargest(2, "qty") |
8, 27 |
SELECT DISTINCT |
drop_duplicates() / unique() |
68, 80 |
GROUP BY ... SUM() |
groupby("item")["qty"].sum() |
53 |
COUNT(*) / COUNT(DISTINCT x) |
size() / nunique() |
56 |
HAVING SUM(qty) >= 8 |
集計結果 g[g >= 8] |
58 |
CASE WHEN ... END |
np.where / np.select |
39, 40 |
INNER JOIN / LEFT JOIN |
merge(how="inner") / merge(how="left") |
63, 64 |
UNION ALL / INSERT |
pd.concat([...], ignore_index=True) |
65 |
UPDATE ... SET ... WHERE |
df.loc[条件, "列"] = 値 |
24 |
ROW_NUMBER() OVER (PARTITION BY) |
groupby().cumcount() + 1 |
70 |
RANK() OVER (ORDER BY) |
rank(method="min") |
69 |
LAG(x) |
shift(1) |
74 |
SUM(x) OVER (PARTITION BY) |
groupby().transform("sum") |
57 |
1点だけ挙動が違います。No.53 と No.81 を見比べると、qty がすべて欠損の file グループは、pandasの sum() では 0.0、SQLの SUM() では NULL(読み込むと NaN)です。欠損だけのグループを欠損のままにしたいときは groupby("item")["qty"].sum(min_count=1) と書きます。
よくある質問
Q. SettingWithCopyWarning の対処法を調べたのに、警告が出ません。
A. pandas 3.0 でこの警告は廃止され、連鎖代入には ChainedAssignmentError が出るようになりました。どちらの場合も、df.loc[条件, "列"] = 値 の1回で書くのが解決策です。
Q. loc と iloc はどちらを使えばよいですか?
A. 列名や条件で選ぶなら loc、何番目かで選ぶなら iloc です。loc[0:2] は2を含み、iloc[0:2] は2を含まない点に気をつけます。並べ替えのあとなど行名が番号とずれたときは、reset_index(drop=True) で振り直すと扱いやすくなります。
Q. apply は遅いと聞きました。使ってはいけませんか?
A. 使ってかまいません。ただ、列同士の四則演算(No.36)や np.where(No.39)のような「列ごとにまとめて計算する書き方」のほうが速く、行数が多いと差が大きくなります。まずまとめて書けないかを考え、どうしても行ごとの処理が必要なときに apply(axis=1) を使うのがおすすめです。
Q. pandas 2.x のままのプロジェクトでも、この記事のコードは使えますか?
A. はい。81項目すべてを pandas 2.3.3 でも実行し、No.38 の pd.col(3.0で追加、2.3.3では AttributeError)以外は同じ結果になることを確認しました。違いは表示だけで、文字列の列が object、日付が datetime64[ns](3.0は datetime64[us])と出ます。
まとめ
- pandasの操作は「選ぶ(loc/iloc)→ 絞る(条件)→ まとめる(groupby/pivot_table)→ つなぐ(merge/concat)」の4つでほとんど表せる
- CSVの文字化けは読み込み
encoding="cp932"、Excel向け書き出しencoding="utf-8-sig"で解決できる - 条件は
&|~と括弧、複数値はisin、範囲はbetween - pandas 3.0 は Copy-on-Write が既定。書き換えは
df.loc[条件, "列"] = 値の1回で appendはpd.concat、applymapはDataFrame.map、fillna(method=)はffillに置き換える- 文字列の列は
str型になり、文字列と欠損値だけが入る - SQLの
GROUP BY・JOIN・ROW_NUMBERもgroupby・merge・cumcountで書ける
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「pandasの使い方 逆引き81選|pandas 3.0の実行結果つき」
株式会社RJCでは、データを読み解き、確かめながら形にする力を、プロジェクトの中で仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。