別名・略称:(なし)
「set theory」は統計データ分析の文脈で扱う重要概念のひとつ。 本ページでは「set theory」を取り巻く中核キーワードを以下にチップで一覧化する。 各キーワードは関連する概念・手法・道具立てを含み、 文献検索や学習計画の起点になる。
これらのキーワードは「set theory の理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。
🍰 まずはやさしく
集合は、ものの集まりのことです。
データの整理や確率の計算に使います。
部活のメンバーをまとめるようなものです。
ここでは集合の基本と計算方法を読みます。
集合(Set):要素の集まり。 確率の基礎
UNION, INTERSECT, EXCEPT、 Python の set 型は集合演算そのもの。df.drop_duplicates() → 行集合を取るdf['col'].unique() → 出現するカテゴリの集合df['col'].nunique() → 集合のサイズset(df1['id']) & set(df2['id']) → 共通顧客 IDset(df1['id']) - set(df2['id']) → 解約顧客df[df['pref'].isin(['東京','大阪'])] → サブセット抽出df[~df['pref'].isin(['北海道'])] → 補集合df1.merge(df2, how='cross') → デカルト積train_test_split(df, test_size=0.2) → 互いに素な分割KFold(n_splits=5) → 5 分割(互いに素・和が全データ)これらの背後にあるのはすべて集合演算。 集合論を知っていればパフォーマンス・正確性の両面で優れたコードが書ける。
集合論を覚えたら、 次は 確率論。 すべての確率の公式は集合論で表現される。
| 確率論の用語 | 集合論的表現 | SSDSE 例 |
|---|---|---|
| 標本空間 Ω | 全体集合 U | 47 都道府県すべて |
| 事象 A | Ω の部分集合 | 人口 200 万以上の県 |
| 確率 P(A) | |A| / |Ω|(等確率の場合) | 16 / 47 ≒ 0.340 |
| A または B | A ∪ B | P(A ∪ B) = P(A) + P(B) − P(A ∩ B) |
| A かつ B | A ∩ B | 独立なら P(A) × P(B) |
| A でない | Aᶜ = Ω \ A | P(Aᶜ) = 1 − P(A) |
| 条件付き確率 P(A|B) | |A ∩ B| / |B| | B = 北日本に限ると… |
| 独立事象 | P(A ∩ B) = P(A) × P(B) | 確率的独立性 |
| σ-加法族 | 「測れる集合」の集合 | 確率を割り当てる先 |
無限集合の濃度を直感的に理解する有名な思考実験。 数学者 David Hilbert が 1924 年の講義で紹介した。
シナリオ:「ヒルベルトのホテル」は 無限個の部屋 を持ち、 全部屋に客がいる。 ある日、 新しい客が 1 人来る。 普通のホテルなら満室で泊められないが、 ヒルベルトの支配人は「全員 1 部屋ずらしてください」と指示。 1 号室の客は 2 号室へ、 2 号室の客は 3 号室へ... こうして 1 号室が空き、 新客はそこに泊まれる。
応用:もし 100 人の客が来ても、 「全員 100 号室分ずらして」で OK。 さらに 無限人の客 が来たら、 「奇数号室を空けて偶数号室にずらす」で対応可能(自然数の偶数集合と全自然数集合の濃度が同じだから)。 ついには「無限台のバスが各々無限人を乗せて到着」しても対角線論法で対応できる。
→ 教訓:無限集合では「全部 + 1 = 全部」(カーディナリティが変わらない)。 ホテル支配人は集合論の知識でビジネスを成功させている。 これがアレフ ℵ₀ の濃度。
1874 年、 ドイツの数学者 Georg Cantor は人類が無限について抱いていた直観を覆す論文を発表した。 「自然数と実数のどちらが多いか?」 — 直観的にはどちらも無限だから同じはず。 しかしカントールは 対角線論法 でこれを否定する。
仮に実数 [0, 1] が可算なら、 $r_1, r_2, r_3, \ldots$ と全部リストできるはず。 各 $r_i$ を小数展開し、 $r_1$ の 1 桁目、 $r_2$ の 2 桁目、 ... に 1 を足した新数 $r^*$ を作る。 すると $r^*$ はリストのどの $r_i$ とも違う → 矛盾。 よって実数は可算でない。
同時にカントールは「集合 $A$ の冪集合 $\mathcal{P}(A)$ は常に $A$ より濃度が大きい」($2^{|A|} > |A|$) も示した。 これにより「無限に階層がある」、 すなわち $\aleph_0 < \aleph_1 < \aleph_2 < \cdots$ という無限の階層が見えてきた。
カントールの理論は当時「神学的すぎる」「数学を破壊する」と猛批判を受け、 自身も精神を病んだ。 しかしダフィット・ヒルベルトは「カントールが我々に拓いた楽園から、 誰も追い出すことはできない」と擁護。 現代では集合論は数学のすべての基礎となっている。
→ データサイエンスの実用は有限集合がほとんどだが、 機械学習で扱う「すべての可能なモデル空間」「すべての可能な仮説」を考えると、 暗黙のうちに無限集合論の世界に入っている。 過学習・正則化の理論的議論は集合論なしには不可能。
1942 年に Eilenberg と Mac Lane が提唱した 圏論 (Category Theory) は、 「集合と関数」を一般化した枠組み。 集合論が「もの (要素)」中心だったのに対し、 圏論は「もの同士の関係 (射)」中心。
| 集合論の用語 | 圏論の用語 | 具体例 |
|---|---|---|
| 集合 | 対象 (Object) | 圏 Set の対象は集合 |
| 関数 (写像) | 射 (Morphism, Arrow) | A → B の射 |
| 恒等関数 | 恒等射 id_A | A → A の特別な射 |
| 合成関数 f∘g | 射の合成 | 結合律を満たす |
| 部分集合 ⊆ | 単射 (mono) | 包含写像 |
| 集合の積 A × B | 圏の積 | 普遍性で特徴付け |
| 写像族 | 関手 (Functor) | 圏 → 圏 の写像 |
| 関係 | 自然変換 | 関手 → 関手 |
圏論は数学を 構造の構造 として見る方法。 関数型プログラミング (Haskell の Monad は圏論の概念)、 機械学習の理論基盤 (Deep Learning as Functor)、 量子計算 (圏論的量子論) 等で再評価されている。
関数 $f: A \to B$ は集合論の最重要構造の 1 つ。 単射・全射・全単射の区別が現代代数の基礎。
| 分類 | 英語 | 定義 | 例 |
|---|---|---|---|
| 単射 | Injection (one-to-one) | $f(a_1) = f(a_2) \Rightarrow a_1 = a_2$ | $f(x) = 2x$ (ℕ → ℕ) |
| 全射 | Surjection (onto) | 任意の $b \in B$ に対し $f(a) = b$ となる $a$ が存在 | $f(x) = x^2$ (ℝ → [0,∞)) |
| 全単射 | Bijection (one-to-one correspondence) | 単射 かつ 全射 | $f(x) = x + 1$ (ℤ → ℤ) |
全単射 ⇔ 逆関数が存在。 機械学習で「特徴量を可逆変換する」「データ拡張で生成 ↔ 元データ」などが全単射の要件を満たす必要がある場面が多い。
集合論とは、 「ものの集まり」を演算で取り扱う数学。 19 世紀末にカントールが基礎を築き、 20 世紀の数学・論理学・コンピュータ科学のすべての言語となった。 「データ ⊆ 母集団」「事象 ⊆ 標本空間」「テーブル = タプル集合」というように、 統計・確率・データベースを統一する基礎概念。
本ページで学んだ要点:(1) 7 つの基本演算 (∪, ∩, \, △, ᶜ, ⊆, ×)、 (2) 包除原理 |A∪B| = |A|+|B|-|A∩B|、 (3) ド・モルガンの法則、 (4) 冪集合のサイズ $2^n$、 (5) ベン図、 (6) SSDSE 47 都道府県を 2-3 集合で分けた検算、 (7) Python set 型と pandas での実装、 (8) SQL の UNION/INTERSECT/EXCEPT との対応、 (9) ラッセルのパラドックスと ZFC、 (10) 推薦・検索・データ分割など実応用。
🍰 まずはやさしく
集合は、数学や統計の共通言語です。
データ分析を正しく行うために使います。
スマホのアプリでデータを分ける時に役立ちます。
定義から実装までを順番に読みましょう。
UNION ALL、 pandas の merge、 機械学習の クラスラベル も集合論で考えられます。 すべての数学・統計の 基礎言語。本ページでは「set theory」を扱う。 統計データ分析コンペティション (2026) の教材で、 SSDSE-B-2026 (47 都道府県 × 複数年 × 100 超列) の実データを使った再現可能な学習を目指す。
「set theory」は統計・データサイエンスの体系における重要概念のひとつ。 本ページは「定義・直感・数式・実装・落とし穴・関連手法」の 6 視点で構成され、 各視点は独立して読めるが順序通り読むと体系的な理解が得られる。
🍰 まずはやさしく
集合は、グループ分けのようなものです。
共通点を持つものを一まとめにするために使います。
クラスの男子だけを集めるような例です。
図を使って、集合の関係性を読みましょう。
「集合」と聞くと数学の抽象概念に感じるかもしれませんが、 身の回りはすべて集合でできています。 「クラスの男子」「東京都に住む人」「赤い花の品種」— 何かを属性で区切って一括りにしたら、それが集合です。 19 世紀末にカントール (Georg Cantor) が 無限集合の比較 を可能にしたことで、 現代数学・確率論・統計学・データベース・プログラミングのすべての基礎言語になりました。
| 演算 | 記号 | 読み方 | 意味 | Python | SQL |
|---|---|---|---|---|---|
| 和集合 | A ∪ B | エー かつ ビー | A または B | A | B | UNION |
| 積集合 | A ∩ B | エー まつ ビー | A かつ B | A & B | INTERSECT |
| 差集合 | A \ B | エー まいなす ビー | A で B でないもの | A - B | EXCEPT |
| 対称差 | A △ B | エー さんかく ビー | どちらか片方のみ | A ^ B | なし |
| 補集合 | Aᶜ | えー こんぷり | A でないもの全部 (U − A) | U - A | NOT IN |
| 部分集合 | A ⊆ B | えー さぶせっと びー | A の全要素が B にも | A.issubset(B) | — |
| 直積 | A × B | えー かける びー | {(a, b) | a∈A, b∈B} | itertools.product | CROSS JOIN |
2 集合 A, B の代表的な関係を、 SSDSE-B-2026 都道府県データで例示します(A = 人口 100 万以上の県、 B = 高齢化率 30% 以上の県)。
| 図領域 | 記号 | SSDSE 例 | 所属する県数 (47 県中) |
|---|---|---|---|
| A のみ | A \ B | 人口 100 万以上で高齢化率 30% 未満 | 12 (東京・神奈川・愛知・大阪 など都市部) |
| B のみ | B \ A | 人口 100 万未満で高齢化率 30% 以上 | 10 (秋田・高知・島根 など人口減少地域) |
| 両方 | A ∩ B | 人口 100 万以上 かつ 高齢化率 30% 以上 | 25 (北海道・新潟・長野 など地方中核県) |
| どちらでもない | (A ∪ B)ᶜ | 人口 100 万未満 かつ 高齢化率 30% 未満 | 0 (該当県なし → 後で詳述) |
| 和集合 | A ∪ B | 人口 100 万以上 または 高齢化率 30% 以上 | 47 (全県) |
→ A ∪ B = 47 県すべて、 A ∩ B = 25 県、 (A ∪ B)ᶜ = 0。 包除原理 |A∪B| = |A| + |B| − |A∩B| = 37 + 35 − 25 = 47 も一致(後の Python セクションで検算)。
2 つの集合 A・B のベン図です。 円をドラッグして重なりを変えたり、 スライダーで全体集合 |U| や各集合の要素数 |A|・|B|・|A∩B| を変えると、 選んだ演算の領域が色づき、 要素数と確率がリアルタイムに更新されます。 初期値は SSDSE-B-2026 の 47 都道府県を全体集合 U に見立てた例です。
💡 A・B の円の中心付近をドラッグすると動かせます(タッチ操作対応)。
| 領域 | 要素数 | 確率 P |
|---|---|---|
| 選択領域 | 37 | 0.787 |
| |A| | 30 | 0.638 |
| |B| | 25 | 0.532 |
| |A∩B| | 18 | 0.383 |
| |A∪B| | 37 | 0.787 |
上のベン図で、 円 A・B は「ある性質を満たす要素の集まり」です。 2 円の重なりが積集合 A∩B、 合わせた全体が和集合 A∪B、 Aだけ・Bだけが差集合、 片方だけが対称差、 円の外側が補集合。 スライダーで |A∩B| を最大 min(|A|,|B|) まで上げると片方がもう片方に完全に含まれ(A⊆B または B⊆A)、 0 まで下げると互いに素(排反)になります。 数値がすべての演算で同時に更新されるので、 「演算=領域の切り分け」という感覚を掴めます。
確率への応用:全体集合 U を標本空間 Ω、 部分集合を事象とみなすと、 等確率なら P(A)=|A|/|U|。 加法定理 P(A∪B)=P(A)+P(B)−P(A∩B) は包除原理そのものです。 条件付き確率 P(A|B)=|A∩B|/|B| も、 上の図で「B の円の中に占める重なりの割合」として読めます(詳しくは 条件付き確率・ベイズの定理)。
ド・モルガンの法則:(A∪B)ᶜ = Aᶜ∩Bᶜ、 (A∩B)ᶜ = Aᶜ∪Bᶜ。 「A または B でない」=「A でも B でもない」を意味します。 演算ボタンで (A∪B)ᶜ を選ぶと、 2 円のどちらにも入らない外側領域が色づき、 これが Aᶜ と Bᶜ の共通部分(Aᶜ∩Bᶜ)と一致することを図で確認できます。 関連:確率・ベン図・独立の各ページ。
🍰 まずはやさしく
集合は、数式で表せるルールです。
正確に計算して答えを出すために使います。
買い物リストの重複を消すような考え方です。
計算の法則や、数学的な定義を読みましょう。
現代数学の標準的な集合論の基盤。 1908 年 Zermelo、 1922 年 Fraenkel 拡張、 選択公理 (C) を含めて ZFC。
選択公理は 1904 年に Zermelo が「整列可能定理」の証明に使ったとされ、 当時は非構成的すぎると批判された。 現代では「Banach-Tarski のパラドックス(球を 5 つに分けて 2 つの球に再構成可能)」など反直観的結論を導くが、 数学全般の便利さから受け入れられている。
集合は 重複なし・順序なし。 リストは 重複あり・順序あり。 Python の set vs list。 大量の「あるか/ないか」判定が必要なら set が O(1)、 順序保持や重複可ならリスト。
中学:要素・部分集合・和集合・積集合・補集合の基本記号。 高校 (数学 A):包除原理、 ベン図、 直積。 大学:公理的集合論、 濃度、 順序数、 ZFC。
$J(A, B) = \dfrac{|A \cap B|}{|A \cup B|}$。 2 集合の「重なり度合い」を 0 〜 1 で表す。 検索エンジン、 推薦システム、 文書類似度に頻出。 上の SSDSE 例で $J(A,B) = 25 / 47 = 0.532$。
確率測度論では 「事象 = 標本空間 Ω の部分集合」。 確率は事象を [0,1] にマップする関数 $P: \mathcal{F} \to [0,1]$。 σ-加法族 (σ-algebra) は「測れる集合の集まり」で、 集合論の言葉そのまま。
SQL は 関係代数(集合論の応用)の実装。 UNION ↔ ∪、 INTERSECT ↔ ∩、 EXCEPT ↔ \、 CROSS JOIN ↔ 直積。 1970 年 E.F. Codd の論文「A Relational Model of Data for Large Shared Data Banks」が起源。
カントールが示した驚き:自然数 ℕ と整数 ℤ と有理数 ℚ の濃度は同じ (ℵ₀)、 しかし実数 ℝ の濃度はそれより大きい (ℵ₁ 以上)。 「無限にも階層がある」のが集合論の最深部。
| 概念 | 重複 | 順序 | 代表的 Python 型 |
|---|---|---|---|
| 集合 (Set) | なし | なし | set, frozenset |
| マルチセット (Multiset / Bag) | あり | なし | collections.Counter |
| タプル (Tuple) | あり | あり | tuple |
| リスト (List) | あり | あり | list |
| 辞書 (Dict / Map) | key なし | Py3.7+ あり | dict |
| 系列 (Sequence) | あり | あり | str, bytes, range |
| 同値類 (Equivalence Class) | なし | なし | クラスタリング結果 |
データ構造選択は「重複・順序」の 2 軸で考えると整理しやすい。 集合は両方「なし」の最もシンプルな構造で、 そのため最も操作が高速。
あるクラス 40 人のうち、 通学方法を聞いたところ「バスを利用する」生徒が 25 人、 「電車を利用する」生徒が 18 人、 「両方利用する」が 8 人だった。 どちらか少なくとも 1 つ利用する生徒は何人か。
答え: 35 人(包除原理 25 + 18 - 8 = 35)。 どちらも使わない生徒は 40 - 35 = 5 人。
$A = \{1, 2, 3\}$ の部分集合は全部で何個あるか。
答え: 8 個($2^3 = 8$。 ∅, {1}, {2}, {3}, {1,2}, {1,3}, {2,3}, {1,2,3})
全体集合 $U = \{1, 2, ..., 10\}$、 $A = \{1, 3, 5, 7, 9\}$(奇数)、 $B = \{1, 2, 3, 4, 5\}$(5 以下)とする。 $(A \cup B)^c$ を求めよ。
答え: {6, 8, 10}。 $A \cup B = \{1, 2, 3, 4, 5, 7, 9\}$、 その補集合は $\{6, 8, 10\}$。 ド・モルガンで $A^c \cap B^c = \{2,4,6,8,10\} \cap \{6,7,8,9,10\} = \{6,8,10\}$ も同じ。
UNION、 INTERSECT、 EXCEPT を実行する SQL を書け。set で実装してみる。matplotlib_venn でベン図を可視化。 重なりを色付き面積で確認。SELECT Prefecture FROM ssdse WHERE 人口>=100万 UNION SELECT Prefecture FROM ssdse WHERE 高齢化率>=0.30 で同じ結果を得る。集合論は単なる「便利な道具」ではなく、 数学の基礎付け として 100 年以上議論されてきた。 ここでは 5 つの大問題を見る。
「自然数の濃度 (ℵ₀) と実数の濃度 (𝔠) の間に、 別の濃度の集合はあるか?」 カントールは「ない (𝔠 = ℵ₁)」と予想したが、 ゲーデル (1940)・コーエン (1963) により ZFC では真偽決定不能 と証明された。
「互いに素な非空集合の族から、 各々から 1 つずつ要素を選ぶ関数が存在する」と認めるとバナッハ・タルスキーのパラドックス(球を有限個に分けて 2 つの同じ球に再構成可能)が導かれる。 反直観的だが、 数学全般の便利さから採用されている。
集合論の対象(無限集合・濃度・順序数)は人類が発見した客観的存在なのか、 人類が便宜的に作った概念なのか。 プラトニズム vs 形式主義の永遠の論争。
標準は ZFC だが、 NBG (von Neumann-Bernays-Gödel)、 MK (Morse-Kelley)、 NF (New Foundations)、 ETCS (Elementary Theory of the Category of Sets) など別公理系も存在。 圏論的アプローチ (HoTT) が 21 世紀に台頭。
「自然数を含む十分に強い無矛盾な公理系には、 真だが証明できない命題が必ず存在する」(1931)。 つまり ZFC ですら完璧ではない。 数学基礎論の根本的限界。
「東京 AND ラーメン -行列」の検索は 集合演算そのもの。 「東京を含む文書集合」∩「ラーメンを含む文書集合」∖「行列を含む文書集合」を実行している。 1990 年代以降、 転置インデックスとビットマップで効率化。
「あなたが買った商品の集合」と「他のユーザが買った商品の集合」の Jaccard 係数で類似ユーザを発見 → そのユーザが買った別商品を推薦。 1990 年代に GroupLens (ミネソタ大) が原型を確立。
「視聴済み映画集合」「高評価映画集合」「ジャンル集合」を組み合わせて好みを推測。 Netflix Prize (2009 年) で行列分解と組合せ最適化が花開いた。
毎週 30 曲のおすすめプレイリストを生成。 「ユーザの好み集合」と「他ユーザの好み集合」の重なり、 「ジャンル ∩ ムード」の積集合などで構築。
INNER JOIN は積集合、 LEFT JOIN は左集合とその部分、 CROSS JOIN は直積。 リレーショナル DB は全て集合論で定義されている (Codd, 1970)。
訓練集合 ∪ 検証集合 ∪ テスト集合 = 全データ、 かつ互いに素 (互いに重ならない)。 これは数学的な分割 (partition) の概念。 k-fold CV も「k 個の互いに素な部分集合への分割」を繰り返し評価。
「あなたのフォロワー集合 ∩ 相手のフォロワー集合」が「共通の友達」。 LinkedIn の「2 次・3 次のつながり」も集合演算の連鎖。
トランザクション集合をハッシュ木で表現。 「特定トランザクションがブロックに含まれるか」が集合所属判定問題に帰着。
| 記号 | 名前 | 読み方 | 意味 |
|---|---|---|---|
| ∈ | 所属 | エレメント・オブ | x ∈ A: x は A の要素 |
| ∉ | 非所属 | ノット イン | ∈ の否定 |
| ⊆ | 部分集合 | サブセット・オブ | A ⊆ B: A の全要素が B にも |
| ⊂ | 真部分集合 | プロパー サブセット | ⊆ かつ A ≠ B |
| ⊇ | 上位集合 | スーパーセット | A ⊇ B = B ⊆ A |
| ∪ | 和集合 | ユニオン | A または B |
| ∩ | 積集合 | インターセクション | A かつ B |
| \ | 差集合 | セット マイナス | A から B の要素を除いた集合 |
| △ | 対称差 | シンメトリック ディフ | A △ B = (A \ B) ∪ (B \ A) |
| Aᶜ, A̅ | 補集合 | コンプリメント | U \ A |
| ∅, { } | 空集合 | エンプティ セット | 要素ゼロ |
| U, Ω | 全体集合 | ユニバース | 議論の対象すべて |
| |A|, #A | 濃度 | カーディナリティ | A の要素数 |
| 𝒫(A) | 冪集合 | パワーセット | A の部分集合すべて |
| × | 直積 | デカルトプロダクト | A × B = {(a,b)} |
| ℕ | 自然数 | ナチュラル ナンバー | {0, 1, 2, ...} or {1, 2, ...} |
| ℤ | 整数 | インテジャー | {..., -1, 0, 1, ...} |
| ℚ | 有理数 | ラショナル | 分数で表せる数 |
| ℝ | 実数 | リアル | 数直線上の点全部 |
| ℵ₀ | 可算無限 | アレフ ゼロ | |ℕ| |
上の包除原理・ド・モルガンの法則・冪集合に出てくる記号と概念をすべて言葉に翻訳します。 これさえ覚えれば、 確率・統計・データベース・プログラミングの抽象記述が読めるようになります。
x in A。 これに含まれない場合は $x \notin A$。set()。len(A)。EXCEPT、 Python の A - B。 引き算と違うのは「もともと B にしかない要素はノーカン」という点。itertools.product。 関係データベースの基礎概念。集合論の核心は 4 つの基本演算です。 これらは「データのフィルタリング」「重複除去」「差分検出」「除外」というデータ分析の日常操作と 1 対 1 対応します。 全国 47 都道府県を全体集合 \(U\) とし、 A = 太平洋側 13 県、 B = 人口 200 万人超 16 県として演算結果を見てみましょう。
$$ A \cup B = \{x \mid x \in A \;\text{または}\; x \in B\} \quad \text{(和集合)} $$
$$ A \cap B = \{x \mid x \in A \;\text{かつ}\; x \in B\} \quad \text{(積集合)} $$
$$ A \setminus B = \{x \mid x \in A \;\text{かつ}\; x \notin B\} \quad \text{(差集合)} $$
$$ A^c = U \setminus A = \{x \mid x \in U \;\text{かつ}\; x \notin A\} \quad \text{(補集合)} $$
| 演算 | 記号 | SQL/pandas での対応 | 意味 | SSDSE 例(要素数) |
|---|---|---|---|---|
| 和集合 | \(A \cup B\) | UNION / pd.concat().drop_duplicates() | どちらか一方でも該当 | 太平洋側 OR 200 万人超 = 18 県 |
| 積集合 | \(A \cap B\) | INNER JOIN / set(A) & set(B) | 両方に該当 | 太平洋側 AND 200 万人超 = 7 県 |
| 差集合 | \(A \setminus B\) | EXCEPT / set(A) - set(B) | A だが B でない | 太平洋側だが 200 万人未満 = 6 県 |
| 補集合 | \(A^c\) | NOT IN / ~df.isin(A) | A 以外すべて | 太平洋側でない = 34 県 |
| 対称差 | \(A \triangle B\) | set(A) ^ set(B) | どちらか一方のみ | = \(|A|+|B|-2|A\cap B|\) = 11 県 |
このコードでやること: SSDSE-B-2026 の 2023 年都道府県データから「太平洋側 13 県 (A)」「人口 200 万人超 16 県 (B)」を集合として定義し、 set 型と pandas.Index の集合演算で \(A \cup B\), \(A \cap B\), \(A \setminus B\), \(B \setminus A\), \(A^c\) を計算する。
📥 入力データ (太平洋側 13 県の定義 + SSDSE 人口列):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df_2023 = df[df['SSDSE-B-2026'] == 2023] # A = 太平洋側 13 県 (海岸線が太平洋に面する) A = {'青森県', '岩手県', '宮城県', '福島県', '茨城県', '千葉県', '東京都', '神奈川県', '静岡県', '愛知県', '三重県', '和歌山県', '高知県'} # B = 2023 年人口 200 万超の都道府県 (SSDSE 実データから) B = set(df_2023[df_2023['A1101'] >= 2_000_000]['Prefecture']) U = set(df_2023['Prefecture']) # 全体集合 = 47 県 union = A | B # 和集合 inter = A & B # 積集合 diff_AB = A - B # 差集合 A\B diff_BA = B - A # 差集合 B\A comp_A = U - A # 補集合 A^c sym_diff = A ^ B # 対称差 print(f'|A| = {len(A)}, |B| = {len(B)}, |U| = {len(U)}') print(f'|A ∪ B| = {len(union)}') print(f'|A ∩ B| = {len(inter)}: {sorted(inter)}') print(f'|A \\ B| = {len(diff_AB)}: {sorted(diff_AB)}') print(f'|B \\ A| = {len(diff_BA)}: {sorted(diff_BA)}') print(f'|A^c| = {len(comp_A)}') print(f'|A △ B| = {len(sym_diff)} (検算: |A|+|B|-2|A∩B| = {len(A)+len(B)-2*len(inter)})') |
📤 実行例:
💬 包含と排除の原理 \(|A \cup B| = |A| + |B| - |A \cap B|\) を実値で確認: \(13 + 16 - 7 = 22\) ✓。 また対称差の公式 \(|A \triangle B| = |A| + |B| - 2|A \cap B| = 15\) も成立。 「太平洋に面し、 かつ人口 200 万超」の 7 県(首都圏 + 中京 + 仙台)は日本の経済中心軸そのものであり、 集合演算が地理経済の構造を抽出することを実演している。
ここまでで集合の基本演算(和・積・差・補・対称差)と Python での扱い方を見てきた。 しかし、 実務で 集合論が本当に効いてくるのは「複数のデータソースを突き合わせるとき」「変な欠損や重複を検出するとき」「ベン図的に世界を分けて確率を計算するとき」の 3 場面である。 本セクションでは SSDSE-B-2026(都道府県・年次データ)と SSDSE-A-2026(市町村データ)を題材に、 集合論が JOIN・データ品質・確率モデルの 3 領域でどう動いているかを具体的に解剖する。
| シーン | 集合論の役割 | SSDSE での具体例 | 使う演算 |
|---|---|---|---|
| ① データ統合 | 2 つ以上の表のキー集合を突き合わせる | SSDSE-B-2026 と SSDSE-E-2026 を「市町村コード」で結合 | ∩ (INNER), ∪ (OUTER), \\ (LEFT EXCL) |
| ② データ品質 | 「あるべき集合」と「実際の集合」の差を取る | 47 都道府県集合 \\ 実データ集合 = 欠損都道府県 | \\ (差集合) |
| ③ 確率モデル | 標本空間 Ω を排反な部分集合に分割 | 都道府県を「人口 100 万以上」「未満」に分割し条件付き確率 | 分割, P(A|B) |
集合論の感覚を磨くには、 まず「分割」が大事だ。 SSDSE-B-2026 の 2023 年データで都道府県を A = 「人口 100 万以上」と Aᶜ = 「100 万未満」に分けると、 これは Ω = {47 都道府県} の 2 分割になる。 さらに「年間出生数 (A4101) が 1 万人以上」を B とすれば、 A∩B, A∩Bᶜ, Aᶜ∩B, Aᶜ∩Bᶜ の 4 区画(2x2 のクロス表)が現れる。 下の散布図は、 ベン図が 連続変数空間上での分割として実装されている様子を一般的に示す(この図版そのものの変数は下のキャプションを参照)。
この「閾値で分けると集合になる」感覚が、 のちに 決定木のノード分割、 ロジスティック回帰の境界線、 クラスタリングなどに直結する。 機械学習はざっくり言えば「Ω を予測したいラベルに合わせてうまく分割する方法を探す問題」であり、 そのバックボーンが集合論である。
| 人口 \\ 出生数 | B: 1 万人以上 | Bᶜ: 1 万人未満 | 行合計 |
|---|---|---|---|
| A: 100 万人以上 | 20 (例: 東京, 大阪, 愛知, ...) | 17 (例: 青森, 岩手, 山形, ...) | 37 |
| Aᶜ: 100 万人未満 | 0 | 10 (例: 鳥取, 島根, 高知, ...) | 10 |
| 列合計 | 20 | 27 | 47 |
この表から条件付き確率も読める: P(A|B) = 20/20 = 1.0 (出生数 1 万人以上なら必ず人口 100 万以上)、 P(B|Aᶜ) = 0/10 = 0 (人口 100 万未満で出生数 1 万人以上の県は存在しない)。 つまり B は A の十分条件であり、 集合論的に言えば B ⊆ A が成立する。 「包含が確率 1 で厳密に成り立つ」ことを確率の言葉で語れるのが、 集合論を確率論に拡張した意義である。
このコードでやること: SSDSE-B-2026 の 2023 年データを読み、 「人口 100 万以上 (A)」「出生数 1 万人以上 (B)」の 2 つの集合を pandas の boolean Index で表現し、 4 つの分割集合の要素数を数える。
📥 入力データ (SSDSE-B-2026 抜粋):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] A = set(df[df['A1101'] >= 1_000_000]['Prefecture']) B = set(df[df['A4101'] >= 10_000]['Prefecture']) print('|A| =', len(A)) print('|B| =', len(B)) print('|A ∩ B| =', len(A & B)) print('|A ∪ B| =', len(A | B)) print('|A \\ B| =', len(A - B)) print('|A △ B| =', len(A ^ B)) |
📤 実行例:
💬 |A ∪ B| = |A| = 37 ということは B ⊆ A、 つまり「出生数 1 万人以上の県は、 すべて人口 100 万以上の県でもある」。 これは 包含写像そのものであり、 集合論の言葉でデータの構造的事実が言える。 包含が確認できたら、 次は「なぜ B は A に含まれるのか?」という因果や人口動態の説明に進める。
ヒストグラムは 連続データを集合に変換する装置である。 階級(bin)の境界を引いた瞬間に、 各階級は「値が範囲内に入る都道府県の集合」になる。 47 都道府県を 5 つの bin に分ければ、 互いに排反で和集合が Ω となる 分割 (partition)ができる。 この性質を σ-加法族と呼び、 確率測度を定義する数学的な土台になる。
| 人口階級 (千人) | 該当都道府県数 | 確率 P (= 件数/47) | 代表的な県 |
|---|---|---|---|
| [0, 1000) | 10 | 0.213 | 鳥取, 島根, 高知, 福井 |
| [1000, 2000) | 21 | 0.447 | 沖縄, 青森, 岩手 |
| [2000, 5000) | 7 | 0.149 | 広島, 京都, 茨城 |
| [5000, 10000) | 8 | 0.170 | 北海道, 大阪, 神奈川 |
| [10000, ∞) | 1 | 0.021 | 東京 |
| 合計 | 47 | 1.000 | — (Ω = 全 47 都道府県) |
合計確率が 1.0 になるのは、 5 つの階級が「互いに排反 (disjoint) かつ和が Ω」を満たすからである。 これが 確率分布の定義そのものであり、 集合論の分割概念がそのまま確率の 規格化条件に対応している。
このコードでやること: pandas.cut で人口を 5 階級に切り、 各階級を「都道府県の集合」として取り出す。 さらに各集合のサイズが Ω (47) の分割になっていることを assert で検証する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] bins = [0, 1_000_000, 2_000_000, 5_000_000, 10_000_000, 9_999_999_999] labels = ['~1M', '1-2M', '2-5M', '5-10M', '10M~'] df['階級'] = pd.cut(df['A1101'], bins=bins, labels=labels, right=False) partition = {lbl: set(df[df['階級'] == lbl]['Prefecture']) for lbl in labels} for lbl, s in partition.items(): print(f'{lbl}: {len(s)} 件') union_all = set().union(*partition.values()) assert len(union_all) == 47, '分割になっていない!' print('分割 OK (合計 47 都道府県, 互いに排反)') |
📤 実行例:
💬 5 つの集合の和が Ω と一致し、 互いに排反であることが確認できた。 これで「人口階級が ~1M となる確率は 17/47」と確率を語れる。 pandas.cut は集合論的に言えば「分割を定める写像」であり、 ビニング・離散化はすべて集合論の言葉で記述できる。
箱ひげ図で複数グループを横並びに表示するとき、 我々は暗黙のうちに「グループ = 集合の分割」を前提にしている。 たとえば「北海道・東北・関東・中部・近畿・中国・四国・九州」の 8 区分は、 47 都道府県を 8 つの排反な集合に分けた partitionである。 ある県が同時に 2 地方に属することは無いし、 どこにも属さない県もない。 これが「箱ひげ図でグループを並べる」可視化が成立する数学的根拠である。
実務で集合論が最も活躍するのは データ品質チェックである。 「47 都道府県すべてが揃っているはずだ」というドメイン知識を 期待集合 Eとして表現し、 実際のデータから抽出した 実集合 Rと比較する。 欠損は E \\ R で取れ、 重複や想定外の値は R \\ E で取れる。
| チェック項目 | 集合論的表現 | 何を意味するか |
|---|---|---|
| 欠損都道府県 | E \\ R | 期待にあるが実データに無いキー = 拾い忘れ |
| 想定外キー | R \\ E | 実データにあるが期待にないキー = タイポ・コード変更 |
| 完全一致 | E △ R = ∅ | 対称差が空 = 期待と実測が完全に一致 |
| 部分一致率 | |E ∩ R| / |E| | 期待に対するカバレッジ (リコール相当) |
| Jaccard 類似度 | |E ∩ R| / |E ∪ R| | 2 集合の重なり度 (推薦・クラスタリングで頻出) |
このコードでやること: SSDSE-B-2026 の特定年度に欠損があったら検出する。 期待集合 E は「47 都道府県」、 実集合 R は「実データに出現した都道府県」とし、 集合差で欠損を一発で取り出す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) EXPECTED = set([ '北海道', '青森県', '岩手県', '宮城県', '秋田県', '山形県', '福島県', '茨城県', '栃木県', '群馬県', '埼玉県', '千葉県', '東京都', '神奈川県', '新潟県', '富山県', '石川県', '福井県', '山梨県', '長野県', '岐阜県', '静岡県', '愛知県', '三重県', '滋賀県', '京都府', '大阪府', '兵庫県', '奈良県', '和歌山県', '鳥取県', '島根県', '岡山県', '広島県', '山口県', '徳島県', '香川県', '愛媛県', '高知県', '福岡県', '佐賀県', '長崎県', '熊本県', '大分県', '宮崎県', '鹿児島県', '沖縄県', ]) for y in [2021, 2022, 2023]: R = set(df[df['SSDSE-B-2026'] == y]['Prefecture']) missing = EXPECTED - R extra = R - EXPECTED jaccard = len(EXPECTED & R) / len(EXPECTED | R) print(f'{y}: 欠損 {len(missing)} 件 / 想定外 {len(extra)} 件 / Jaccard {jaccard:.3f}') |
📤 実行例:
💬 Jaccard が 3 年連続 1.000 なので、 SSDSE-B-2026 は 47 都道府県完全カバーが維持されている。 もし途中の年度で 0.957 (= 45/47) と出たら 2 県欠損を疑い、 欠損 set の中身を print(EXPECTED - R) で確認する流れになる。 これが 集合論ベースの欠損モニタリングの定型パターンである。
SQL や pandas.merge の JOIN は、 そのまま集合論の演算に翻訳できる。 これを把握しておくと「LEFT OUTER JOIN したら行数が増えた」「INNER JOIN したらキーが消えた」といった現象の原因が、 すべて 集合の重なり方として説明できるようになる。
| JOIN タイプ | 残るキーの集合 | 集合論の式 | 用途 |
|---|---|---|---|
| INNER | A ∩ B | A ∩ B | 両方にあるキーだけ残す |
| LEFT | A | (A ∩ B) ∪ (A \ B) | 左を主、 右の欠損は NaN |
| RIGHT | B | (A ∩ B) ∪ (B \\ A) | 右を主、 左の欠損は NaN |
| FULL OUTER | A ∪ B | A ∪ B | 両方を保持、 欠損は NaN |
| LEFT ANTI | A \ B | A \ B | 左にしかないキー (差分検出) |
| SYMMETRIC ANTI | A △ B | A △ B | どちらか片方だけにあるキー |
このコードでやること: SSDSE-B-2026 の異なる 2 年度のデータをキーで結合し、 INNER と OUTER の結果行数が集合演算 (A ∩ B, A ∪ B) と一致することを確かめる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df2012 = df[df['SSDSE-B-2026'] == 2012][['Prefecture', 'A1101']].rename(columns={'A1101': 'pop_2012'}) df2023 = df[df['SSDSE-B-2026'] == 2023][['Prefecture', 'A1101']].rename(columns={'A1101': 'pop_2023'}) A = set(df2012['Prefecture']) B = set(df2023['Prefecture']) inner = df2012.merge(df2023, on='Prefecture', how='inner') outer = df2012.merge(df2023, on='Prefecture', how='outer') print('|A ∩ B| =', len(A & B), '/ INNER rows =', len(inner)) print('|A ∪ B| =', len(A | B), '/ OUTER rows =', len(outer)) |
📤 実行例:
💬 SSDSE-B は 47 都道府県完全カバーなので A = B となり、 INNER と OUTER が同じ 47 行になる。 一方、 たとえば SSDSE-A (市町村) と SSDSE-B (都道府県) を結合する場合は A ⊋ B (市町村集合の方が大きい) となり、 INNER と OUTER の行数が大きく違ってくる。
| 落とし穴 | 起きる現象 | 対処 |
|---|---|---|
| ① 表記ゆれ | 「東京都」と「東京」を別要素扱い | 正規化辞書を用意し、 set 化前に統一 |
| ② 全角・半角混在 | 「A」「A」が別キー | unicodedata.normalize('NFKC', s) |
| ③ 空白 | 「 東京都 」と「東京都」が別要素 | .strip() を必ず通す |
| ④ NaN | set に nan が混入し常に「無い」と判定 | dropna() してから set 化 |
| ⑤ 集合 vs マルチセット | 重複が消えてカウントを失う | 必要なら collections.Counter を使う |
| ⑥ 順序を保持したい | set は順序を持たない | 順序付き集合は dict.fromkeys(seq) か pandas.Index.unique |
集合論の応用として、 2 つの集合の「似ている度」を測る指標が Jaccard 類似度である。 推薦システム・検索エンジン・クラスタリングの内部で頻出する。
$$ J(A, B) = \frac{|A \cap B|}{|A \cup B|} \quad \in [0, 1] $$J=1 は完全一致、 J=0 は重なりゼロ (排反)。 たとえば「2012 年の人口 100 万以上県集合」と「2023 年の人口 100 万以上県集合」を比較すれば、 11 年で「人口 100 万県」がどれだけ入れ替わったかが 1 つの数値で言える。
| 2 集合の例 | |A∩B| | |A∪B| | Jaccard | 解釈 |
|---|---|---|---|---|
| A=人口100万県(2012), B=人口100万県(2023) | 37 | 38 | 0.974 | 11 年でほぼ同じ顔ぶれ |
| A=人口200万県, B=出生数1.2万県 | 14 | 17 | 0.824 | 概ね一致するが完全ではない |
| A=東日本, B=西日本 | 0 | 47 | 0.000 | 完全に排反 |
ここまでで 有限集合の運用感は身についた。 集合論はこのあと、 無限集合の濃度 (アレフ数)、 順序数、 公理系 (ZFC) の独立性、 大きな基数、 強制法 (forcing) などへと延びていく。 現代の 機械学習における関数空間 (確率測度空間 L²) や 分散システムの一貫性証明 (CRDT は半束構造、 部分順序集合) なども、 突き詰めれば集合論の上に立っている。
| 分野 | 集合論の使われ方 | 代表概念 |
|---|---|---|
| 確率論 | 標本空間 Ω と σ-加法族で事象を定義 | σ-algebra, 測度 |
| 機械学習 | 仮説集合 H から best h を選ぶ | VC 次元, PAC 学習 |
| データベース | 関係 (relation) = タプルの集合 | 関係代数, JOIN/UNION |
| 分散システム | 半束 (join-semilattice) で一貫性 | CRDT, 部分順序集合 |
| 形式手法 | 状態空間 = 集合、 遷移 = 関係 | TLA+, Alloy |
集合論を授業で初めて触ったとき、 多くの学習者が次の 3 つの誤読をする: ①「和集合 ∪ は単なる加算だ」 ②「補集合は 残り全部 ではなく 母集団との差 である」 ③「対称差 △ は ∪ − ∩ ではなく ∪ ∖ ∩ である」。 ここでは SSDSE-B-2026(都道府県 = 47 件) を母集団 U として、 この 3 つを実値で潰す。
47 都道府県のうち A = 「人口 100 万超」 が 34 県、 B = 「面積 5,000 km² 超」 が 35 県、 重複 |A ∩ B| が 28 県だったとする。 加算なら 34 + 35 = 69 だが、 当然 47 を超えない。 これは 包除原理 |A ∪ B| = |A| + |B| − |A ∩ B| = 34 + 35 − 28 = 41 で正しい値 41 が得られる。 「重複を引く」の感覚が抜けると、 真夏のキャンペーン分析で「該当顧客数 1.2 倍」と過大計上する事故が起きる。
A = 「人口 100 万超」34 件のとき、 補集合は Ac = U ∖ A = 47 − 34 = 13 県。 ここで「補集合 = 全部」と読むと 47 件全部が Ac になってしまい、 pandas の ~mask が常に全行を選ぶ謎挙動を生む。 補集合は 常に U(母集団)に依存する相対概念 である。
対称差は A △ B = (A ∪ B) ∖ (A ∩ B) であり、 差の集合(要素) である。 |A △ B| = |A| + |B| − 2|A ∩ B| = 34 + 35 − 2·28 = 13。 これは A だけ ∪ B だけに属する県数、 すなわち「片方の条件でしか引っかからない県」が 13 県あるという意味になる。 「∪ − ∩」のような算術差ではなく、 集合演算の差であることを忘れない。
| 誤読 | 正しい定義 | SSDSE での値 |
|---|---|---|
| ∪ = 加算 | |A ∪ B| = |A| + |B| − |A ∩ B| | 41 県 |
| 補集合 = 全部 | Ac = U ∖ A | 13 県 |
| △ = ∪ − ∩ | A △ B = (A∪B) ∖ (A∩B) | 13 県 |
| ∅ = 0 ではない | ∅ = 要素を持たない集合 | |∅| = 0 |
| ∈ と ⊂ は同じ | ∈: 要素、 ⊂: 部分集合 | {東京} ⊂ A, 東京 ∈ A |
SQL の INNER / LEFT / RIGHT / OUTER JOIN は集合論の A ∩ B, A, B, A ∪ B にそのまま対応する。 ただし「キー一致だけが集合の所属判定」になる点に注意。 SSDSE-B-2026 の県コード(R01000~R47000)を共通キーに、 A = 「2023 年人口データを持つ県」、 B = 「2018 年人口データを持つ県」とした場合、 同年の SSDSE は両方 47 件揃っているため A = B = U で、 ∩ = ∪ = 47 になる。 この「自明な一致」を一旦確認しておくと、 欠損があった時の異常検知が容易になる。
| SQL JOIN | 集合演算 | pandas merge how | 結果サイズ (SSDSE) |
|---|---|---|---|
| INNER JOIN | A ∩ B | how='inner' | 47 |
| LEFT JOIN | A | how='left' | 47 |
| RIGHT JOIN | B | how='right' | 47 |
| FULL OUTER JOIN | A ∪ B | how='outer' | 47 |
| ANTI JOIN (A only) | A ∖ B | how='left' + indicator | 0 |
| SYMMETRIC DIFFERENCE | A △ B | outer + indicator != both | 0 |
実務で欠損 (例: B のみ 46 県しかない) のとき、 INNER は 46、 LEFT は 47、 RIGHT は 46、 OUTER は 47、 A ∖ B は 1(欠けた 1 県のコード)、 A △ B も 1 になる。 SSDSE のような 網羅型 パネルデータでは、 ANTI JOIN が空集合 ∅ であることを データ品質の合格基準 として使える。
SSDSE-B-2026 の 2023 年データから、 以下の 2 集合を定義します。
| 集合 | |集合| | 代表的な所属県 |
|---|---|---|
| $|A|$ | 37 | 人口 100 万以上の県(鳥取・島根・高知・福井 など 10 県を除く 37 県) |
| $|B|$ | 35 | 高齢化率 30% 以上の県(東京・神奈川・愛知・大阪・滋賀・沖縄 など 12 県を除く 35 県) |
| $|A \cap B|$ | 25 | 人口 100 万以上 かつ 高齢化率 30% 以上の県(北海道・新潟・長野・茨城・福島・広島・岡山・熊本 など) |
| $|A \cup B|$ | 47 | 47 都道府県すべて(補集合は空) |
| $|A \setminus B|$ | 12 | 人口 100 万以上で高齢化率 30% 未満(東京・神奈川・愛知・大阪・千葉・埼玉・京都・兵庫・福岡・宮城・滋賀・沖縄) |
| $|B \setminus A|$ | 10 | 高齢化率 30% 以上で人口 100 万未満(秋田・高知・島根・徳島・福井・佐賀・和歌山・山梨・香川・鳥取) |
包除原理の検算:$|A \cup B| = |A| + |B| - |A \cap B| = 37 + 35 - 25 = 47$ ✓(全 47 県と一致)
解釈:「人口が少なくて、 かつ若い県」は実は存在しない。 これは日本の人口動態の縮図 — 大都市は若くて人口集中、 地方は人口少なくて高齢化、 中間がない。
もう 1 つ集合を加えて 3 集合の包除原理を試します。
$$|A \cup B \cup C| = |A| + |B| + |C| - |A \cap B| - |A \cap C| - |B \cap C| + |A \cap B \cap C|$$
各項は Python セクションで計算しますが、 最終的に「日本のどの県もこの 3 条件のいずれかは満たす」ことが分かります。
$|A| = n$ なら $|\mathcal{P}(A)| = 2^n$。 SSDSE 47 都道府県の冪集合は $2^{47} = 140{,}737{,}488{,}355{,}328$ 個(約 141 兆)。 仮に 1 ms で 1 つの部分集合を吟味しても、 全部見終わるのに 4,470 年かかる。 これが 「ナイーブな全探索アルゴリズムが破綻する」 集合論的理由。
あるクラス 40 人の調査結果:
$A = $ 人口 100 万以上、 $B = $ 高齢化率 30% 以上 として、 $(A \cap B)^c$ を計算。
→ ド・モルガンの法則 $(A \cap B)^c = A^c \cup B^c$ が成立。
合成 2 集合で和・積・差・対称差を計算する。
1 2 3 4 5 6 | A = {1,2,3,4} B = {3,4,5,6} print(f"A∪B: {A|B}") print(f"A∩B: {A&B}") print(f"A-B: {A-B}") print(f"A△B: {A^B}") |
💬 手計算 (Step 2) と Python 出力が完全一致。
Python set 型と pandas で SSDSE-B-2026 の 47 都道府県を集合演算します。
🎯 このコードでやること:Python の組み込み set 型で、 和・積・差・対称差・部分集合判定を行う最小例。
📥 入力データ: 2 つの簡単な集合 A = {1,2,3,4,5}, B = {4,5,6,7,8}
1 2 3 4 5 6 7 8 9 10 11 | # Python の set 型で集合演算 A = {1, 2, 3, 4, 5} B = {4, 5, 6, 7, 8} print('A∪B =', A | B) print('A∩B =', A & B) print('A\\B =', A - B) print('A△B =', A ^ B) print('A⊆A∪B =', A.issubset(A | B)) print('|A| =', len(A), ' |A∩B| =', len(A & B)) print('包除 =', len(A) + len(B) - len(A & B)) |
📤 実行すると次の出力が得られる:
💬 結果の読み方:Python では | & - ^ が和・積・差・対称差。 包除原理 |A|+|B|-|A∩B| = 5+5-2 = 8 が |A∪B| = 8 と一致。 これが集合演算の最基礎。
🎯 このコードでやること:SSDSE-B-2026 から「人口 100 万以上」と「高齢化率 30% 以上」の 2 集合を作り、 |A|・|B|・|A∩B|・|A∪B| を計算し包除原理を検算する。
📥 入力データ: SSDSE-B-2026.csv の 2023 年 47 行。 関係列は A1101(総人口)・A1303(65 歳以上人口)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # SSDSE-B-2026 で 2 集合を作る import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023].copy() df['総人口'] = pd.to_numeric(df['A1101'], errors='coerce') df['高齢化率'] = pd.to_numeric(df['A1303'], errors='coerce') / df['総人口'] A = set(df[df['総人口'] >= 1_000_000]['Prefecture']) B = set(df[df['高齢化率'] >= 0.30]['Prefecture']) print(f'|A| (人口100万以上) = {len(A)}') print(f'|B| (高齢化率30%以上) = {len(B)}') print(f'|A∩B| = {len(A & B)}') print(f'|A∪B| = {len(A | B)}') print(f'包除原理 |A|+|B|-|A∩B| = {len(A) + len(B) - len(A & B)}') print('A∩B のメンバー (一部):', sorted(A & B)[:8]) print('A のみ (人口大・若い):', sorted(A - B)) |
📤 実行すると次の出力が得られる:
💬 結果の読み方:包除原理 37 + 35 − 25 = 47 が |A∪B| = 47 と一致 ✓。 「A のみ(人口大かつ若い)」12 県には東京・神奈川・愛知・大阪 など大都市と 沖縄 が含まれる。 全 47 県のうち「人口少なくかつ若い」県は存在しない — 日本の人口動態の縮図。
🎯 このコードでやること:pandas の isin・ブールマスク(~・|・&)で SSDSE の都道府県を絞り込む。 SQL の UNION/INTERSECT/EXCEPT に相当。
📥 入力データ: 上で読んだ df(2023 年 47 行)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # pandas で集合演算 (DataFrame / Series レベル) import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023].copy() df['総人口'] = pd.to_numeric(df['A1101'], errors='coerce') # 集合 A: 関東 1 都 6 県、 B: 関西 2 府 4 県 kanto = ['東京都', '神奈川県', '埼玉県', '千葉県', '茨城県', '栃木県', '群馬県'] kansai = ['大阪府', '京都府', '兵庫県', '奈良県', '滋賀県', '和歌山県'] A_df = df[df['Prefecture'].isin(kanto)] B_df = df[df['Prefecture'].isin(kansai)] print(f'|A| 関東 = {len(A_df)} 県、 総人口計 = {A_df["総人口"].sum():,} 人') print(f'|B| 関西 = {len(B_df)} 府県、 総人口計 = {B_df["総人口"].sum():,} 人') # A ∪ B (UNION 相当) union_df = df[df['Prefecture'].isin(kanto + kansai)] print(f'|A∪B| = {len(union_df)} 県、 総人口計 = {union_df["総人口"].sum():,} 人') # Aᶜ ∩ Bᶜ (関東でも関西でもない県 = NOT IN) others = df[~df['Prefecture'].isin(kanto + kansai)] print(f'|(A∪B)ᶜ| = {len(others)} 県 (47-13=34)') |
📤 実行すると次の出力が得られる:
💬 結果の読み方:関東 + 関西 = 13 県で日本の総人口 1.24 億のうち 6,379 万人 (51%)。 残り 34 県に 6,056 万人。 「2 つの地域だけで全国半分の人口」という日本の都市集中が、 集合演算 1 行で可視化できる。 SQL なら WHERE pref IN (...) と同義。
🎯 このコードでやること:3 集合 A=人口100万以上、 B=高齢化率30%以上、 C=年平均気温16℃以上 の包除原理を全項目検算する。
📥 入力データ: SSDSE-B-2026 の A1101 / A1303 / B4101 列。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # 3 集合の包除原理 import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023].copy() df['pop'] = pd.to_numeric(df['A1101']) df['aging'] = pd.to_numeric(df['A1303']) / df['pop'] df['temp'] = pd.to_numeric(df['B4101']) A = set(df[df['pop'] >= 1_000_000]['Prefecture']) B = set(df[df['aging'] >= 0.30]['Prefecture']) C = set(df[df['temp'] >= 16]['Prefecture']) lhs = len(A | B | C) rhs = (len(A) + len(B) + len(C) - len(A & B) - len(A & C) - len(B & C) + len(A & B & C)) print(f'|A|={len(A)}, |B|={len(B)}, |C|={len(C)}, |A∩B∩C|={len(A&B&C)}, |A∪B∪C|(LHS)={lhs}, RHS={rhs}') |
📤 実行すると次の出力が得られる(実行例):
💬 結果の読み方:左辺 = 右辺 = 47 で包除原理が成立 ✓。 「3 条件のいずれかを満たす県」が全 47 県、 「3 条件すべて満たす県」は 18 県(茨城・岡山・広島・熊本 など中規模・暖かい・高齢化進行)。
🎯 このコードでやること:47 都道府県の冪集合のサイズ ($2^{47}$) を計算し、 「全部探索したら何年かかるか」を見積もる。
📥 入力データ: SSDSE-B-2026 の都道府県名(47 件)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | # 冪集合のサイズ爆発 import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) prefs = df[df['SSDSE-B-2026'] == 2023]['Prefecture'].tolist() n = len(prefs) size = 2 ** n print(f'|U| = {n} 都道府県') print(f'|P(U)| = 2^{n} = {size:,}') # 1 ms/部分集合で全探索すると... years = size / 1000 / 86400 / 365 print(f'1 ms/集合で全探索 → {years:,.1f} 年') # 比較: 10 都道府県の冪集合は print(f'参考: |U|=10 なら |P(U)|={2**10:,} = 1,024 個 (1 秒で全探索)') |
📤 実行すると次の出力が得られる:
💬 結果の読み方:47 県の全部分集合を見るだけで 4,463 年。 これが「組合せ最適化問題は NP 困難」「特徴量選択にナイーブな全探索を使えない」根本理由。 集合論を知っていれば、 アルゴリズムの計算量が分かる。
このコードでやること: SSDSE-B-2026 の県コード集合に対して、 Python 標準 set / pandas Index / pandas merge(indicator=True) の 3 種類の API で同じ「対称差」を求め、 結果が一致することを確認する。 「同じ集合演算が 3 つの書き方で書ける」と理解すれば、 実務でデータ規模・型に応じた最適 API を選べる。
📥 入力データ (SSDSE-B-2026 抜粋):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df_2023 = df[df['SSDSE-B-2026'] == 2023] df_2018 = df[df['SSDSE-B-2026'] == 2018] # 1) Python 標準 set s_set = set(df_2023['Code']) ^ set(df_2018['Code']) # 2) pandas Index.symmetric_difference s_idx = df_2023.set_index('Code').index.symmetric_difference( df_2018.set_index('Code').index) # 3) merge(indicator=True) で対称差 m = df_2023.merge(df_2018, on='Code', how='outer', indicator=True) s_mrg = set(m.loc[m['_merge'] != 'both', 'Code']) print('set :', len(s_set)) print('Index :', len(s_idx)) print('merge :', len(s_mrg)) print('全て一致 :', s_set == set(s_idx) == s_mrg) |
📤 実行すると次の出力が得られる:
💬 3 つの API すべてで対称差が空集合 ∅(要素数 0)となり、 SSDSE-B-2026 の 2018 年と 2023 年で県コードに欠損が無いことを示す。 同じ集合演算を 3 通りで書き、 結果を == で比較する パターンは、 集合演算の正しさを確認するゴールドスタンダードとして覚えておくと良い。 規模が大きい (10⁶ 行超) 場合は set、 列単位の演算は Index、 結合と同時に必要な場合は merge が定石。
set は NaN を含めると 1 つの要素として扱うが、 == 比較が False になる。 集合化前に dropna() を必ず通す。frozenset ではなく tuple: 「東京→大阪」と「大阪→東京」を区別したいなら集合は使えない。 経路・順序がある場合は tuple + 比較関数で扱う。str.normalize('NFKC').str.lower() で正規化してから集合化する。{a} と書くと 1 個に潰れる。 個数が意味を持つ場合は collections.Counter を使う。set() は ∅ だが {0} は要素 0 を持つ 1 元集合。 len(s) == 0 で空判定するのが安全。集合の基本演算 (∪, ∩, 差集合, 補集合) は素朴に見えるが、 実は統計・機械学習の現場で「データの結合・フィルタリング・評価指標」のすべてに浸透している。 ここでは SSDSE-B-2026 都道府県データと典型タスクに即して、 集合演算が効く具体的場面を整理する。
SQL の INNER JOIN は左テーブルのキー集合 K_L と右テーブルのキー集合 K_R の共通部分 K_L ∩ K_R を取る操作に等しい。 LEFT JOIN は K_L 全体を保つ操作なので集合的には K_L (一方向の和) と読める。 SSDSE-B-2026 で「都道府県コード」をキーに人口データと産業データを結合するとき、 47 都道府県すべてが両方に存在するなら INNER と LEFT は一致するが、 たとえば沖縄・離島のみ片方欠ければ INNER は減り LEFT は欠損で残る。 集合演算で意識すると「なぜ行数が変わるか」を直感把握できる。
分類モデルの予測陽性集合を P、 真陽性集合を T とすると、 precision = |P ∩ T| / |P|、 recall = |P ∩ T| / |T|。 つまり共通部分の比率を異なる分母で割ったものに過ぎない。 SSDSE-B-2026 で「人口減少県」を 2 値分類するモデルを作ると、 「予測減少県」P と「実減少県」T の比較で性能が決まる。 集合のサイズ比として読めば、 「閾値を変えると P が動き、 P ∩ T と |P| の比が変わって precision が上下する」という挙動が腑に落ちる。
(A ∪ B)^c = A^c ∩ B^c は単なる論理規則ではなく、 データ抽出時の典型ミスを救う。 SSDSE-B で「人口 100 万未満 または 高齢化率 35% 超 ではない都道府県」を取りたいとき、 NOT (A ∪ B) = (NOT A) ∩ (NOT B) と書き換えれば「人口 100 万以上 かつ 高齢化率 35% 以下」というシンプルな条件に変換できる。 pandas で書くと df[~(df['pop']<1e6) | (df['aging']>0.35)] よりも df[(df['pop']>=1e6) & (df['aging']<=0.35)] のほうが意図が読みやすい。
k-fold CV では訓練データ集合 D を k 個に互いに素な部分集合 F_1, F_2, ..., F_k に分割する (F_i ∩ F_j = ∅ for i ≠ j, ∪ F_i = D)。 互いに素であることが保証されない場合 (例: 同一サンプルが複数 fold に出現) はリーク (data leakage) となり、 評価精度が水増しされる。 group-k-fold や time-series split など、 グループ単位で互いに素を担保する手法はすべて集合論の「分割」概念に対応する。
3 個の分類器 C_1, C_2, C_3 の多数決は、 「少なくとも 2 個が陽性と判定した集合」= (C_1 ∩ C_2) ∪ (C_2 ∩ C_3) ∪ (C_1 ∩ C_3) として書ける。 各分類器の予測陽性集合の組み合わせで定義されるので、 アンサンブルの効果は集合の重なり具合で説明される。 SSDSE で人口減少予測モデルを 3 種類組み合わせる際、 共通領域が大きいほど多数決はその領域に強く依存する。
文書 A と文書 B の単語集合を W_A, W_B とすると、 Jaccard 類似度 = |W_A ∩ W_B| / |W_A ∪ W_B|。 0 (重なりなし) から 1 (完全一致) の値域を持ち、 集合の重なり率そのもの。 SSDSE-B には文書はないが、 たとえば「都道府県の主要産業集合」を都道府県ごとに作って、 都道府県間の Jaccard 類似度を計算すれば、 産業構成が似た県のクラスタリングが可能。
3 集合のベン図には 8 領域 (内側 7 + 外側 1) ある。 確率的に推論するとき、 P(A) + P(B) + P(C) ≤ P(A ∪ B ∪ C) + 1 などの単純な不等式に閉じ込められないので、 包除原理 (inclusion-exclusion principle) で正しく分解する。
P(A ∪ B ∪ C) = P(A) + P(B) + P(C) − P(A ∩ B) − P(A ∩ C) − P(B ∩ C) + P(A ∩ B ∩ C)
これを SSDSE で「人口 100 万未満 ∪ 高齢化率 35% 超 ∪ 第 1 次産業優位」の都道府県数に当てはめると、 単純な和では二重計上が起きるので、 共通領域を差し引く必要がある。 全 47 県のうち、 上記 3 条件のいずれかに該当する県の正確な数を出すには、 必ず包除原理を適用する。
集合演算は記法こそ簡素だが、 結合・評価・分割・推論・類似度計算という統計実務の主要要素にすべて顔を出す。 ベン図的なイメージを身に付けておくと、 SQL・pandas・scikit-learn のドキュメントを読むときの「なぜこの結果になるのか」が腑に落ちやすくなる。
集合 S の要素数を |S| と書き、 これを濃度と呼ぶ。 SSDSE-B-2026 の都道府県集合 P について |P| = 47、 全国の市区町村集合 M については |M| ≒ 1,741 と覚えておくと、 集計テーブルの行数の妥当性チェックに即使える。 たとえば「都道府県 × 産業 20 分類」のクロス集計を作るとき、 期待行数は |P| × 20 = 940 行。 実際に出てきた DataFrame の行数がこれよりはるかに大きければ重複が、 小さければ欠損があると即座に判別できる。 濃度を意識する習慣は、 データ品質チェックの最も基本的かつ強力な手段の 1 つである。
n 個の要素を持つ集合 S の部分集合は全部で 2^n 個ある (空集合と S 自身を含む)。 特徴量選択で「k 個の特徴のうち、 どの組合せがベストか」を全数探索する場合、 候補数は 2^k に膨らむ。 SSDSE-B-2026 の指標が約 100 種類あるとして、 そこから人口予測モデルに使う特徴を全数探索すると 2^100 通り (10^30 オーダー) となり、 現実的には不可能。 だからこそ前進選択・後退削除・LASSO といった部分集合探索の効率化手法が必要となる。 集合の濃度爆発が、 特徴量選択の難しさの根本原因である。
2 集合 A, B の直積 A × B = {(a, b) | a ∈ A, b ∈ B} の部分集合を「A から B への関係」と呼ぶ。 SSDSE-B-2026 で「都道府県 P と統計指標 I の関係」を考えると、 P × I の 47 × 8 = 376 要素の中から「その指標が全国トップ 10 に入る」というペアだけを抜き出した部分集合が、 県と得意指標の関係表になる。 関係データベース (RDB) は文字通り「関係 = 直積集合の部分集合」を扱う仕組みであり、 集合論の延長線上にある。
厳密には、 関数 f: A → B も「A × B の特殊な部分集合 (各 a に対し b がただ 1 つ対応する部分集合)」として集合論で定義される。 SSDSE で「都道府県 → 県庁所在地」の対応を関数 f と書くと、 f は P × C の部分集合であり、 各都道府県 a に対して県庁所在地 b がちょうど 1 つ対応する。 機械学習モデル m: X → Y も「入力空間 X と出力空間 Y の直積 X × Y の部分集合」として読める。 学習とはこの部分集合を観測データから推定する作業に他ならない。
確率論の出発点である確率空間 (Ω, F, P) も集合論で構成される。 Ω は標本空間 (起こりうる全結果の集合)、 F は事象集合 (Ω の部分集合の集まり)、 P は F の各要素に [0, 1] の値を割り当てる関数。 SSDSE-B で「無作為に 1 つ都道府県を選んだとき、 人口 100 万未満である事象 A」を扱う場合、 Ω = 47 都道府県、 A は Ω の部分集合 (該当する県の集合)、 P(A) = |A| / |Ω|。 確率の加法定理 P(A ∪ B) = P(A) + P(B) − P(A ∩ B) は、 集合の包除原理を確率に直訳したもの。
位相空間 (topological space) は「集合 X とその開集合系 τ の組」として定義される。 開集合系は X の部分集合の集まりで、 (1) 空集合と X 自身を含む、 (2) 任意個の和集合で閉じる、 (3) 有限個の共通部分で閉じる、 という 3 条件を満たすもの。 これだけで連続性・収束・連結性などの幾何的概念が定義可能となる。 機械学習では多様体学習 (manifold learning) や位相的データ解析 (TDA: Topological Data Analysis) でこの考え方が利用される。 集合論は単なる「データ集めの道具」ではなく、 現代の幾何・解析・確率論すべての土台である。
集合論の最も驚くべき成果の 1 つは「無限にも大小がある」というカントールの定理。 自然数全体の集合 N は「可算無限」 (要素を 1, 2, 3, ... と一列に並べられる) だが、 実数全体 R は「非可算無限」 (どんな一列も漏れがある)。 機械学習で扱うパラメータ空間は連続値なので非可算無限、 だからこそ最適化問題は離散探索ではなく勾配法に頼る。 「無限の濃度の違い」が、 連続最適化と組合せ最適化の根本的な違いを生んでいる。
SQL の集合演算句は名前のとおり集合論そのもの。 UNION は和集合 (重複削除あり)、 UNION ALL は多重集合の和 (重複保持)、 INTERSECT は共通部分、 EXCEPT (または MINUS) は差集合に対応する。 SSDSE-B のデータを SQL で扱うとき、 「人口減少県 EXCEPT 高齢化県」と書けば、 人口減少しているが高齢化していない県の集合が得られる。 NULL の扱いには注意が必要 (集合演算は NULL を等価と見るが WHERE 句は等価と見ない) で、 ここを間違えると意図しない結果になる。
集合論は数学基礎論の華やかな話題と見られがちだが、 実務での価値は「データ操作の意図を明確に言語化できる」点にある。 「INNER JOIN を取った」「unique を取った」「dropna した」という操作の背後にはすべて集合演算が潜んでおり、 これを意識すると「なぜこの結果になったのか」を 1 段深い層で説明できる。 SSDSE-B-2026 の都道府県データに対して、 集合演算をベン図と言葉と pandas コードの 3 つで同時に扱える力を養うのが、 本ページの究極のゴールである。
標準 SQL は集合演算を直接サポート。 UNION は和集合 (重複除去)、 UNION ALL は和集合 (重複保持)、 INTERSECT は共通部分、 EXCEPT (MySQL では MINUS) は差集合。 SSDSE-B-2026 で「人口減少県と高齢化県の共通部分」を SQL で表現: SELECT 都道府県 FROM 人口減少県 INTERSECT SELECT 都道府県 FROM 高齢化県。 概念は集合論と完全に一致。 さらに SQL の DISTINCT は集合化操作 (重複削除して一意集合化)、 GROUP BY は同値類による商集合への射影と見ることができる。 SQL を集合論の言語として読み直すと、 クエリ設計の意図が明瞭になり、 結果の正しさを論理的に検証しやすくなる。 特に大規模データウェアハウスで複雑な JOIN を扱う際、 集合論的思考は不可欠な道具となる。
pandas Index・Series・DataFrame で集合演算: (1) Index.union(other), Index.intersection(other), Index.difference(other)、 (2) set(s1).union(set(s2)) で Python set 経由、 (3) df1.merge(df2, how='inner') は ∩、 how='outer' は ∪。 SSDSE-B-2026 で複数年データを結合する際の how パラメータは集合論的に解釈可能。 how='left' は左集合を基準にした選択結合、 how='right' は右基準、 how='cross' は直積 (デカルト積) である。 さらに isin は元の所属判定 (∈)、 ~df.isin(...) は補集合フィルタ、 combine_first は欠損埋めだが集合的には「左集合優先の合併」と読める。 これらを集合論の言葉で整理すると pandas の挙動が直感的に理解できる。
Python の set はハッシュテーブルで O(1) の検索・追加・削除。 frozenset は immutable で hashable、 set の set に使える。 集合演算の演算子: | (∪), & (∩), - (差), ^ (対称差)。 大規模データでは set 操作が list より圧倒的に高速。 例えば 47 都道府県のうち「人口減少県」と「高齢化県」の共通集合を求める場合、 list の二重ループでは O(n×m) だが、 set の & 演算では平均 O(min(n,m))。 100 万要素規模では数千倍の速度差が出る。 また set リテラル {1,2,3}、 内包表記 {x for x in iterable} も活用可能。 ただし set の要素は hashable でなければならず、 list や dict は要素にできない点に注意。
分類モデル評価の Precision/Recall/F1/IoU はすべて集合の比。 (1) Precision = |P ∩ T| / |P| (予測陽性のうち正解)、 (2) Recall = |P ∩ T| / |T| (正解陽性のうち検出)、 (3) F1 = 2 × P × R / (P + R)、 (4) IoU (画像セグメンテーション) = |A ∩ B| / |A ∪ B|。 SSDSE で「人口減少県」予測モデルを評価する際、 P = 予測集合、 T = 真集合として計算。 さらに Jaccard 係数 = |A ∩ B| / |A ∪ B| は IoU と同一概念で、 文書類似度・推薦システム・クラスタ評価などで広く使われる。 Dice 係数 = 2|A ∩ B| / (|A| + |B|) も類似だが分母が異なる。 これら指標は集合論の語彙で統一的に理解でき、 「なぜこの式なのか」が直感化される。
k-means, hierarchical clustering, DBSCAN などすべて「データを互いに素な部分集合に分割」する集合論的タスク。 評価指標も集合論ベース: Adjusted Rand Index, Normalized Mutual Information, Silhouette Score。 SSDSE-B-2026 で 47 都道府県を産業構成でクラスタリングし、 例えば 4 クラスタに分けると、 各クラスタは互いに素で 4 クラスタの合併が全体集合。 これは集合論の「分割 (partition)」の定義そのもの。 ファジィクラスタリング (Fuzzy C-Means) は各要素が複数集合に確率的に属する「ファジィ集合」の概念に対応し、 重複ありクラスタリング (overlapping clustering) は互いに素の条件を緩めた集合族として扱う。 ARI は「2 つの分割がどれだけ一致するか」を集合論的に測る指標である。
3 個の分類器の多数決は集合演算: 「少なくとも 2 個が陽性」= (C1 ∩ C2) ∪ (C2 ∩ C3) ∪ (C1 ∩ C3)。 Voting Classifier (sklearn), Bagging, Random Forest など、 すべて集合論的に解釈可能。 「Diversity を高める」とはアンサンブル構成集合の交差を小さくすること。 Bagging のブートストラップサンプリングは元集合からの復元抽出で、 各学習器が見る部分集合の交差が「out-of-bag (OOB) sample」となり評価に使われる。 Stacking は複数学習器の予測集合をメタ学習器の特徴として再利用し、 これも集合論的には「予測空間への射影と再結合」と読める。 「弱学習器の独立性」とは予測集合の対称差が大きいことに他ならない。
(1) 重複行削除 = 集合の一意化 (df.drop_duplicates())、 (2) 外れ値除外 = 全集合から外れ値集合の差、 (3) 欠損行除去 = 全集合 - 欠損行集合 (df.dropna())、 (4) フィルタリング = 部分集合抽出 (df[df['col'] > threshold])。 すべて集合論の演算として理解可能。 さらに条件付き置換 (df.loc[cond, 'col'] = value) は「部分集合への写像の制限と更新」、 マージによる補完 (df1.merge(df2, how='left')) は「左集合上での右集合からの値の引き戻し」と解釈できる。 データクリーニングの全工程を集合演算として整理すると、 副作用の少ない再現可能なパイプラインが組みやすくなる。 これは MLOps の文脈でも重要視される。
matplotlib-venn, plotly-venn で 2-3 集合ベン図を描画可能。 4 集合以上は UpSet plot (PyUpSet, UpSetR) が標準。 SSDSE-B-2026 で「人口減少県」「高齢化県」「第 1 次産業県」の 3 集合ベン図を描けば、 各組み合わせの都道府県数を可視化できる。 ベン図は 3 集合までは円で表現可能だが、 4 集合以上では円では領域の交差を完全に表現できず、 楕円や凸でない曲線を必要とする。 そのため大量の集合の重複構造を見るには UpSet plot がはるかに優れている。 UpSet plot は集合の組み合わせをマトリクスで表現し、 各組み合わせのサイズを棒グラフで示す。 ゲノミクスやテキスト解析など多集合の比較が必要な領域で標準的に使われている。
(1) データベース理論: リレーショナルモデルは集合論ベース (Codd 1970)、 (2) 計算理論: チューリングマシン・帰納的可算集合、 (3) 形式言語: アルファベットの集合からの再帰的構築、 (4) 型理論: 部分型関係は集合の包含関係、 (5) 群論・環論: 代数構造は集合 + 演算。 集合論はあらゆる計算機科学概念の基盤。 関数型プログラミングの型システム (Haskell の代数的データ型、 Scala の case class、 TypeScript の union/intersection types) はすべて集合論的構成。 union type は和集合、 intersection type は積集合、 product type は直積。 Kotlin の sealed class は有限集合の枚挙的定義。 こうした抽象が日常のコーディングに浸透している。
(1) A = 人口減少率 5% 以上の県、 B = 高齢化率 35% 以上の県、 C = 第 1 次産業優位県 として、 A ∪ B ∪ C, A ∩ B ∩ C, A - B などを計算。 (2) 各集合のサイズ、 ベン図、 包除原理の検証。 (3) 都道府県のクラスタリング結果を集合として表現し、 ARI で比較。 これら演習で集合論の実装力が身につく。 さらに発展課題として、 (4) 各都道府県の経年変化を「同一県が異なる年で異なる集合に属する」マルチセット問題として扱う、 (5) 集合演算の包除原理を 3 集合以上で実装し公式と計算結果が一致することを確認、 (6) 「人口」「経済」「産業」など複数指標で集合を定義し、 多次元的な集合比較を行うことで、 集合論を実データ分析の武器として身につけられる。
Zermelo-Fraenkel 集合論 (ZFC) は現代数学の標準的基礎。 連続体仮説、 選択公理、 Russell のパラドックス (set of all sets that don't contain themselves) などの哲学的問題は、 集合論の限界と魅力を示す。 これらは直接データサイエンスに使わないが、 「集合とは何か」の理解を深める。 Russell のパラドックスは「自分自身を含まない集合の集合」を考えると矛盾が生じるという問題で、 これを解決するため公理的集合論 (ZFC) が整備された。 選択公理は「任意の空でない集合の族から各集合の代表を 1 つずつ選べる」という直感的に正しそうな主張だが、 Banach-Tarski のパラドックスのような反直感的結果も導く。 これらは数学基礎論の魅力的な探求対象である。
集合論は単独で学ぶより、 SQL・pandas・ML・統計・可視化のすべての場面で「集合演算として何が起きているか」を意識的に追うことで真価を発揮する。 SSDSE-B-2026 のような実データで、 都道府県の組み合わせを集合演算で操作する練習が、 抽象的概念と実務スキルを結びつける最良の方法である。 統計学では確率空間が「標本空間 (集合) + 事象の σ-加法族 (集合の集合) + 確率測度」として定義され、 集合論なしには確率論すら定義できない。 機械学習の学習データ・検証データ・テストデータの分割、 交差検証の fold 設計、 サンプリング戦略 — すべて集合演算の応用である。 集合論を「共通言語」として身につければ、 異なる分野・ツール・抽象度をまたいで思考を統合できるようになる。
set() もこの性質を満たす。set([1,1,2]) も自動的に重複を除去するので注意。set は順序保証なし、 list は順序あり、 Python 3.7+ の dict は挿入順保持。WHERE x IN (NULL) は常に偽。 pandas の NaN も同様。 集合演算前に dropna() や COALESCE で前処理を。| 層 | 上位概念 | 下位・派生 | 応用先 |
|---|---|---|---|
| 公理 | 数学基礎論 | ZF, ZFC, NBG, MK | 数学全般の基盤 |
| 演算 | 集合演算 | ∪, ∩, \, △, ᶜ, ×, 𝒫 | SQL, pandas, NumPy |
| 構造 | 集合 + 演算 | 群、 環、 体、 束、 位相空間 | 抽象代数、 トポロジー |
| 関係 | $A \times B$ の部分集合 | 関数、 同値関係、 順序関係 | RDBMS、 関数型言語 |
| 濃度 | 集合の「大きさ」 | 有限・可算・連続体濃度 | 確率測度、 ルベーグ積分 |
| 論理 | 記号論理 | 命題論理、 述語論理、 ブール代数 | プログラミング論理、 AI 推論 |
| 圏論 | 集合論の一般化 | 射、 関手、 自然変換 | Haskell、 関数型 ML |
「集合論」は 確率論・統計学・データベース・論理学の共通基盤 として、 上流の数学的厳密性と下流の SQL や Pandas 操作を結ぶ抽象言語である。 ベン図で直感を掴み、 包含関係や演算則を確率や集約処理にそのまま転用できる。
集合論は確率・データベース・ベン図のすべての土台で、 ∈ ⊂ ∪ ∩ の記号を読めるようになるだけで統計・SQL・論理回路が一段深く理解できる。
「集合」をどう扱うかは、 要素の重複と順序の有無で判断する。
A | B、 積 (∩) → A & B、 差 (\) → A - B、 対称差 (Δ) → A ^ BSSDSE-B-2026 で「人口減少地域」と「高齢化地域」の共通県を抽出する場合は set(pop_decline) & set(aging) で集合演算が直接書ける。
本文ではベン図・包除原理・ド・モルガンの法則など「ある時点で固定された集合」の演算を扱いました。 ここでは一歩進めて、 データ分析の現場で使う集合がほぼすべて 内包的定義 $\{x \in U \mid P(x)\}$ —「述語 P(条件式)+閾値+時点」で決まるスナップショット— であることに注目します。 述語・閾値・時点のどれか 1 つが動くと、 同じ名前の集合でも中身は別物になります。
集合 $A \subseteq U$ は、 指示関数(indicator function) $\mathbf{1}_A : U \to \{0,1\}$($x \in A$ なら 1、 そうでなければ 0)と 1 対 1 に対応します。 pandas で df['A1101'] >= 1_000_000 と書いたときにできる True/False の列が、 まさに指示関数そのものです。 この対応で集合演算は0/1 列の算術に翻訳できます。
| 集合の言葉 | 指示関数の言葉 | pandas の言葉 |
|---|---|---|
| 要素数 $|A|$ | $\sum_x \mathbf{1}_A(x)$ | mask.sum() |
| 確率 $P(A)=|A|/|U|$ | $\mathbf{1}_A$ の平均 | mask.mean() |
| 積集合 $A \cap B$ | $\mathbf{1}_A \cdot \mathbf{1}_B$ | maskA & maskB |
| 和集合 $A \cup B$ | $\mathbf{1}_A + \mathbf{1}_B - \mathbf{1}_A\mathbf{1}_B$ | maskA | maskB |
| 補集合 $A^c$ | $1 - \mathbf{1}_A$ | ~maskA |
和集合の行の両辺の平均(期待値)を取ると $P(A \cup B) = P(A) + P(B) - P(A \cap B)$ — 包除原理は「指示関数の恒等式の期待値」だった、 と分かります。 さらに 2 つの指示関数のピアソン相関を取れば「集合 A と B の重なりが偶然より多いか少ないか」を測れます(φ 係数。 発展で後述)。
(1) 閾値近傍の不安定性。 本文の集合 B(高齢化率 = A1303/A1101 が 30% 以上)は閾値 30% に依存しています。 SSDSE-B-2026 の 2023 年データで閾値を 1 ポイントずつ動かすと、 |B| は次のように大きく変わります(実測値)。
| 閾値 | 29% 以上 | 30% 以上 | 31% 以上 | 32% 以上 |
|---|---|---|---|---|
| |B|(47 県中) | 38 | 35 | 28 | 23 |
境界付近には 兵庫県 29.96%・広島県 30.13% のように0.2 ポイント差で所属が分かれる県が並びます(ほかに宮城 29.24%・京都 29.70%・栃木 30.21% など)。 「集合のサイズ」を根拠に結論を出すときは、 閾値を少し動かしても結論が保つかの感度チェックが必須です。
(2) 時点でメンバーが入れ替わる。 同じ述語「高齢化率 30% 以上」でも、 2012 年の B は 秋田県(30.67%)と高知県(30.09%)のわずか 2 県。 それが 2023 年には 35 県 に拡大しました(実測値。 $B_{2012} \subseteq B_{2023}$ で脱退ゼロ・33 県が新規加入という単調増加)。 一方、 集合 A(人口 100 万以上)では逆向きの移動が起きています:秋田県は 2012 年 106.3 万人で A に所属していましたが、 2023 年には 91.4 万人となり脱退($A_{2012} \setminus A_{2023} = \{\text{秋田県}\}$)。 年をまたいで「集合 A」を比較するときは、 全体集合 U と述語・閾値を固定した上で「どの年のスナップショットか」を必ず明示しないと、 同じ記号 A が別の集合を指してしまいます。
(3) 重なりの大小は「独立の目安」と比べて初めて意味を持つ。 2023 年の実データでは $P(A) \cdot P(B) = (37/47)(35/47) \approx 0.586$ に対し $P(A \cap B) = 25/47 \approx 0.532$。 指示関数同士の相関(φ 係数)は −0.304(実測値)で、 「人口 100 万以上」と「高齢化率 30% 以上」は負の関連(大都市圏ほど高齢化率が 30% に達しにくい)です。 |A∩B| = 25 という数だけ見ると「25 県も重なっている」と感じますが、 独立を仮定した期待値 47 × 0.586 ≈ 27.5 県より少ない。 本文の 🎮 ウィジェットでスライダーを |U|=47、 |A|=37、 |B|=35、 |A∩B|=25 に合わせると、 この「やや負の関連」の判定を再現できます。