
リード(結論)
基礎を終えたら次は実務の現場で頻出する処理を“型”で覚える段階です。本記事は、pandas 2.x を前提に、欠損・外れ値・結合・ウィンドウ関数・時系列・カテゴリ処理・集計の自動化・大規模データの分割処理・テスト/再現性まで、現場で即使えるレシピを体系化しました。月末ミニプロジェクトのレビュー観点チェックリスト付き。週10時間×2〜3週で“回せる前処理”を手に入れます。
現場でつまずく3大ポイント
- 結合の地雷:キーの重複や型不一致に気づかず、行が爆増/欠落する。
- 時系列/ウィンドウ:
rolling
/expanding
/shift
の使い分けが曖昧で誤学習に繋がる。 - 品質保証:Notebookが一度は動いても、翌週に再現できない(データ差分/前処理の暗黙仕様)。
解決策は、事前チェック→明示的な型/キー管理→関数化→簡易テストのルーチン化。本記事の“型”を丸ごと持ち帰ってください。
現場10年の学びから
筆者(ふみと)は大手企業のデータサイエンティスト/マーケティングサイエンティスト歴10年、案件100件超。精度1%よりも、再現性/読みやすさ/速度で勝負が決まる場面が多い。ここでは失敗しない順番とチェックポイントを余すことなく共有します。
[内部リンク:【自己紹介】大手企業データサイエンティスト10年のキャリアと学び]
実体験メモ
「月次レポートの数値が前週とズレた」——原因はmerge
前のキー重複。以降、validate="many_to_one"
を絶対ルールにしてから事故はゼロになりました。
pandas実務レシピ 12パターン(Python 3.10+ / pandas 2.x)
以降は import pandas as pd
を前提に進めます。
サンプルデータ
orders.csv
:order_id, order_date, customer_id, sku, qty, unit_price, store
customers.csv
:customer_id, gender, age, area, signup_date
calendar.csv
:date, dow, holiday_flag
1) 事前チェック(型・重複・分布)
import pandas as pd
def read\_orders(path: str) -> pd.DataFrame:
return pd.read\_csv(
path,
parse\_dates=\["order\_date"],
dtype={"customer\_id": "Int64", "sku": "string", "store": "category"},
na\_values=\["", "NA", "null"]
)
df = read\_orders("orders.csv")
# 基本プロファイル(軽量版)
print(df.info())
print(df.describe(numeric\_only=True))
print(df.isna().mean().sort\_values(ascending=False).head(10)) # 欠損率
# キー重複の検査(order\_idがユニークか)
assert not df\["order\_id"].duplicated().any(), "order\_id に重複があります"
判断基準:読み込み時に型を決めると後工程が安定。キーはassertで即落とす。
2) 欠損処理の型(意味を保つ)
from statistics import median
num\_cols = \["qty", "unit\_price"]
# 数値:中央値で補完(分布の歪みが小さめ)
df\[num\_cols] = df\[num\_cols].apply(lambda s: s.fillna(median(s.dropna())))
# カテゴリ:"Unknown" で明示(分析時にフィルタ可能)
df\["store"] = df\["store"].cat.add\_categories(\["Unknown"]).fillna("Unknown")
判断基準:補完の根拠をコメントで残す(レビューでの誤解を防止)。
3) 外れ値の検知とWinsorize(軽量)
import numpy as np
amount = df\["qty"] \* df\["unit\_price"]
q\_low, q\_hi = amount.quantile(\[0.01, 0.99])
df\["amount\_clip"] = amount.clip(lower=q\_low, upper=q\_hi)
# 参考:z-scoreで粗い検知
z = (amount - amount.mean()) / amount.std(ddof=0)
df\["is\_outlier"] = (z.abs() > 3)
判断基準:指標のロバスト性とビジネス影響を天秤に。クリッピングはレポートに注記。
4) 結合前のキー健全性チェック
cust = pd.read_csv(
"customers.csv",
dtype={"customer_id": "Int64", "gender": "category", "area": "category"},
parse_dates=["signup_date"]
)
# 参照キーの重複チェック(customer\_idは一意か)
dups = cust\["customer\_id"].duplicated(keep=False)
assert not dups.any(), "customers: customer\_id が重複しています"
# 型合わせ(orders側と一致)
assert df\["customer\_id"].dtype == cust\["customer\_id"].dtype
# 安全な左結合(受注に顧客属性を付与)
joined = df.merge(cust, on="customer\_id", how="left", validate="many\_to\_one")
判断基準:validate="many_to_one"
で事故防止。一致しない型は明示変換してから結合。
5) カレンダーテーブルの活用(完全な時系列)
cal = pd.read_csv("calendar.csv", parse_dates=["date"], dtype={"dow": "int8", "holiday_flag": "int8"})
# 受注を日次集約
daily = (
df.assign(date=df\["order\_date"].dt.date)
.groupby("date", as\_index=False)
.agg(sales=(lambda d: (d\["qty"]\*d\["unit\_price"]).sum()),
orders=("order\_id", "nunique"))
)
# カレンダーに結合して“穴のない”日次へ
full = cal.merge(daily, on="date", how="left").fillna({"sales": 0, "orders": 0})
判断基準:観測のない日を含めておくとrolling/resample
や可視化が滑らか。
6) ウィンドウ関数(rolling/expanding/shift)
full = full.sort_values("date").reset_index(drop=True)
# 7日移動平均と前年比(365日シフト例)
full\["ma7"] = full\["sales"].rolling(window=7, min\_periods=1).mean()
full\["sales\_prev\_year"] = full\["sales"].shift(365)
full\["yoy"] = (full\["sales"] - full\["sales\_prev\_year"]) / full\["sales\_prev\_year"]
判断基準:因果汚染を避けるため、未来情報(リーク)が混ざらない順序で計算する。
7) カテゴリ処理(order/target encodingの前室)
# カテゴリの頻度で並べ替え(Top-Nを固定、その他は"Other")
TOP_N = 20
freq = df["sku"].value_counts()
major = freq.index[:TOP_N]
df["sku_top"] = df["sku"].where(df["sku"].isin(major), other="Other")
# 頻度エンコード(単純版)
sku\_freq = df\["sku"].value\_counts(normalize=True)
df\["sku\_freq"] = df\["sku"].map(sku\_freq)
判断基準:説明可能性と汎化のバランス。学習用途では[内部リンク:scikit-learn基礎]に接続。
8) グループ集計の自動化(辞書で定義→一括適用)
AGG_DEF = {
"amount": ["sum", "mean", "median"],
"qty": ["sum", "mean"],
}
df\["amount"] = df\["qty"] \* df\["unit\_price"]
agg = (
df.groupby(\[df\["order\_date"].dt.to\_period("M").astype(str), "store"], as\_index=False)
.agg(\*\*{f"{col}\_{fn}": (col, fn) for col, fns in AGG\_DEF.items() for fn in fns})
)
判断基準:定義をデータ化しておくと変更に強い。命名規則を統一。
9) メソッドチェーン+pipe
で“読みやすく速い”前処理
from typing import Callable
DF = pd.DataFrame
def add\_amount(d: DF) -> DF:
return d.assign(amount=d\["qty"] \* d\["unit\_price"]) # type: ignore
def add\_month(d: DF) -> DF:
return d.assign(ym=d\["order\_date"].dt.to\_period("M").astype(str))
def filter\_valid(d: DF) -> DF:
return d.query("qty > 0 and unit\_price > 0")
monthly = (
df.pipe(filter\_valid)
.pipe(add\_amount)
.pipe(add\_month)
.groupby(\["ym", "store"], as\_index=False)
.agg(sales=("amount", "sum"), orders=("order\_id", "nunique"))
)
判断基準:処理は小さな純関数に分割。Notebookでもテスト可能になる。
10) 大規模データ:分割読み込み(chunksize)と段階保存
chunks = pd.read_csv("orders.csv", chunksize=200_000, parse_dates=["order_date"])
acc = \[]
for ch in chunks:
ch = ch.query("qty > 0 and unit\_price > 0").assign(amount=ch\["qty"] \* ch\["unit\_price"]) # type: ignore
acc.append(
ch.groupby(ch\["order\_date"].dt.to\_period("M").astype(str), as\_index=False)
.agg(sales=("amount", "sum"))
)
monthly\_big = pd.concat(acc, ignore\_index=True).groupby("order\_date", as\_index=False).sum()
monthly\_big.to\_parquet("monthly\_sales.parquet", index=False) # 段階保存
判断基準:中間成果をParquetで保存して、再実行時間を短縮。集約は早めに。
11) 品質保証:データ検査とpytestの最小セット
data_checks.py
# data_checks.py
import pandas as pd
def check\_orders(df: pd.DataFrame) -> None:
assert (df\["qty"] >= 0).all(), "qty に負値があります"
assert (df\["unit\_price"] >= 0).all(), "unit\_price に負値があります"
assert df\["order\_id"].is\_unique, "order\_id が一意ではありません"
test_data_checks.py(pytest)
# test_data_checks.py
import pandas as pd
from data_checks import check_orders
def test\_check\_orders\_ok():
d = pd.DataFrame({"order\_id": \[1,2], "qty": \[1,2], "unit\_price": \[100,200]})
check\_orders(d) # 例外が出なければOK
判断基準:壊れたら即落ちるチェックを先頭に。Notebookでも最初に呼ぶ習慣を。
12) 速度/メモリ最適化の最短メモ
- dtype最適化:整数は
Int32/Int16
、浮動はFloat32
(精度要件と相談) - category活用:
store/area/gender
などラベル列はcategory化 - 列演算優先:
apply(axis=1)
回避、map/where/clip
で列ベクトル処理 - 不要列を早く落とす:
drop(columns=...)
、usecols
で読み込み制限 - I/O:中間はParquet、配布はExcel/CSV
- 他ツール併用:更に大規模なら[内部リンク:SQLite×Python]やPolarsの検討
迷ったら伴走を付ける
独学でも回せますが、レビュー(設計/仮説/評価まで)と質問対応があるとスピードと品質が段違い。6ヶ月ロードマップに沿ってポートフォリオへ落とし込むなら、次の2校の無料相談から始めましょう。
- 株式会社キカガク:業務再現型の課題設計と出口支援。転職直結を狙う人に。
- Tech Academy:質問の速さ×短時間運用で継続しやすい。副業/在宅と相性◎。
TechAcademy データサイエンスコース(受講料:174,600円~ ※更に割引あり)

