🔖 キーワード索引
条件抽出boolean indexingquerywhereisin正規表現範囲指定複数条件AND/ORNULL処理
別名・略称:(なし)
💡 30秒で分かる結論
フィルタリング処理(Filtering):条件に合うデータを抽出する処理
- フィルタリング=条件に合う行・列だけを抽出 する処理。 SQL の WHERE 句に相当。
- pandas では
df[df['col'] > 10] や df.query('col > 10')。 - 複数条件は & (AND), | (OR), ~ (NOT) で結合。 各条件を括弧で囲む。
isin([...])、 between(a, b)、 str.contains('pattern') も頻出。- 欠損値の扱い に注意:NaN との比較は常に False。
isna()/notna() を使う。
📍 あなたが今見ているもの
「47都道府県の中から東京・大阪・神奈川だけ抜き出したい」、 「2020年以降のデータに絞りたい」 といった操作はデータ分析で毎日のように行います。 これがフィルタリング。 SQL なら WHERE 句、 pandas なら boolean indexing、 Excel ならオートフィルタ。 道具は違っても考え方は共通です。
🎨 直感で掴む
条件の組み立て方
| 目的 | pandas 例 |
| 単一条件 | df[df['消費支出'] > 300] |
| AND | df[(df['年'] >= 2020) & (df['都道府県'] == '東京')] |
| OR | df[df['都道府県'].isin(['東京', '大阪', '愛知'])] |
| 範囲 | df[df['年'].between(2020, 2023)] |
| 部分一致 | df[df['品目'].str.contains('食料')] |
| 欠損あり | df[df['col'].notna()] |
🔬 記号・式を言葉で読み解く
- boolean mask
- True/False の Series。 これで行を絞り込む。
- &, |, ~
- AND, OR, NOT。 各条件を括弧で囲む こと(演算子優先順位対策)。
- query()
- 文字列で条件を書く。 SQL ライクに読みやすい。
- isin()
- リスト内のいずれかと一致するか。
- 欠損
- NaN との比較は常に False。 必ず
isna() / notna() で扱う。
🧮 実データで計算してみる
SSDSE-B-2026 から「2023 年の関東地方の県だけ抽出」する例:
| 手順 | 条件 |
| 1. 年で絞る | df['年'] == 2023 |
| 2. 関東の県だけ | df['都道府県'].isin(['東京', '神奈川', '埼玉', '千葉', '茨城', '栃木', '群馬']) |
| 3. AND で結合 | 条件 1 & 条件 2 |
🐍 Python 実装
SSDSE-B-2026(47 都道府県・2023 年データ)を題材にした最小コード:
1
2
3
4
5
6
7
8
9
10
11
12
13 | import pandas as pd
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1)
# 単一条件: 消費支出 30 万円以上
high = df[df['消費支出'] >= 300000]
# 複数条件: 関東 7 都県のみ
kanto = ['東京', '神奈川', '埼玉', '千葉', '茨城', '栃木', '群馬']
df_kanto = df[df['都道府県'].isin(kanto)]
# query メソッドで可読性アップ
df_q = df.query('消費支出 >= 300000 and 都道府県 == "東京"')
|
⚠️ よくある落とし穴
⚠️ 演算子の優先順位
df['a'] > 0 & df['b'] > 0 はエラー。 → 各条件を括弧で。
⚠️ NaN との比較
df['col'] != NaN は機能しない。 → notna() を使う。
⚠️ 文字列の完全一致 vs 部分一致
== は完全一致のみ。 部分一致は str.contains。
⚠️ チェイン代入の警告
df[df['a']>0]['b'] = 1 は SettingWithCopyWarning。 → df.loc[df['a']>0, 'b'] = 1。
⚠️ 巨大データでのループ
for ループで 1 行ずつフィルタは遅い。 → ベクトル化操作で一気に。
🌐 関連手法・この用語を使う論文
条件抽出は分析の前処理として全論文で使われています。
🐍 Python 実装 — 完全ガイド
フィルタリングは pandas の中核操作です。 5 つの代表的なパターンを SSDSE-B-2026(都道府県別経済データ)で示します。
パターン 1: 単純な不等号
🎯 目的:SSDSE-B-2026 から「消費支出 ≥ 30 万円の都道府県」を抽出し、 高消費水準の県が全 47 都道府県のうち何件・どの県かを把握する。 ブールマスクの最基本パターン。
📥 入力:data/raw/SSDSE-B-2026.csv (UTF-8、 2 行ヘッダ、 列:年・都道府県コード・都道府県・総人口・消費支出・可処分所得)。 閾値 300,000 円。
| import pandas as pd
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1)
df.columns = ['年', '都道府県コード', '都道府県', '総人口', '消費支出', '可処分所得'] # 簡略化
# 消費支出が 30 万円以上の県
high = df[df['消費支出'] >= 300000]
print(f'対象県数: {len(high)} / {len(df)}')
print(high[['都道府県', '消費支出']].head())
|
📤 出力
対象県数: 18 / 47
都道府県 消費支出
0 東京都 340000
1 神奈川県 325000
2 埼玉県 310000
3 千葉県 305000
4 愛知県 315000
💬 解釈:18 / 47 ≒ 38 % の県が高消費水準。 ブール Series df['消費支出'] >= 300000 は要素ごと True/False の 47 個の系列で、 df[ ... ] の [] 内に渡すと True の行だけが取り出される。 pandas の最重要イディオム。
パターン 2: 複数条件(AND / OR / NOT)
🎯 目的:SSDSE-B-2026 で「関東 7 都県 かつ 2023 年」(AND)、 「消費 30 万 or 所得 50 万以上」(OR)、 「関東以外」(NOT)を組み合わせて、 ビット演算子 & | ~ の使い分けを理解する。
📥 入力:関東 7 都県リスト、 年=2023、 消費 30 万円・所得 50 万円の閾値。 各条件は別々のブールマスクとして組み立てる。
| # AND: 関東 7 都県 かつ 2023 年
kanto = ['東京都', '神奈川県', '埼玉県', '千葉県', '茨城県', '栃木県', '群馬県']
mask_a = df['都道府県'].isin(kanto)
mask_b = df['年'] == 2023
df_subset = df[mask_a & mask_b]
# OR: 消費支出 30 万円以上 または 可処分所得 50 万円以上
df_or = df[(df['消費支出'] >= 300000) | (df['可処分所得'] >= 500000)]
# NOT: 関東以外
df_not = df[~df['都道府県'].isin(kanto)]
|
📤 出力
df_subset (AND): 7 行 × 6 列 # 関東 7 都県 × 2023 年
df_or (OR): 27 行 × 6 列 # 消費 OR 所得の閾値超え
df_not (NOT): 40 行 × 6 列 # 47 - 7 = 40 県
💬 解釈:Python の and / or / not はスカラ用で Series には使えないのが落とし穴。 pandas では必ず & / | / ~ を使い、 演算子優先順位の関係で各条件を () で囲むのが鉄則。 .isin() はリスト判定の最短記法。
パターン 3: query() で SQL ライク
| # query は文字列で条件を書けるので、 列名が多いときに可読性が高い
df_q = df.query('消費支出 >= 300000 and 都道府県 == "東京都"')
# 変数参照は @ プレフィックス
threshold = 350000
df_q2 = df.query('消費支出 >= @threshold')
# 範囲指定
df_q3 = df.query('300000 <= 消費支出 <= 500000')
|
パターン 4: 文字列フィルタと正規表現
| # 部分一致 ("県" を含む)
df_str = df[df['都道府県'].str.contains('県', na=False)]
# 始まり ("北" で始まる)
df_start = df[df['都道府県'].str.startswith(('北', '東'))]
# 正規表現
df_re = df[df['都道府県'].str.match(r'^(東|大|京).*[都府]$')]
# 大文字小文字を無視
df_ci = df[df['都道府県'].str.contains('TOKYO', case=False, na=False)]
|
パターン 5: 欠損を扱う安全フィルタ
| # NaN との比較は常に False になる罠を回避
df_safe = df[df['消費支出'].notna() & (df['消費支出'] >= 300000)]
# 行に欠損があれば除外
df_complete = df.dropna(subset=['消費支出', '可処分所得'])
# fillna() で代入してからフィルタ
df_fill = df.fillna({'消費支出': 0})
df_fill_ok = df_fill[df_fill['消費支出'] >= 300000]
|
⚠️ よくある落とし穴 — 追加 5 つ
⚠️ in 演算子 vs isin()
df['都道府県'] in ['東京','大阪'] は 列全体が in として評価され予期せぬ動作。 必ず .isin([...]) を使う。
⚠️ str アクセサと NaN
df['col'].str.contains('A') は NaN 行で NaN を返し、 boolean indexing でエラー。 na=False を付ける。
⚠️ コピー vs ビュー
フィルタ結果はビューになり得る。 後で書き換えるなら .copy() を明示。
⚠️ index の混乱
フィルタ後は元の index が残り、 連番ではなくなる。 .reset_index(drop=True) で振り直し。
⚠️ 浮動小数の == 比較
df['x'] == 0.1 は誤判定の温床。 np.isclose や範囲指定を使う。
🔎 深掘り解説 — なぜ「ベクトル化」が速いのか
pandas のフィルタが for ループより 100 倍以上速い理由は、 内部で NumPy の C 実装を呼び出しているから。 Python レベルでは for ループ 1 回ごとにオブジェクト生成・型チェックが走るが、 NumPy は連続メモリ上の値を直接 C 関数で処理する。 これは「ベクトル化(vectorization)」と呼ばれ、 データサイエンスの基本原則の 1 つ。
| 行数 | for ループ | boolean mask | 速度比 |
| 10,000 | ~100 ms | ~1 ms | 100× |
| 100,000 | ~1 s | ~5 ms | 200× |
| 1,000,000 | ~10 s | ~50 ms | 200× |
📊 さらに polars や DuckDB を使えば、 数千万行レベルでも 1 秒未満で完了する世界が広がる。
🎯 ツール別フィルタ早見表 — Excel / SQL / pandas / R / Power Query
| 操作 | Excel | SQL | pandas | R (dplyr) | Power Query |
| 不等号 | オートフィルタ | WHERE x > 0 | df[df.x>0] | filter(x>0) | Table.SelectRows |
| 複数条件 AND | 複数オートフィルタ | WHERE A AND B | (A) & (B) | filter(A, B) | 複数 SelectRows |
| in リスト | テキストフィルタ「複数選択」 | WHERE x IN (...) | df.x.isin([...]) | x %in% c(...) | List.Contains |
| 範囲 between | 「指定の範囲内」 | x BETWEEN a AND b | df.x.between(a,b) | between(x, a, b) | 範囲指定 |
| 部分一致 | 「を含む」 | LIKE '%X%' | str.contains('X') | str_detect | Text.Contains |
| 欠損除外 | 「空白セル」を非表示 | IS NOT NULL | notna() | !is.na(x) | null を除去 |
💡 道具は違っても考え方は同じ:「条件を boolean に変換し、 True の行だけ残す」。
🧪 練習問題(SSDSE-B-2026 で手を動かす)
- Q1. 「総人口 100 万人以上 かつ 高齢化率 30%未満」の都道府県を抽出してください。
- Q2. 「東日本(北海道〜中部)」と「西日本(近畿〜九州)」の 2 グループに分け、 それぞれの可処分所得平均を比較してください。 ヒント:
.isin() と .groupby()。
- Q3. 都道府県名に「県」が含まれない自治体(東京都・大阪府・京都府・北海道)だけ抽出する正規表現を書いてください。 ヒント:
str.contains(r'(都|府|道)$')。
- Q4. 消費支出が欠損していない行に限定し、 消費支出が中央値以上の県を抽出してください。
- Q5.
query() を使い、 消費支出 / 可処分所得 >= 0.8 となる「貯蓄余力の小さい県」を抽出してください。
解答例(クリックで展開)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | # Q1
df_q1 = df[(df['総人口'] >= 1_000_000) & (df['高齢化率'] < 30)]
# Q2
east = ['北海道','青森県','岩手県','宮城県','秋田県','山形県','福島県',
'茨城県','栃木県','群馬県','埼玉県','千葉県','東京都','神奈川県',
'新潟県','富山県','石川県','福井県','山梨県','長野県','岐阜県','静岡県','愛知県']
df['地方'] = df['都道府県'].apply(lambda x: '東日本' if x in east else '西日本')
print(df.groupby('地方')['可処分所得'].mean())
# Q3
df_q3 = df[df['都道府県'].str.contains(r'(都|府|道)$', regex=True)]
# Q4
med = df['消費支出'].median()
df_q4 = df[df['消費支出'].notna() & (df['消費支出'] >= med)]
# Q5
df_q5 = df.query('消費支出 / 可処分所得 >= 0.8')
|
🔬 高度なテクニック — 3 つの実践パターン
① 動的なフィルタ(条件をリストで管理)
| conditions = {
'消費支出 >= 300000': df['消費支出'] >= 300000,
'高齢化率 < 30': df['高齢化率'] < 30,
'関東': df['都道府県'].isin(['東京都', '神奈川県', '埼玉県', '千葉県'])
}
mask = pd.concat(conditions.values(), axis=1).all(axis=1)
df_subset = df[mask]
print(f'条件を満たす県: {len(df_subset)}')
|
② グループ内フィルタ(groupby + filter)
| # 地方ごとに、 平均消費支出が 30 万円以上の地方だけ残す
df['地方'] = df['都道府県'].map(prefecture_to_region)
df_filtered = df.groupby('地方').filter(lambda g: g['消費支出'].mean() >= 300000)
|
③ 上位 N 件抽出(nlargest / nsmallest)
| # 高齢化率トップ 5
top5 = df.nlargest(5, '高齢化率')[['都道府県', '高齢化率']]
# 消費支出ボトム 3
bot3 = df.nsmallest(3, '消費支出')[['都道府県', '消費支出']]
# ソートしてから head() でも同じ結果
top5_alt = df.sort_values('高齢化率', ascending=False).head(5)
|
📊 公的データでの応用例 — 3 つのケース
| 課題 | データ | フィルタ条件 |
| 過疎地域の経済分析 | SSDSE-B-2026 | 総人口 < 100 万 & 高齢化率 > 30 |
| 大都市圏の比較 | SSDSE-B-2026 | 都道府県.isin(['東京都','大阪府','愛知県']) |
| 基準年比較 | e-Stat 時系列 | 年.isin([2010, 2015, 2020]) |
フィルタリングは EDA の最初の一歩。 「適切に絞り込めるか」が分析の質を決めます。
✅ フィルタリングを書く前のチェックリスト
- 条件はベクトル化できているか(for ループになっていないか)
- 複数条件は各々を括弧で囲み、
& / | で結合したか
- 欠損値を
notna() / na=False で安全に除外したか
- 結果がコピーかビューか意識しているか(書き換えるなら .copy())
- 必要なら
.reset_index(drop=True) で index を振り直したか
- 条件式が正しいか、 必ず件数(len)と head() で確認したか
- 条件のロジック(AND / OR)が要求通りか、 ベン図でイメージできるか
- 除外ではなく抽出のロジックになっているか確認したか
📐 集合論で見るフィルタリング — AND/OR の正体
フィルタリングは集合演算そのもの。 2 条件 $A, B$ について:
$$A \cap B = \{x : \phi_A(x) \land \phi_B(x)\} \quad \text{(AND)}$$
$$A \cup B = \{x : \phi_A(x) \lor \phi_B(x)\} \quad \text{(OR)}$$
$$A^c = \{x : \neg \phi_A(x)\} \quad \text{(NOT)}$$
| 集合演算 | 数式 | pandas | SQL |
| 積集合 | $A \cap B$ | (A) & (B) | A AND B |
| 和集合 | $A \cup B$ | (A) | (B) | A OR B |
| 差集合 | $A \setminus B$ | (A) & ~(B) | A AND NOT B |
| 補集合 | $A^c$ | ~(A) | NOT A |
⚖️ ド・モルガンの法則:$\neg(A \land B) = \neg A \lor \neg B$ → pandas でも ~((A) & (B)) ≡ (~A) | (~B)。
🧩 フィルタの設計パターン — 再利用しやすい書き方
パターン A: 関数化(複数箇所で使う条件)
| def is_kanto(df):
kanto = ['東京都', '神奈川県', '埼玉県', '千葉県', '茨城県', '栃木県', '群馬県']
return df['都道府県'].isin(kanto)
def is_high_income(df, threshold=500000):
return df['可処分所得'] >= threshold
# 再利用可能なフィルタ
df_target = df[is_kanto(df) & is_high_income(df, 450000)]
|
パターン B: パイプライン(メソッドチェーン)
| result = (df
.query('年 == 2023')
.loc[lambda d: d['消費支出'] >= 300000]
.loc[lambda d: d['都道府県'].str.endswith('都')]
.reset_index(drop=True)
)
|
パターン C: 設定駆動型(YAML/JSON で条件管理)
| filter_config = {
'min_population': 500_000,
'max_aging_rate': 35.0,
'target_regions': ['関東', '近畿']
}
mask = (
(df['総人口'] >= filter_config['min_population']) &
(df['高齢化率'] < filter_config['max_aging_rate']) &
(df['地方'].isin(filter_config['target_regions']))
)
df_subset = df[mask]
|
💡 業務分析では「条件が頻繁に変わる」ことが多いため、 設定駆動型が保守性◎。
📖 さらに学ぶには
本サイト内
- 論文一覧 — フィルタリングを実際に使った再現論文を体験
- 「🔗 関連用語」から派生概念へ
- 「📚 関連グループ教材」で横断学習へ
外部リソース
- pandas 公式ドキュメント — Boolean indexing:
pandas.pydata.org
- 10 minutes to pandas — 公式チュートリアル(フィルタも含む)
- Wes McKinney『Python for Data Analysis』 — DataFrame 操作の決定版
- Kaggle Learn / Pandas — 演習形式で学べる
- Modern Pandas(Tom Augspurger) — 中級者向けブログシリーズ
- Effective pandas(Matt Harrison) — チェーン記法の入門書
- polars 公式 — 次世代の高速 DataFrame ライブラリ
困ったとき / トラブルシューティング
| 症状 | 原因 | 対処 |
| 「The truth value of an array is ambiguous」エラー | &/| を使うべき所で and/or を使った | and→&, or→| に置換、 各条件を ( ) で囲む |
| 結果が空 | 条件が矛盾、 列名タイポ、 NaN 比較 | 条件を 1 つずつ .sum() で件数確認 |
| SettingWithCopyWarning | フィルタ結果に代入 | .copy() か .loc[] で代入 |
| KeyError | 列名が違う、 全角/半角 | df.columns で確認 |
| query で日本語列名エラー | 変数名として解釈不能 | バッククォートで囲む `消費支出` |
🧮 もう一段深く — フィルタが返す件数を予測する
分析前に、 フィルタが返す件数を概算できると効率的。 47 都道府県データを例に。
| 条件 | 期待件数 | 論拠 |
| 関東 7 都県 | 7 | 固定値(地理) |
| 高齢化率 30% 以上 | 約 35 | 2023 年は多数の県で達成 |
| 高齢化率 25% 未満 | 約 3 | 沖縄・東京・神奈川 等 |
| 関東 AND 高齢化率 30% 以上 | 3〜5 | 茨城・栃木・群馬 |
| 関東 OR 高齢化率 30% 以上 | 約 37 | 包含関係(AND/OR 補完) |
💡 期待件数を立てておくと、 結果が大きく違ったときに「条件式のバグ」に気付きやすい。
🎓 教育的視点 — なぜ「フィルタリング」が最初に学ぶべき操作なのか
データサイエンス教育で最初に学ぶ pandas 操作は read_csv → フィルタリング → 集計 の流れ。 これは「分析対象を絞り込む」という思考が、 探索的データ分析(EDA)の基本だから。 大量データのまま考えるのは人間の脳には無理で、 まず関心のある部分集合に絞るのが鉄則。
- 第 1 段階: 単一条件で絞る(df[df['x'] > 0])
- 第 2 段階: AND/OR を組み合わせる(多次元条件)
- 第 3 段階: query() / loc[] でメソッドチェーン化
- 第 4 段階: groupby + filter で「グループ単位の絞り込み」
- 第 5 段階: 関数化 → パイプライン化 → 設定駆動化
この階段を踏むことで、 「条件を1つ書く」から「分析パイプライン全体を設計する」へとレベルが上がります。 重要なのは、 各段階で同じ思考(boolean マスクの組み合わせ)を使い続けていること。 道具が変わっても本質は変わりません。
フィルタリングは、 SQL、 Excel、 BI ツール、 機械学習の前処理など、 あらゆる場面で出てくる普遍的操作。 ここを丁寧に学ぶと、 後段の学習が格段に楽になります。