株式会社キカガク AI人材長期育成コース(受講料:237,600円~)

目的別の重点配分
- 転職(未経験→DS):
結合の健全性→カレンダー結合→ウィンドウ→品質保証
を厚め。READMEと再現手順まで。 - 副業(自動化/レポート):
集計の自動化→ExcelWriter/Parquet→段階保存
を厚め。納品テンプレへ。 - 在宅(短時間×高頻度):
pipe
と小関数化で中断→再開が容易な構成に。
[内部リンク:データレポート納品の型] [内部リンク:面接で刺さる発表の作り方]
行動:月末ミニプロジェクト(レビュー観点付き)
課題:「月次×店舗の売上トレンドと前年比を作り、課題と打ち手を3行で示す」
orders.csv
を読み、amount=qty*unit_price
とym
を作成。calendar.csv
と結合し、穴のない日次→月次に集約。rolling(7)
で短期トレンド、shift(12)
で前年同月比を計算。report.xlsx
にmonthly/YoY
を出力し、上位店舗のグラフを作成。- READMEに示唆(例:特定エリアのYoY低下→在庫/販促の仮説)を記載。
レビュー観点チェックリスト(コピペ可)
- [ ] 参照キーは一意か(
validate=
使用) - [ ]
dtype
は明示か(カテゴリ/整数の最適化) - [ ] 欠損/外れ値の方針がコメントされているか
- [ ] メソッドチェーン/
pipe
で読みやすいか - [ ] 中間成果(Parquet/Excel)の再現手順が残っているか
付録A:実務で効くユーティリティ関数集
from pathlib import Path
import pandas as pd
def to\_month(d: pd.Series) -> pd.Series:
return d.dt.to\_period("M").astype(str)
def read\_csv\_fast(path: str, usecols: list\[str] | None = None) -> pd.DataFrame:
return pd.read\_csv(path, usecols=usecols, low\_memory=False)
def ensure\_unique(df: pd.DataFrame, key: str) -> None:
assert df\[key].is\_unique, f"{key} is not unique"
def top\_n(df: pd.DataFrame, key: str, n: int = 20) -> pd.DataFrame:
return df.nlargest(n, key)
付録B:Notebook→スクリプト化の最短手順
- Notebookで
pipe
小関数化→src/
に切り出し if __name__ == "__main__":
ブロックでI/Oを分離pytest
でデータ検査だけ先に書くMakefile
やタスクランナーで一発実行に
FAQ:よくある質問
Q1. rolling
とexpanding
の違いは?
A. rolling
は一定窓、expanding
は累積。移動平均はrolling
、累積比率はexpanding
。
Q2. キーの重複で行が増えます
A. まずvalue_counts
で重複を特定。結合はvalidate="many_to_one"
で即検知。
Q3. 中間ファイルはどこまで保存する?
A. 重い工程の直後と、レビュー共有が必要な集約結果。形式はParquetが基本。
Q4. Excel中心の現場対策は?
A. ExcelWriter
で複数シート、UTF-8 BOMのCSV、ピボット素材を渡す運用が最短。
Q5. さらに速くしたい
A. 列演算の徹底・category
化に加え、必要なら[内部リンク:SQLite×Python]やPolarsも検討。
この記事から次に読むべきもの(内部リンク)
-
-
【保存版】scikit-learn基礎:回帰・分類・前処理・パイプライン・交差検証を“実務の型”で習得
機械学習で迷子になる最大の理由は、前処理→学習→評価→改善の順番が曖昧なまま個々のアルゴリズムに飛びつくこと。本記事は、未経験〜初学者が週10時間×2〜3週で到達できるscikit-learnの最短ル ...
-
-
【保存版】モデル評価:指標の選び方・交差検証・閾値最適化・ビジネス接続を“実務の型”で解説
精度が上がらない原因の多くは「評価設計の誤り」にあります。評価とは「何点取れたか」ではなく、意思決定に耐えるかを測る営み。この記事では、回帰/分類/ランキングの指標の選び方、交差検証の正しい使い分け、 ...
-
-
【保存版】可視化入門:Matplotlib/Plotlyの使い分けと“伝わるグラフ設計”10ステップ
結論:可視化は「きれいに描く」ことではなく、意思決定を動かすための設計です。本稿では、未経験〜初学者が 週10時間×1〜2週 で、Matplotlib/Plotlyを軸に “伝わるグラフ”の設計と実装 ...
-
-
はじめてのSQL:SELECT/WHERE/GROUP BYを最短で理解【コピペOK】
データ分析・自動レポート・簡易アプリの土台はSQLです。Pythonだけで押し切るより、前処理の7割をDB側で完結させる方が速く・安定します。本記事は、未経験〜初学者が週10時間×2〜3週で、SELE ...
-
-
【保存版】SQLite×Pythonで作る“ローカルDWH”——ETL・集計・レポート自動化の最短手順
ローカルでゼロ構築、ファイル1つで完結、サーバ不要。本記事はSQLite×Pythonで“毎日回る”ETL・集計・レポート自動化を最短で作るための完全ガイドです。データ設計→DB作成→ETL(取り込み ...
-
-
【保存版】データレポート納品の型:要件定義→ETL→検証→可視化→Excel/PDF→引き継ぎまで、失注しないワークフロー完全版
“いい分析”より“伝わる納品”。副業や実務で評価されるのは、意思決定に効く1枚と再現できるパッケージを期限通り出せること。 本記事は、未経験〜初学者が週10時間×2〜3週で、要件定義→データ受領→ET ...
最近のコメント