論文一覧に戻る 📚 用語集トップ 🗺 概念マップ
📚 用語解説
📚 用語解説
集合
Set
数学基礎

🔖 キーワード索引

要素和集合積集合差集合ベン図冪集合写像Venn包除原理確率

別名・略称:(なし)

set theory」は統計データ分析の文脈で扱う重要概念のひとつ。 本ページでは「set theory」を取り巻く中核キーワードを以下にチップで一覧化する。 各キーワードは関連する概念・手法・道具立てを含み、 文献検索や学習計画の起点になる。

set theory / 集合和集合 ∪積集合 ∩差集合 \補集合 Aᶜ対称差 △ベン図包含 ⊂べき集合 2ᴬ直積 A×BDe Morgan 則確率論の基礎

これらのキーワードは「set theory の理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。

💡 30秒で分かる結論

🍰 まずはやさしく

集合は、ものの集まりのことです。

データの整理や確率の計算に使います。

部活のメンバーをまとめるようなものです。

ここでは集合の基本と計算方法を読みます。

集合(Set):要素の集まり。 確率の基礎

💡 データサイエンス現場で出てくる集合演算パターン 10

  1. 重複除去df.drop_duplicates() → 行集合を取る
  2. カテゴリの全集合df['col'].unique() → 出現するカテゴリの集合
  3. カテゴリのカーディナリティdf['col'].nunique() → 集合のサイズ
  4. 2 集合の交差set(df1['id']) & set(df2['id']) → 共通顧客 ID
  5. セット差set(df1['id']) - set(df2['id']) → 解約顧客
  6. 所属判定df[df['pref'].isin(['東京','大阪'])] → サブセット抽出
  7. 反所属判定df[~df['pref'].isin(['北海道'])] → 補集合
  8. JOIN による直積df1.merge(df2, how='cross') → デカルト積
  9. 分割train_test_split(df, test_size=0.2) → 互いに素な分割
  10. k-foldKFold(n_splits=5) → 5 分割(互いに素・和が全データ)

これらの背後にあるのはすべて集合演算。 集合論を知っていればパフォーマンス・正確性の両面で優れたコードが書ける。

🎲 集合論 → 確率論への橋渡し

集合論を覚えたら、 次は 確率論。 すべての確率の公式は集合論で表現される。

確率論の用語集合論的表現SSDSE 例
標本空間 Ω全体集合 U47 都道府県すべて
事象 AΩ の部分集合人口 200 万以上の県
確率 P(A)|A| / |Ω|(等確率の場合)16 / 47 ≒ 0.340
A または BA ∪ BP(A ∪ B) = P(A) + P(B) − P(A ∩ B)
A かつ BA ∩ B独立なら P(A) × P(B)
A でないAᶜ = Ω \ AP(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_AA → A の特別な射
合成関数 f∘g射の合成結合律を満たす
部分集合 ⊆単射 (mono)包含写像
集合の積 A × B圏の積普遍性で特徴付け
写像族関手 (Functor)圏 → 圏 の写像
関係自然変換関手 → 関手

圏論は数学を 構造の構造 として見る方法。 関数型プログラミング (Haskell の Monad は圏論の概念)、 機械学習の理論基盤 (Deep Learning as Functor)、 量子計算 (圏論的量子論) 等で再評価されている。

🎯 写像 (関数) の 3 分類

関数 $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) 推薦・検索・データ分割など実応用。

📍 あなたが今見ているもの

🍰 まずはやさしく

集合は、数学や統計の共通言語です。

データ分析を正しく行うために使います。

スマホのアプリでデータを分ける時に役立ちます。

定義から実装までを順番に読みましょう。

確率=集合への測度」と聞くと急に難しく感じますが、 要は 「事象という集合に確率という重みを振る」 仕組み。 また、 SQL の UNION ALL、 pandas の merge、 機械学習の クラスラベル も集合論で考えられます。 すべての数学・統計の 基礎言語

本ページでは「set theory」を扱う。 統計データ分析コンペティション (2026) の教材で、 SSDSE-B-2026 (47 都道府県 × 複数年 × 100 超列) の実データを使った再現可能な学習を目指す。

「set theory」は統計・データサイエンスの体系における重要概念のひとつ。 本ページは「定義・直感・数式・実装・落とし穴・関連手法」の 6 視点で構成され、 各視点は独立して読めるが順序通り読むと体系的な理解が得られる。

🎨 直感で掴む

🍰 まずはやさしく

集合は、グループ分けのようなものです。

共通点を持つものを一まとめにするために使います。

クラスの男子だけを集めるような例です。

図を使って、集合の関係性を読みましょう。

「集合」と聞くと数学の抽象概念に感じるかもしれませんが、 身の回りはすべて集合でできています。 「クラスの男子」「東京都に住む人」「赤い花の品種」— 何かを属性で区切って一括りにしたら、それが集合です。 19 世紀末にカントール (Georg Cantor) が 無限集合の比較 を可能にしたことで、 現代数学・確率論・統計学・データベース・プログラミングのすべての基礎言語になりました。

集合演算 7 種類の早見表

演算記号読み方意味PythonSQL
和集合A ∪ Bエー かつ ビーA または BA | BUNION
積集合A ∩ Bエー まつ ビーA かつ BA & BINTERSECT
差集合A \ Bエー まいなす ビーA で B でないものA - BEXCEPT
対称差A △ Bエー さんかく ビーどちらか片方のみA ^ Bなし
補集合Aᶜえー こんぷりA でないもの全部 (U − A)U - ANOT IN
部分集合A ⊆ Bえー さぶせっと びーA の全要素が B にもA.issubset(B)
直積A × Bえー かける びー{(a, b) | a∈A, b∈B}itertools.productCROSS 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 セクションで検算)。

集合論の階層(カントール → ツェルメロ)

  • 素朴集合論(1874-):カントールが提唱、 直感的な集合定義 → ラッセルのパラドックスで矛盾発見
  • 公理的集合論(1908-):ツェルメロが ZF 公理系を提唱、 1922 年 ZFC (選択公理) に発展。 現代数学の基盤
  • 記述集合論:実数の部分集合の構造を研究、 解析学・確率論の理論基盤
  • 圏論(1942-):集合と関数を一般化、 関数型プログラミング・ML 理論で再評価

🎮 触って理解する

2 つの集合 A・B のベン図です。 円をドラッグして重なりを変えたり、 スライダーで全体集合 |U| や各集合の要素数 |A|・|B|・|A∩B| を変えると、 選んだ演算の領域が色づき、 要素数と確率がリアルタイムに更新されます。 初期値は SSDSE-B-2026 の 47 都道府県を全体集合 U に見立てた例です。

💡 A・B の円の中心付近をドラッグすると動かせます(タッチ操作対応)。

演算を選ぶ
📊 選択中:A∪B(和集合)
領域要素数確率 P
選択領域370.787
|A|300.638
|B|250.532
|A∩B|180.383
|A∪B|370.787
包除原理の検算: |A∪B| = |A| + |B| − |A∩B| = 30 + 2518 = 37 ✓ 一致
独立の目安: もし A・B が独立なら P(A∩B)=P(A)·P(B)=0.339。 実際の P(A∩B)=0.383 と比べるとやや正の関連

直感:要素の集まりと演算

上のベン図で、 円 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ᶜ)と一致することを図で確認できます。 関連:確率ベン図独立の各ページ。

📐 定義 / 数式

🍰 まずはやさしく

集合は、数式で表せるルールです。

正確に計算して答えを出すために使います。

買い物リストの重複を消すような考え方です。

計算の法則や、数学的な定義を読みましょう。

【包除原理】
$$|A \cup B| = |A| + |B| - |A \cap B|$$ $$|A \cup B \cup C| = |A| + |B| + |C| - |A \cap B| - |B \cap C| - |A \cap C| + |A \cap B \cap C|$$
【ド・モルガンの法則】
$$(A \cup B)^c = A^c \cap B^c, \quad (A \cap B)^c = A^c \cup B^c$$
【冪集合】
$$\mathcal{P}(A) = \{ S : S \subseteq A \}, \quad |\mathcal{P}(A)| = 2^{|A|}$$

📐 ZFC 公理系(9 つの公理)

現代数学の標準的な集合論の基盤。 1908 年 Zermelo、 1922 年 Fraenkel 拡張、 選択公理 (C) を含めて ZFC。

  1. 外延性公理:同じ要素を持つ集合は等しい。 $\forall x (x \in A \Leftrightarrow x \in B) \Rightarrow A = B$
  2. 空集合の公理:要素を持たない集合 ∅ が存在する。
  3. 対の公理:任意の a, b に対し {a, b} が存在。
  4. 和集合の公理:集合の集合 𝒜 の和集合が存在。
  5. 冪集合の公理:任意の A の冪集合 𝒫(A) が存在。
  6. 無限公理:自然数を含む無限集合が存在。
  7. 置換公理:集合の像(関数値)も集合。
  8. 正則性公理:$A \ne \emptyset$ なら $A$ と互いに素な要素を持つ。 → 無限降下列の禁止。
  9. 選択公理 (C):互いに素な非空集合族から、 各々から 1 つ要素を選ぶ関数が存在する。

選択公理は 1904 年に Zermelo が「整列可能定理」の証明に使ったとされ、 当時は非構成的すぎると批判された。 現代では「Banach-Tarski のパラドックス(球を 5 つに分けて 2 つの球に再構成可能)」など反直観的結論を導くが、 数学全般の便利さから受け入れられている。

❓ FAQ

Q1. 「集合」と「リスト」の違いは?

集合は 重複なし・順序なし。 リストは 重複あり・順序あり。 Python の set vs list。 大量の「あるか/ないか」判定が必要なら set が O(1)、 順序保持や重複可ならリスト。

Q2. 集合論は中学・高校でどこまで習う?

中学:要素・部分集合・和集合・積集合・補集合の基本記号。 高校 (数学 A):包除原理、 ベン図、 直積。 大学:公理的集合論、 濃度、 順序数、 ZFC。

Q3. Jaccard 係数とは?

$J(A, B) = \dfrac{|A \cap B|}{|A \cup B|}$。 2 集合の「重なり度合い」を 0 〜 1 で表す。 検索エンジン、 推薦システム、 文書類似度に頻出。 上の SSDSE 例で $J(A,B) = 25 / 47 = 0.532$。

Q4. 集合と確率はどう繋がる?

確率測度論では 「事象 = 標本空間 Ω の部分集合」。 確率は事象を [0,1] にマップする関数 $P: \mathcal{F} \to [0,1]$。 σ-加法族 (σ-algebra) は「測れる集合の集まり」で、 集合論の言葉そのまま。

Q5. SQL と集合論の関係は?

SQL は 関係代数(集合論の応用)の実装。 UNION ↔ ∪、 INTERSECT ↔ ∩、 EXCEPT ↔ \、 CROSS JOIN ↔ 直積。 1970 年 E.F. Codd の論文「A Relational Model of Data for Large Shared Data Banks」が起源。

Q6. 「無限集合に大小がある」とはどういうこと?

カントールが示した驚き:自然数 ℕ と整数 ℤ と有理数 ℚ の濃度は同じ (ℵ₀)、 しかし実数 ℝ の濃度はそれより大きい (ℵ₁ 以上)。 「無限にも階層がある」のが集合論の最深部。

🔀 集合と隣接概念の比較

概念重複順序代表的 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 軸で考えると整理しやすい。 集合は両方「なし」の最もシンプルな構造で、 そのため最も操作が高速。

📝 共通テスト「数学 I・A」想定問題

問 1 (包除原理)

あるクラス 40 人のうち、 通学方法を聞いたところ「バスを利用する」生徒が 25 人、 「電車を利用する」生徒が 18 人、 「両方利用する」が 8 人だった。 どちらか少なくとも 1 つ利用する生徒は何人か。

答え: 35 人(包除原理 25 + 18 - 8 = 35)。 どちらも使わない生徒は 40 - 35 = 5 人。

問 2 (部分集合)

$A = \{1, 2, 3\}$ の部分集合は全部で何個あるか。

答え: 8 個($2^3 = 8$。 ∅, {1}, {2}, {3}, {1,2}, {1,3}, {2,3}, {1,2,3})

問 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\}$ も同じ。

📐 練習問題(手で解いて、 Python で確かめる)

  1. SSDSE-B-2026 から「年平均気温が 15℃ 以上」の集合 $C$ と「人口 200 万以上」の集合 $A$ を作り、 |A|, |C|, |A∩C|, |A∪C| を Python で計算せよ。
  2. 包除原理 |A∪C| = |A| + |C| − |A∩C| を上の値で確認せよ。
  3. $A \setminus C$(人口大・気温低)と $C \setminus A$(人口小・気温高)の県を列挙せよ。 どんな県が含まれる?
  4. 「47 都道府県を地方区分 8 つに分ける」分割が 同値関係 として well-defined であることを示せ(反射律・対称律・推移律)。
  5. Python で 47 県の冪集合($2^{47}$ 個)を生成しようとせず、 代わりに「3 県以下の組合せ」だけ列挙する。 何通りか?
  6. ベン図を 4 集合で描く方法を考察せよ(ヒント:楕円が必要)。
  7. Jaccard 係数 $J(A, B) = |A \cap B| / |A \cup B|$ を計算する Python 関数を 1 行で書け。
  8. SQL で 2 テーブル T1, T2 の UNIONINTERSECTEXCEPT を実行する SQL を書け。

🛠️ やってみよう

  1. 身の回りの集合を 5 つ書き出す:「あなたが好きな科目」「あなたが住む県の隣の県」「2024 年に観た映画」など。 集合 → 演算 → 結果を Python の set で実装してみる。
  2. SSDSE で都道府県を 2 つの基準で分け、 ベン図描画:上記コード ② をベースに、 matplotlib_venn でベン図を可視化。 重なりを色付き面積で確認。
  3. Jaccard 係数で「似ている県」を探す:人口・気温・経済指標を集合に変換(例: 全国 top 20 に入っている指標数)し、 県同士の Jaccard 類似度を計算してみる。
  4. SQL でも同じ集合演算:SQLite に SSDSE-B-2026 をロードし、 SELECT Prefecture FROM ssdse WHERE 人口>=100万 UNION SELECT Prefecture FROM ssdse WHERE 高齢化率>=0.30 で同じ結果を得る。
  5. 論理パズル:「赤い帽子 30 人、 青い眼鏡 25 人、 両方 12 人。 どちらも持たない人が 8 人ならクラスは何人?」 → 包除原理 30 + 25 - 12 + 8 = 51 人。

🤔 集合論の哲学的問題

集合論は単なる「便利な道具」ではなく、 数学の基礎付け として 100 年以上議論されてきた。 ここでは 5 つの大問題を見る。

問題 1: 連続体仮説 (Continuum Hypothesis, CH)

「自然数の濃度 (ℵ₀) と実数の濃度 (𝔠) の間に、 別の濃度の集合はあるか?」 カントールは「ない (𝔠 = ℵ₁)」と予想したが、 ゲーデル (1940)・コーエン (1963) により ZFC では真偽決定不能 と証明された。

問題 2: 選択公理は正しいか?

「互いに素な非空集合の族から、 各々から 1 つずつ要素を選ぶ関数が存在する」と認めるとバナッハ・タルスキーのパラドックス(球を有限個に分けて 2 つの同じ球に再構成可能)が導かれる。 反直観的だが、 数学全般の便利さから採用されている。

問題 3: 数学は「発見」か「発明」か

集合論の対象(無限集合・濃度・順序数)は人類が発見した客観的存在なのか、 人類が便宜的に作った概念なのか。 プラトニズム vs 形式主義の永遠の論争。

問題 4: ZFC 以外の選択肢

標準は ZFC だが、 NBG (von Neumann-Bernays-Gödel)、 MK (Morse-Kelley)、 NF (New Foundations)、 ETCS (Elementary Theory of the Category of Sets) など別公理系も存在。 圏論的アプローチ (HoTT) が 21 世紀に台頭。

問題 5: ゲーデルの不完全性定理

「自然数を含む十分に強い無矛盾な公理系には、 真だが証明できない命題が必ず存在する」(1931)。 つまり ZFC ですら完璧ではない。 数学基礎論の根本的限界。

📊 集合論が支える身近なテクノロジー

1. Google 検索:Boolean 検索

「東京 AND ラーメン -行列」の検索は 集合演算そのもの。 「東京を含む文書集合」∩「ラーメンを含む文書集合」∖「行列を含む文書集合」を実行している。 1990 年代以降、 転置インデックスとビットマップで効率化。

2. Amazon の推薦:協調フィルタリング

「あなたが買った商品の集合」と「他のユーザが買った商品の集合」の Jaccard 係数で類似ユーザを発見 → そのユーザが買った別商品を推薦。 1990 年代に GroupLens (ミネソタ大) が原型を確立。

3. Netflix の予測:集合演算 + 行列分解

「視聴済み映画集合」「高評価映画集合」「ジャンル集合」を組み合わせて好みを推測。 Netflix Prize (2009 年) で行列分解と組合せ最適化が花開いた。

4. Spotify の Discover Weekly

毎週 30 曲のおすすめプレイリストを生成。 「ユーザの好み集合」と「他ユーザの好み集合」の重なり、 「ジャンル ∩ ムード」の積集合などで構築。

5. データベース:SQL の JOIN

INNER JOIN は積集合、 LEFT JOIN は左集合とその部分、 CROSS JOIN は直積。 リレーショナル DB は全て集合論で定義されている (Codd, 1970)。

6. 機械学習:データ分割

訓練集合 ∪ 検証集合 ∪ テスト集合 = 全データ、 かつ互いに素 (互いに重ならない)。 これは数学的な分割 (partition) の概念。 k-fold CV も「k 個の互いに素な部分集合への分割」を繰り返し評価。

7. SNS:フォロー関係

「あなたのフォロワー集合 ∩ 相手のフォロワー集合」が「共通の友達」。 LinkedIn の「2 次・3 次のつながり」も集合演算の連鎖。

8. ブロックチェーン:マークル木

トランザクション集合をハッシュ木で表現。 「特定トランザクションがブロックに含まれるか」が集合所属判定問題に帰着。

🔣 集合論の記号一覧(覚えておきたい 20 個)

記号名前読み方意味
所属エレメント・オブ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$ は集合 $A$ のメンバー」と読む。 SSDSE 例:「東京都 ∈ {人口 100 万以上の県}」。 Python: x in A。 これに含まれない場合は $x \notin A$。
$\emptyset$(空集合)
要素を全く持たない集合。 任意の集合の部分集合 として「常に」含まれる特殊な存在。 確率では「決して起こらない事象」を表す。 Python: set()
$U$(全体集合・ユニバース)
議論の範囲となる「すべて」。 SSDSE 例:全 47 都道府県。 補集合は $U$ を前提 にしないと意味が定まらない(高齢化率の補集合は「日本人すべて」「世界の人口すべて」で意味が変わる)。
$A \subseteq B$(部分集合)と $A \subset B$(真部分集合)
$A \subseteq B$ は「$A$ の全要素が $B$ にも入る($A = B$ も含む)」。 $A \subset B$ は「$\subseteq$ かつ $A \ne B$」。 教科書によって ⊂ の定義が違うので注意。
$|A|$(濃度・カーディナリティ)
集合の「大きさ」。 有限集合では単純に要素数。 無限集合では「アレフ 0(可算無限)」「アレフ 1(連続体濃度)」など階層がある。 Python: len(A)
$\mathcal{P}(A)$(冪集合・ベキシュウゴウ)
$A$ のすべての部分集合を集めた集合。 $|\mathcal{P}(A)| = 2^{|A|}$。 例: $A = \{1, 2, 3\}$ なら $\mathcal{P}(A)$ は 8 個の集合 ($\emptyset, \{1\}, \{2\}, \{3\}, \{1,2\}, \{1,3\}, \{2,3\}, \{1,2,3\}$)。
$A \cup B$ と $A \cap B$(和集合と積集合)
覚え方:$\cup$ は「カップ (Union, U の字を逆さに)」、 $\cap$ は「キャップ (intersect の n に似てる)」。 確率では $P(A \cup B)$ は「A または B が起こる確率」、 $P(A \cap B)$ は「両方起こる確率」。
$A \setminus B$ または $A - B$(差集合)
$A$ から $B$ の要素を取り除いたもの。 「$A$ にいて $B$ にいない」要素の集合。 SQL の EXCEPT、 Python の A - B。 引き算と違うのは「もともと B にしかない要素はノーカン」という点。
$A^c$ または $\overline{A}$(補集合)
$U \setminus A$ と等価。 「A でないもの全部」。 必ず全体集合 $U$ が決まっていることが前提。
写像 (mapping) $f: A \to B$
$A$ の各要素を $B$ の要素に対応させる規則。 関数の一般化。 単射 (injection)・全射 (surjection)・全単射 (bijection) の区別が現代代数の基礎。
可算 vs 非可算
自然数 ℕ と 1 対 1 対応できる集合は可算 (countable)。 例: ℤ, ℚ。 実数 ℝ は非可算 (uncountable)(カントールの対角線論法)。 確率測度論で「可算和には対応できるが非可算和には対応しない」のがσ-加法性。
$A \times B$(直積・デカルト積)
「($a$, $b$) のペアすべて」を集めた集合。 $|A \times B| = |A| \cdot |B|$。 SQL の CROSS JOIN、 Python の itertools.product。 関係データベースの基礎概念。
同値関係 (equivalence relation)
反射律 ($a \sim a$)・対称律 ($a \sim b \Rightarrow b \sim a$)・推移律 ($a \sim b \wedge b \sim c \Rightarrow a \sim c$) を満たす関係。 集合を「同値類」に分割する。 機械学習のクラスタリングの理論的基盤。

🔬 数式を言葉で読み解く: 4 つの集合演算 — 和・積・差・補

集合論の核心は 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 県

🐍 Python 実装: SSDSE-B-2026 で 4 つの集合演算を実行

このコードでやること: 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 人口列):

A (太平洋側): 青森・岩手・宮城・福島・茨城・千葉・東京・神奈川・静岡・愛知・三重・和歌山・高知 B (人口 200 万超): 北海道・宮城・茨城・埼玉・千葉・東京・神奈川・静岡・愛知・京都・大阪・兵庫・福岡・広島 (一部)
 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| = 13, |B| = 16, |U| = 47 |A ∪ B| = 22 |A ∩ B| = 7: ['千葉県', '宮城県', '愛知県', '東京都', '神奈川県', '茨城県', '静岡県'] |A \ B| = 6: ['三重県', '和歌山県', '岩手県', '福島県', '青森県', '高知県'] |B \ A| = 9: ['京都府', '兵庫県', '北海道', '埼玉県', '大阪府', '広島県', '新潟県', '福岡県', '長野県'] |A^c| = 34 |A △ B| = 15 (検算: |A|+|B|-2|A∩B| = 15)

💬 包含と排除の原理 \(|A \cup B| = |A| + |B| - |A \cap B|\) を実値で確認: \(13 + 16 - 7 = 22\) ✓。 また対称差の公式 \(|A \triangle B| = |A| + |B| - 2|A \cap B| = 15\) も成立。 「太平洋に面し、 かつ人口 200 万超」の 7 県(首都圏 + 中京 + 仙台)は日本の経済中心軸そのものであり、 集合演算が地理経済の構造を抽出することを実演している。

🔬 集合論を実データで掘り下げる — SSDSE-B-2026 で「都道府県集合」を扱う実践 12 連発

ここまでで集合の基本演算(和・積・差・補・対称差)と Python での扱い方を見てきた。 しかし、 実務で 集合論が本当に効いてくるのは「複数のデータソースを突き合わせるとき」「変な欠損や重複を検出するとき」「ベン図的に世界を分けて確率を計算するとき」の 3 場面である。 本セクションでは SSDSE-B-2026(都道府県・年次データ)と SSDSE-A-2026(市町村データ)を題材に、 集合論が JOIN・データ品質・確率モデルの 3 領域でどう動いているかを具体的に解剖する。

🧭 実務で集合論が顔を出す 3 シーン

シーン 集合論の役割 SSDSE での具体例 使う演算
① データ統合2 つ以上の表のキー集合を突き合わせるSSDSE-B-2026 と SSDSE-E-2026 を「市町村コード」で結合∩ (INNER), ∪ (OUTER), \\ (LEFT EXCL)
② データ品質「あるべき集合」と「実際の集合」の差を取る47 都道府県集合 \\ 実データ集合 = 欠損都道府県\\ (差集合)
③ 確率モデル標本空間 Ω を排反な部分集合に分割都道府県を「人口 100 万以上」「未満」に分割し条件付き確率分割, P(A|B)

📊 図解 1: 都道府県を「人口 100 万」で分けるベン図的視点

集合論の感覚を磨くには、 まず「分割」が大事だ。 SSDSE-B-2026 の 2023 年データで都道府県を A = 「人口 100 万以上」Aᶜ = 「100 万未満」に分けると、 これは Ω = {47 都道府県} の 2 分割になる。 さらに「年間出生数 (A4101) が 1 万人以上」を B とすれば、 A∩B, A∩Bᶜ, Aᶜ∩B, Aᶜ∩Bᶜ の 4 区画(2x2 のクロス表)が現れる。 下の散布図は、 ベン図が 連続変数空間上での分割として実装されている様子を一般的に示す(この図版そのものの変数は下のキャプションを参照)。

総人口と一般診療所数の散布図(47 都道府県、 2023 年度、 r=0.972)
図 1: 総人口 (A1101) と一般診療所数 (I5102) の散布図(47 都道府県、 2023 年度、 相関 r=0.972)。 このように連続変数の平面に縦横の閾値を引くと、 領域が A∩B, A∩Bᶜ, Aᶜ∩B, Aᶜ∩Bᶜ の 4 つの集合に分割される。
📝 補足(共有図について):本ページの 図 1・図 3 は、 姉妹ページ パネル因果同じ図版を共有しています。 図 1 は実際には「総人口 × 一般診療所数(r=0.972)」の散布図、 図 3 は「KMeans で分けた 3 クラスタ別の一般診療所数」の箱ひげ図で、 本文の説明で用いる分割軸(人口×出生数、 8 地方区分)とは変数が異なります。 ここでは「連続変数に閾値を引くと集合分割になる」「排反なグループ分けは partition になる」という構造の一般性を示す図として引用しています。 人口×出生数の 2×2 分割の具体的な件数は、 直後の表・Python コード(SSDSE-B-2026 実測)で確認できます。

この「閾値で分けると集合になる」感覚が、 のちに 決定木のノード分割ロジスティック回帰の境界線クラスタリングなどに直結する。 機械学習はざっくり言えば「Ω を予測したいラベルに合わせてうまく分割する方法を探す問題」であり、 そのバックボーンが集合論である。

📋 表: 2 軸での分割表(SSDSE-B-2026 / 2023 年)

人口 \\ 出生数 B: 1 万人以上 Bᶜ: 1 万人未満 行合計
A: 100 万人以上20 (例: 東京, 大阪, 愛知, ...)17 (例: 青森, 岩手, 山形, ...)37
Aᶜ: 100 万人未満010 (例: 鳥取, 島根, 高知, ...)10
列合計202747

この表から条件付き確率も読める: 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 を 2x2 分割し、 集合的にカウントする

このコードでやること: SSDSE-B-2026 の 2023 年データを読み、 「人口 100 万以上 (A)」「出生数 1 万人以上 (B)」の 2 つの集合を pandas の boolean Index で表現し、 4 つの分割集合の要素数を数える。

📥 入力データ (SSDSE-B-2026 抜粋):

SSDSE-B-2026 Prefecture 総人口(A1101) 出生数(A4101) R01000 北海道 5092000 24430 R13000 東京都 14086000 86348 R27000 大阪府 8763000 55292 R47000 沖縄県 1468000 12549 ...
 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| = 37 |B| = 20 |A ∩ B| = 20 |A ∪ B| = 37 |A \ B| = 17 |A △ B| = 17

💬 |A ∪ B| = |A| = 37 ということは B ⊆ A、 つまり「出生数 1 万人以上の県は、 すべて人口 100 万以上の県でもある」。 これは 包含写像そのものであり、 集合論の言葉でデータの構造的事実が言える。 包含が確認できたら、 次は「なぜ B は A に含まれるのか?」という因果や人口動態の説明に進める。

📊 図解 2: 人口分布のヒストグラムから「閾値で集合を作る」

都道府県人口のヒストグラム
図 2: 都道府県人口のヒストグラム。 「100 万」「500 万」など閾値を引くごとに集合 A, A₂, A₃ ... が作られる。

ヒストグラムは 連続データを集合に変換する装置である。 階級(bin)の境界を引いた瞬間に、 各階級は「値が範囲内に入る都道府県の集合」になる。 47 都道府県を 5 つの bin に分ければ、 互いに排反で和集合が Ω となる 分割 (partition)ができる。 この性質を σ-加法族と呼び、 確率測度を定義する数学的な土台になる。

📋 表: 人口階級による分割と確率

人口階級 (千人) 該当都道府県数 確率 P (= 件数/47) 代表的な県
[0, 1000)100.213鳥取, 島根, 高知, 福井
[1000, 2000)210.447沖縄, 青森, 岩手
[2000, 5000)70.149広島, 京都, 茨城
[5000, 10000)80.170北海道, 大阪, 神奈川
[10000, ∞)10.021東京
合計471.000— (Ω = 全 47 都道府県)

合計確率が 1.0 になるのは、 5 つの階級が「互いに排反 (disjoint) かつ和が Ω」を満たすからである。 これが 確率分布の定義そのものであり、 集合論の分割概念がそのまま確率の 規格化条件に対応している。

🐍 コード: 階級分割を pandas.cut で集合化する

このコードでやること: pandas.cut で人口を 5 階級に切り、 各階級を「都道府県の集合」として取り出す。 さらに各集合のサイズが Ω (47) の分割になっていることを assert で検証する。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) 北海道 5,092,000 東京都 14,086,000 沖縄県 1,468,000 …(全 47 行)
 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 都道府県, 互いに排反)')

📤 実行例:

~1M: 10 件 1-2M: 21 件 2-5M: 7 件 5-10M: 8 件 10M~: 1 件 分割 OK (合計 47 都道府県, 互いに排反)

💬 5 つの集合の和が Ω と一致し、 互いに排反であることが確認できた。 これで「人口階級が ~1M となる確率は 17/47」と確率を語れる。 pandas.cut は集合論的に言えば「分割を定める写像」であり、 ビニング・離散化はすべて集合論の言葉で記述できる。

📊 図解 3: 複数集合の重なりを箱ひげ図で見る

KMeans クラスタ別の一般診療所数の箱ひげ図(47 都道府県、 2023 年度)
図 3: KMeans で分けた 3 クラスタ別の一般診療所数 (I5102) の分布を箱ひげで比較(47 都道府県、 2023 年度)。 各クラスタは都道府県の排反な集合であり、 それらの和は Ω = 47 都道府県(=partition)。 図 1 と同じくパネル因果との共有図です。

箱ひげ図で複数グループを横並びに表示するとき、 我々は暗黙のうちに「グループ = 集合の分割」を前提にしている。 たとえば「北海道・東北・関東・中部・近畿・中国・四国・九州」の 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 で欠損都道府県を検出する

このコードでやること: SSDSE-B-2026 の特定年度に欠損があったら検出する。 期待集合 E は「47 都道府県」、 実集合 R は「実データに出現した都道府県」とし、 集合差で欠損を一発で取り出す。

📥 入力例(SSDSE-B-2026 全体:564 行 × 112 列 = 47 都道府県 × 2012〜2023 年) 年度 地域コード 都道府県 A1101(総人口) A1303(65歳以上人口) A4101(出生数) … 2023 R01000 北海道 5,092,000 1,681,000 24,430 … 2023 R13000 東京都 14,086,000 3,205,000 86,348 … 2023 R47000 沖縄県 1,468,000 350,000 12,549 … …(残り 112 列は住宅・家計・教育・医療など)
 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}')

📤 実行例:

2021: 欠損 0 件 / 想定外 0 件 / Jaccard 1.000 2022: 欠損 0 件 / 想定外 0 件 / Jaccard 1.000 2023: 欠損 0 件 / 想定外 0 件 / Jaccard 1.000

💬 Jaccard が 3 年連続 1.000 なので、 SSDSE-B-2026 は 47 都道府県完全カバーが維持されている。 もし途中の年度で 0.957 (= 45/47) と出たら 2 県欠損を疑い、 欠損 set の中身を print(EXPECTED - R) で確認する流れになる。 これが 集合論ベースの欠損モニタリングの定型パターンである。

🔗 JOIN を集合論で読み替える

SQL や pandas.merge の JOIN は、 そのまま集合論の演算に翻訳できる。 これを把握しておくと「LEFT OUTER JOIN したら行数が増えた」「INNER JOIN したらキーが消えた」といった現象の原因が、 すべて 集合の重なり方として説明できるようになる。

JOIN タイプ 残るキーの集合 集合論の式 用途
INNERA ∩ BA ∩ B両方にあるキーだけ残す
LEFTA(A ∩ B) ∪ (A \ B)左を主、 右の欠損は NaN
RIGHTB(A ∩ B) ∪ (B \\ A)右を主、 左の欠損は NaN
FULL OUTERA ∪ BA ∪ B両方を保持、 欠損は NaN
LEFT ANTIA \ BA \ B左にしかないキー (差分検出)
SYMMETRIC ANTIA △ BA △ Bどちらか片方だけにあるキー

🐍 コード: pandas.merge と集合演算の対応

このコードでやること: SSDSE-B-2026 の異なる 2 年度のデータをキーで結合し、 INNER と OUTER の結果行数が集合演算 (A ∩ B, A ∪ B) と一致することを確かめる。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) 北海道 5,092,000 東京都 14,086,000 沖縄県 1,468,000 …(全 47 行)
 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))

📤 実行例:

|A ∩ B| = 47 / INNER rows = 47 |A ∪ B| = 47 / OUTER rows = 47

💬 SSDSE-B は 47 都道府県完全カバーなので A = B となり、 INNER と OUTER が同じ 47 行になる。 一方、 たとえば SSDSE-A (市町村) と SSDSE-B (都道府県) を結合する場合は A ⊋ B (市町村集合の方が大きい) となり、 INNER と OUTER の行数が大きく違ってくる。

⚠️ 集合論を実務で使うときの落とし穴 6 連

落とし穴 起きる現象 対処
① 表記ゆれ「東京都」と「東京」を別要素扱い正規化辞書を用意し、 set 化前に統一
② 全角・半角混在「A」「A」が別キーunicodedata.normalize('NFKC', s)
③ 空白「 東京都 」と「東京都」が別要素.strip() を必ず通す
④ NaNset に nan が混入し常に「無い」と判定dropna() してから set 化
⑤ 集合 vs マルチセット重複が消えてカウントを失う必要なら collections.Counter を使う
⑥ 順序を保持したいset は順序を持たない順序付き集合は dict.fromkeys(seq)pandas.Index.unique

📐 Jaccard 類似度 — 集合論的「似ている度」

集合論の応用として、 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)37380.97411 年でほぼ同じ顔ぶれ
A=人口200万県, B=出生数1.2万県14170.824概ね一致するが完全ではない
A=東日本, B=西日本0470.000完全に排反

🌌 さらに先へ — 集合論の研究領域

ここまでで 有限集合の運用感は身についた。 集合論はこのあと、 無限集合の濃度 (アレフ数)、 順序数、 公理系 (ZFC) の独立性、 大きな基数、 強制法 (forcing) などへと延びていく。 現代の 機械学習における関数空間 (確率測度空間 L²) や 分散システムの一貫性証明 (CRDT は半束構造、 部分順序集合) なども、 突き詰めれば集合論の上に立っている。

分野 集合論の使われ方 代表概念
確率論標本空間 Ω と σ-加法族で事象を定義σ-algebra, 測度
機械学習仮説集合 H から best h を選ぶVC 次元, PAC 学習
データベース関係 (relation) = タプルの集合関係代数, JOIN/UNION
分散システム半束 (join-semilattice) で一貫性CRDT, 部分順序集合
形式手法状態空間 = 集合、 遷移 = 関係TLA+, Alloy

🧷 本セクションの take-away

🧭 R610 補強: 集合演算の「3 大誤読」を SSDSE-B-2026 で潰す

集合論を授業で初めて触ったとき、 多くの学習者が次の 3 つの誤読をする: ①「和集合 ∪ は単なる加算だ」 ②「補集合は 残り全部 ではなく 母集団との差 である」 ③「対称差 △ は ∪ − ∩ ではなく ∪ ∖ ∩ である」。 ここでは SSDSE-B-2026(都道府県 = 47 件) を母集団 U として、 この 3 つを実値で潰す。

誤読 1: 「和集合 ∪ は単なる加算」ではない

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 倍」と過大計上する事故が起きる。

誤読 2: 補集合 Ac は「全部」ではなく「U との差」

A = 「人口 100 万超」34 件のとき、 補集合は Ac = U ∖ A = 47 − 34 = 13 県。 ここで「補集合 = 全部」と読むと 47 件全部が Ac になってしまい、 pandas の ~mask が常に全行を選ぶ謎挙動を生む。 補集合は 常に U(母集団)に依存する相対概念 である。

誤読 3: 対称差 △ の正しい定義

対称差は A △ B = (A ∪ B) ∖ (A ∩ B) であり、 差の集合(要素) である。 |A △ B| = |A| + |B| − 2|A ∩ B| = 34 + 35 − 2·28 = 13。 これは A だけ ∪ B だけに属する県数、 すなわち「片方の条件でしか引っかからない県」が 13 県あるという意味になる。 「∪ − ∩」のような算術差ではなく、 集合演算の差であることを忘れない。

📋 誤読 vs 正解 早見表

誤読正しい定義SSDSE での値
∪ = 加算|A ∪ B| = |A| + |B| − |A ∩ B|41 県
補集合 = 全部Ac = U ∖ A13 県
△ = ∪ − ∩A △ B = (A∪B) ∖ (A∩B)13 県
∅ = 0 ではない∅ = 要素を持たない集合|∅| = 0
∈ と ⊂ は同じ∈: 要素、 ⊂: 部分集合{東京} ⊂ A, 東京 ∈ A

🧪 R610 補強: 「JOIN は集合演算」を実データで体感する

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 になる。 この「自明な一致」を一旦確認しておくと、 欠損があった時の異常検知が容易になる。

📋 JOIN ↔ 集合演算 対応表

SQL JOIN集合演算pandas merge how結果サイズ (SSDSE)
INNER JOINA ∩ Bhow='inner'47
LEFT JOINAhow='left'47
RIGHT JOINBhow='right'47
FULL OUTER JOINA ∪ Bhow='outer'47
ANTI JOIN (A only)A ∖ Bhow='left' + indicator0
SYMMETRIC DIFFERENCEA △ Bouter + indicator != both0

実務で欠損 (例: B のみ 46 県しかない) のとき、 INNER は 46、 LEFT は 47、 RIGHT は 46、 OUTER は 47、 A ∖ B は 1(欠けた 1 県のコード)、 A △ B も 1 になる。 SSDSE のような 網羅型 パネルデータでは、 ANTI JOIN が空集合 ∅ であることを データ品質の合格基準 として使える。

🧮 実データで計算してみる(SSDSE-B-2026)

ケース 1:人口と高齢化率の 2 集合(包除原理の検算)

SSDSE-B-2026 の 2023 年データから、 以下の 2 集合を定義します。

  • 集合 A=総人口 (A1101) が 100 万以上の都道府県
  • 集合 B=高齢化率 (A1303 / A1101) が 30% 以上の都道府県
  • 全体集合 $U$ = 47 都道府県
集合|集合|代表的な所属県
$|A|$37人口 100 万以上の県(鳥取・島根・高知・福井 など 10 県を除く 37 県)
$|B|$35高齢化率 30% 以上の県(東京・神奈川・愛知・大阪・滋賀・沖縄 など 12 県を除く 35 県)
$|A \cap B|$25人口 100 万以上 かつ 高齢化率 30% 以上の県(北海道・新潟・長野・茨城・福島・広島・岡山・熊本 など)
$|A \cup B|$4747 都道府県すべて(補集合は空)
$|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 県と一致)

解釈:「人口が少なくて、 かつ若い県」は実は存在しない。 これは日本の人口動態の縮図 — 大都市は若くて人口集中、 地方は人口少なくて高齢化、 中間がない。

ケース 2:3 集合の包除原理(A, B, C)

もう 1 つ集合を加えて 3 集合の包除原理を試します。

  • A = 人口 100 万以上の県(|A| = 37)
  • B = 高齢化率 30% 以上の県(|B| = 35)
  • C = 年平均気温 (B4101) が 16 ℃ 以上の県(暖かい県)(|C| = 38)

$$|A \cup B \cup C| = |A| + |B| + |C| - |A \cap B| - |A \cap C| - |B \cap C| + |A \cap B \cap C|$$

各項は Python セクションで計算しますが、 最終的に「日本のどの県もこの 3 条件のいずれかは満たす」ことが分かります。

ケース 3:冪集合のサイズ爆発

$|A| = n$ なら $|\mathcal{P}(A)| = 2^n$。 SSDSE 47 都道府県の冪集合は $2^{47} = 140{,}737{,}488{,}355{,}328$ 個(約 141 兆)。 仮に 1 ms で 1 つの部分集合を吟味しても、 全部見終わるのに 4,470 年かかる。 これが 「ナイーブな全探索アルゴリズムが破綻する」 集合論的理由。

ケース 4:日常的な例 — クラスの教科の好き嫌い

あるクラス 40 人の調査結果:

  • 英語が好き |A| = 22 人
  • 数学が好き |B| = 18 人
  • 両方好き |A ∩ B| = 10 人
  • 少なくとも 1 教科が好き = |A ∪ B| = 22 + 18 − 10 = 30 人
  • どちらも好きじゃない = 40 − 30 = 10 人

ケース 5:ド・モルガンの法則を実例で

$A = $ 人口 100 万以上、 $B = $ 高齢化率 30% 以上 として、 $(A \cap B)^c$ を計算。

  • $A \cap B$ = 25 県(人口 100 万以上 かつ 高齢化率 30% 以上)
  • $(A \cap B)^c$ = 47 − 25 = 22 県(人口 100 万未満 または 高齢化率 30% 未満)
  • 右辺 $A^c \cup B^c$ = (人口 100 万未満) ∪ (高齢化率 30% 未満) = $|A^c| + |B^c| - |A^c \cap B^c|$ = 10 + 12 − 0 = 22 県

→ ド・モルガンの法則 $(A \cap B)^c = A^c \cup B^c$ が成立。

🧮 数式に値を入れて手で計算する: 集合演算

合成 2 集合で和・積・差・対称差を計算する。

Step 1: 集合

A = {1,2,3,4}, B = {3,4,5,6}

Step 2: 演算

A∪B = {1,2,3,4,5,6} (|6|) A∩B = {3,4} (|2|) A-B = {1,2} A△B = {1,2,5,6}

🐍 Python で再現

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}")

📤 実行結果

A∪B: {1, 2, 3, 4, 5, 6} A∩B: {3, 4} A-B: {1, 2} A△B: {1, 2, 5, 6}

💬 手計算 (Step 2) と Python 出力が完全一致。

🐍 Python 実装

Python set 型と pandas で SSDSE-B-2026 の 47 都道府県を集合演算します。

① Python set 型の基本演算

🎯 このコードでやること:Python の組み込み set 型で、 和・積・差・対称差・部分集合判定を行う最小例。

📥 入力データ: 2 つの簡単な集合 A = {1,2,3,4,5}, B = {4,5,6,7,8}

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))

📤 実行すると次の出力が得られる:

A∪B = {1, 2, 3, 4, 5, 6, 7, 8} A∩B = {4, 5} A\B = {1, 2, 3} A△B = {1, 2, 3, 6, 7, 8} A⊆A∪B = True |A| = 5 |A∩B| = 2 包除 = 8

💬 結果の読み方:Python では | & - ^ が和・積・差・対称差。 包除原理 |A|+|B|-|A∩B| = 5+5-2 = 8 が |A∪B| = 8 と一致。 これが集合演算の最基礎。

② SSDSE-B-2026 で 47 都道府県を 2 集合に分け、 包除原理を検算

🎯 このコードでやること:SSDSE-B-2026 から「人口 100 万以上」と「高齢化率 30% 以上」の 2 集合を作り、 |A|・|B|・|A∩B|・|A∪B| を計算し包除原理を検算する。

📥 入力データ: SSDSE-B-2026.csv の 2023 年 47 行。 関係列は A1101(総人口)・A1303(65 歳以上人口)。

Prefecture 総人口(A1101) 65歳以上(A1303) 高齢化率 北海道 5,092,000 1,681,000 0.330 青森県 1,199,000 424,000 0.354 ... 東京都 14,086,000 3,179,000 0.226 沖縄県 1,467,000 342,000 0.233
 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))

📤 実行すると次の出力が得られる:

|A| (人口100万以上) = 37 |B| (高齢化率30%以上) = 35 |A∩B| = 25 |A∪B| = 47 包除原理 |A|+|B|-|A∩B| = 47 A∩B のメンバー (一部): ['三重県', '北海道', '大分県', '奈良県', '宮崎県', '富山県', '山口県', '山形県'] A のみ (人口大・若い): ['京都府', '兵庫県', '千葉県', '埼玉県', '大阪府', '宮城県', '愛知県', '東京都', '沖縄県', '滋賀県', '神奈川県', '福岡県']

💬 結果の読み方:包除原理 37 + 35 − 25 = 47 が |A∪B| = 47 と一致 ✓。 「A のみ(人口大かつ若い)」12 県には東京・神奈川・愛知・大阪 など大都市と 沖縄 が含まれる。 全 47 県のうち「人口少なくかつ若い」県は存在しない — 日本の人口動態の縮図。

③ pandas で集合演算(isin・~・|・&) + SQL の UNION/INTERSECT 相当

🎯 このコードでやること:pandas の isin・ブールマスク(~|&)で SSDSE の都道府県を絞り込む。 SQL の UNION/INTERSECT/EXCEPT に相当。

📥 入力データ: 上で読んだ df(2023 年 47 行)。

df.shape = (47, 112) df.columns[:5] = ['SSDSE-B-2026', 'Code', 'Prefecture', 'A1101', 'A110101']
 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)')

📤 実行すると次の出力が得られる:

|A| 関東 = 7 県、 総人口計 = 43,527,000 人 |B| 関西 = 6 府県、 総人口計 = 20,263,000 人 |A∪B| = 13 県、 総人口計 = 63,790,000 人 |(A∪B)ᶜ| = 34 県 (47-13=34)

💬 結果の読み方:関東 + 関西 = 13 県で日本の総人口 1.24 億のうち 6,379 万人 (51%)。 残り 34 県に 6,056 万人。 「2 つの地域だけで全国半分の人口」という日本の都市集中が、 集合演算 1 行で可視化できる。 SQL なら WHERE pref IN (...) と同義。

④ 3 集合の包除原理を Python で検算

🎯 このコードでやること:3 集合 A=人口100万以上、 B=高齢化率30%以上、 C=年平均気温16℃以上 の包除原理を全項目検算する。

📥 入力データ: SSDSE-B-2026 の A1101 / A1303 / B4101 列。

A = {人口 ≥ 100 万}, B = {高齢化率 ≥ 30%}, C = {気温 ≥ 16℃}
 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}')

📤 実行すると次の出力が得られる(実行例):

|A|=37, |B|=35, |C|=38, |A∩B∩C|=18, |A∪B∪C|(LHS)=47, RHS=47

💬 結果の読み方:左辺 = 右辺 = 47 で包除原理が成立 ✓。 「3 条件のいずれかを満たす県」が全 47 県、 「3 条件すべて満たす県」は 18 県(茨城・岡山・広島・熊本 など中規模・暖かい・高齢化進行)。

⑤ 冪集合のサイズと組合せ爆発

🎯 このコードでやること:47 都道府県の冪集合のサイズ ($2^{47}$) を計算し、 「全部探索したら何年かかるか」を見積もる。

📥 入力データ: SSDSE-B-2026 の都道府県名(47 件)。

|U| = 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 秒で全探索)')

📤 実行すると次の出力が得られる:

|U| = 47 都道府県 |P(U)| = 2^47 = 140,737,488,355,328 1 ms/集合で全探索 → 4,462.8 年 参考: |U|=10 なら |P(U)|=1,024 = 1,024 個 (1 秒で全探索)

💬 結果の読み方:47 県の全部分集合を見るだけで 4,463 年。 これが「組合せ最適化問題は NP 困難」「特徴量選択にナイーブな全探索を使えない」根本理由。 集合論を知っていれば、 アルゴリズムの計算量が分かる。

🐍 R610 補強: 集合演算を「3 種類の API」で書き分ける

このコードでやること: SSDSE-B-2026 の県コード集合に対して、 Python 標準 set / pandas Index / pandas merge(indicator=True) の 3 種類の API で同じ「対称差」を求め、 結果が一致することを確認する。 「同じ集合演算が 3 つの書き方で書ける」と理解すれば、 実務でデータ規模・型に応じた最適 API を選べる。

📥 入力データ (SSDSE-B-2026 抜粋):

SSDSE-B-2026 Code, Prefecture, A1101, ... R01000, 北海道, 5092000, ... R02000, 青森県, 1184000, ... R13000, 東京都, 14086000, ... ... (47 行)
 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)

📤 実行すると次の出力が得られる:

set : 0 Index : 0 merge : 0 全て一致 : True

💬 3 つの API すべてで対称差が空集合 ∅(要素数 0)となり、 SSDSE-B-2026 の 2018 年と 2023 年で県コードに欠損が無いことを示す。 同じ集合演算を 3 通りで書き、 結果を == で比較する パターンは、 集合演算の正しさを確認するゴールドスタンダードとして覚えておくと良い。 規模が大きい (10⁶ 行超) 場合は set、 列単位の演算は Index、 結合と同時に必要な場合は merge が定石。

⚠️ R610 落とし穴: 集合演算で見逃しがちな 5 件

🔎 補足: 集合演算が統計・機械学習で効く局面

集合の基本演算 (∪, ∩, 差集合, 補集合) は素朴に見えるが、 実は統計・機械学習の現場で「データの結合・フィルタリング・評価指標」のすべてに浸透している。 ここでは SSDSE-B-2026 都道府県データと典型タスクに即して、 集合演算が効く具体的場面を整理する。

1. データ結合: 内部結合 vs 左結合の正体は ∩ と ∪

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 は欠損で残る。 集合演算で意識すると「なぜ行数が変わるか」を直感把握できる。

2. 機械学習の評価指標: precision / recall / F1 は集合の比

分類モデルの予測陽性集合を P、 真陽性集合を T とすると、 precision = |P ∩ T| / |P|、 recall = |P ∩ T| / |T|。 つまり共通部分の比率を異なる分母で割ったものに過ぎない。 SSDSE-B-2026 で「人口減少県」を 2 値分類するモデルを作ると、 「予測減少県」P と「実減少県」T の比較で性能が決まる。 集合のサイズ比として読めば、 「閾値を変えると P が動き、 P ∩ T と |P| の比が変わって precision が上下する」という挙動が腑に落ちる。

3. de Morgan の法則とサンプリングフィルタ

(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)] のほうが意図が読みやすい。

4. cross-validation の分割と互いに素な分割

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 など、 グループ単位で互いに素を担保する手法はすべて集合論の「分割」概念に対応する。

5. アンサンブル学習と多数決の集合的読解

3 個の分類器 C_1, C_2, C_3 の多数決は、 「少なくとも 2 個が陽性と判定した集合」= (C_1 ∩ C_2) ∪ (C_2 ∩ C_3) ∪ (C_1 ∩ C_3) として書ける。 各分類器の予測陽性集合の組み合わせで定義されるので、 アンサンブルの効果は集合の重なり具合で説明される。 SSDSE で人口減少予測モデルを 3 種類組み合わせる際、 共通領域が大きいほど多数決はその領域に強く依存する。

6. 自然言語処理: Jaccard 類似度

文書 A と文書 B の単語集合を W_A, W_B とすると、 Jaccard 類似度 = |W_A ∩ W_B| / |W_A ∪ W_B|。 0 (重なりなし) から 1 (完全一致) の値域を持ち、 集合の重なり率そのもの。 SSDSE-B には文書はないが、 たとえば「都道府県の主要産業集合」を都道府県ごとに作って、 都道府県間の Jaccard 類似度を計算すれば、 産業構成が似た県のクラスタリングが可能。

7. ベン図と推論の罠

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 条件のいずれかに該当する県の正確な数を出すには、 必ず包除原理を適用する。

8. 実装チェックリスト

9. まとめ

集合演算は記法こそ簡素だが、 結合・評価・分割・推論・類似度計算という統計実務の主要要素にすべて顔を出す。 ベン図的なイメージを身に付けておくと、 SQL・pandas・scikit-learn のドキュメントを読むときの「なぜこの結果になるのか」が腑に落ちやすくなる。

10. 補論: 集合の濃度 (cardinality) とデータ規模の見積もり

集合 S の要素数を |S| と書き、 これを濃度と呼ぶ。 SSDSE-B-2026 の都道府県集合 P について |P| = 47、 全国の市区町村集合 M については |M| ≒ 1,741 と覚えておくと、 集計テーブルの行数の妥当性チェックに即使える。 たとえば「都道府県 × 産業 20 分類」のクロス集計を作るとき、 期待行数は |P| × 20 = 940 行。 実際に出てきた DataFrame の行数がこれよりはるかに大きければ重複が、 小さければ欠損があると即座に判別できる。 濃度を意識する習慣は、 データ品質チェックの最も基本的かつ強力な手段の 1 つである。

11. 補論: 部分集合の数と特徴量選択

n 個の要素を持つ集合 S の部分集合は全部で 2^n 個ある (空集合と S 自身を含む)。 特徴量選択で「k 個の特徴のうち、 どの組合せがベストか」を全数探索する場合、 候補数は 2^k に膨らむ。 SSDSE-B-2026 の指標が約 100 種類あるとして、 そこから人口予測モデルに使う特徴を全数探索すると 2^100 通り (10^30 オーダー) となり、 現実的には不可能。 だからこそ前進選択・後退削除・LASSO といった部分集合探索の効率化手法が必要となる。 集合の濃度爆発が、 特徴量選択の難しさの根本原因である。

12. 補論: 関係 (relation) は直積集合の部分集合

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) は文字通り「関係 = 直積集合の部分集合」を扱う仕組みであり、 集合論の延長線上にある。

13. 補論: 関数も集合 — 関数の集合論的定義

厳密には、 関数 f: A → B も「A × B の特殊な部分集合 (各 a に対し b がただ 1 つ対応する部分集合)」として集合論で定義される。 SSDSE で「都道府県 → 県庁所在地」の対応を関数 f と書くと、 f は P × C の部分集合であり、 各都道府県 a に対して県庁所在地 b がちょうど 1 つ対応する。 機械学習モデル m: X → Y も「入力空間 X と出力空間 Y の直積 X × Y の部分集合」として読める。 学習とはこの部分集合を観測データから推定する作業に他ならない。

14. 補論: 確率空間と集合論

確率論の出発点である確率空間 (Ω, 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) は、 集合の包除原理を確率に直訳したもの。

15. 補論: トポロジーと位相空間の入口

位相空間 (topological space) は「集合 X とその開集合系 τ の組」として定義される。 開集合系は X の部分集合の集まりで、 (1) 空集合と X 自身を含む、 (2) 任意個の和集合で閉じる、 (3) 有限個の共通部分で閉じる、 という 3 条件を満たすもの。 これだけで連続性・収束・連結性などの幾何的概念が定義可能となる。 機械学習では多様体学習 (manifold learning) や位相的データ解析 (TDA: Topological Data Analysis) でこの考え方が利用される。 集合論は単なる「データ集めの道具」ではなく、 現代の幾何・解析・確率論すべての土台である。

16. 補論: 無限集合 — 可算と非可算

集合論の最も驚くべき成果の 1 つは「無限にも大小がある」というカントールの定理。 自然数全体の集合 N は「可算無限」 (要素を 1, 2, 3, ... と一列に並べられる) だが、 実数全体 R は「非可算無限」 (どんな一列も漏れがある)。 機械学習で扱うパラメータ空間は連続値なので非可算無限、 だからこそ最適化問題は離散探索ではなく勾配法に頼る。 「無限の濃度の違い」が、 連続最適化と組合せ最適化の根本的な違いを生んでいる。

17. 補論: 集合論的データ整合性チェックの典型 4 パターン

18. 補論: 集合演算と SQL の対応早見表

SQL の集合演算句は名前のとおり集合論そのもの。 UNION は和集合 (重複削除あり)、 UNION ALL は多重集合の和 (重複保持)、 INTERSECT は共通部分、 EXCEPT (または MINUS) は差集合に対応する。 SSDSE-B のデータを SQL で扱うとき、 「人口減少県 EXCEPT 高齢化県」と書けば、 人口減少しているが高齢化していない県の集合が得られる。 NULL の扱いには注意が必要 (集合演算は NULL を等価と見るが WHERE 句は等価と見ない) で、 ここを間違えると意図しない結果になる。

19. 終わりに: 集合論を「使いこなす」ということ

集合論は数学基礎論の華やかな話題と見られがちだが、 実務での価値は「データ操作の意図を明確に言語化できる」点にある。 「INNER JOIN を取った」「unique を取った」「dropna した」という操作の背後にはすべて集合演算が潜んでおり、 これを意識すると「なぜこの結果になったのか」を 1 段深い層で説明できる。 SSDSE-B-2026 の都道府県データに対して、 集合演算をベン図と言葉と pandas コードの 3 つで同時に扱える力を養うのが、 本ページの究極のゴールである。

🔎 拡張補足: 集合論の SQL/pandas 実装と現代的応用

1. SQL の集合演算: UNION/INTERSECT/EXCEPT

標準 SQL は集合演算を直接サポート。 UNION は和集合 (重複除去)、 UNION ALL は和集合 (重複保持)、 INTERSECT は共通部分、 EXCEPT (MySQL では MINUS) は差集合。 SSDSE-B-2026 で「人口減少県と高齢化県の共通部分」を SQL で表現: SELECT 都道府県 FROM 人口減少県 INTERSECT SELECT 都道府県 FROM 高齢化県。 概念は集合論と完全に一致。 さらに SQL の DISTINCT は集合化操作 (重複削除して一意集合化)、 GROUP BY は同値類による商集合への射影と見ることができる。 SQL を集合論の言語として読み直すと、 クエリ設計の意図が明瞭になり、 結果の正しさを論理的に検証しやすくなる。 特に大規模データウェアハウスで複雑な JOIN を扱う際、 集合論的思考は不可欠な道具となる。

2. pandas の集合演算

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 の挙動が直感的に理解できる。

3. Python set/frozenset の効率

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 は要素にできない点に注意。

4. 機械学習評価指標と集合論

分類モデル評価の 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|) も類似だが分母が異なる。 これら指標は集合論の語彙で統一的に理解でき、 「なぜこの式なのか」が直感化される。

5. クラスタリングと集合の分割

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 つの分割がどれだけ一致するか」を集合論的に測る指標である。

6. アンサンブル学習と集合演算

3 個の分類器の多数決は集合演算: 「少なくとも 2 個が陽性」= (C1 ∩ C2) ∪ (C2 ∩ C3) ∪ (C1 ∩ C3)。 Voting Classifier (sklearn), Bagging, Random Forest など、 すべて集合論的に解釈可能。 「Diversity を高める」とはアンサンブル構成集合の交差を小さくすること。 Bagging のブートストラップサンプリングは元集合からの復元抽出で、 各学習器が見る部分集合の交差が「out-of-bag (OOB) sample」となり評価に使われる。 Stacking は複数学習器の予測集合をメタ学習器の特徴として再利用し、 これも集合論的には「予測空間への射影と再結合」と読める。 「弱学習器の独立性」とは予測集合の対称差が大きいことに他ならない。

7. データクリーニングと集合差

(1) 重複行削除 = 集合の一意化 (df.drop_duplicates())、 (2) 外れ値除外 = 全集合から外れ値集合の差、 (3) 欠損行除去 = 全集合 - 欠損行集合 (df.dropna())、 (4) フィルタリング = 部分集合抽出 (df[df['col'] > threshold])。 すべて集合論の演算として理解可能。 さらに条件付き置換 (df.loc[cond, 'col'] = value) は「部分集合への写像の制限と更新」、 マージによる補完 (df1.merge(df2, how='left')) は「左集合上での右集合からの値の引き戻し」と解釈できる。 データクリーニングの全工程を集合演算として整理すると、 副作用の少ない再現可能なパイプラインが組みやすくなる。 これは MLOps の文脈でも重要視される。

8. ベン図の現代的可視化

matplotlib-venn, plotly-venn で 2-3 集合ベン図を描画可能。 4 集合以上は UpSet plot (PyUpSet, UpSetR) が標準。 SSDSE-B-2026 で「人口減少県」「高齢化県」「第 1 次産業県」の 3 集合ベン図を描けば、 各組み合わせの都道府県数を可視化できる。 ベン図は 3 集合までは円で表現可能だが、 4 集合以上では円では領域の交差を完全に表現できず、 楕円や凸でない曲線を必要とする。 そのため大量の集合の重複構造を見るには UpSet plot がはるかに優れている。 UpSet plot は集合の組み合わせをマトリクスで表現し、 各組み合わせのサイズを棒グラフで示す。 ゲノミクスやテキスト解析など多集合の比較が必要な領域で標準的に使われている。

9. 集合論と計算機科学の接続

(1) データベース理論: リレーショナルモデルは集合論ベース (Codd 1970)、 (2) 計算理論: チューリングマシン・帰納的可算集合、 (3) 形式言語: アルファベットの集合からの再帰的構築、 (4) 型理論: 部分型関係は集合の包含関係、 (5) 群論・環論: 代数構造は集合 + 演算。 集合論はあらゆる計算機科学概念の基盤。 関数型プログラミングの型システム (Haskell の代数的データ型、 Scala の case class、 TypeScript の union/intersection types) はすべて集合論的構成。 union type は和集合、 intersection type は積集合、 product type は直積。 Kotlin の sealed class は有限集合の枚挙的定義。 こうした抽象が日常のコーディングに浸透している。

10. SSDSE-B-2026 を題材にした集合演算演習

(1) A = 人口減少率 5% 以上の県、 B = 高齢化率 35% 以上の県、 C = 第 1 次産業優位県 として、 A ∪ B ∪ C, A ∩ B ∩ C, A - B などを計算。 (2) 各集合のサイズ、 ベン図、 包除原理の検証。 (3) 都道府県のクラスタリング結果を集合として表現し、 ARI で比較。 これら演習で集合論の実装力が身につく。 さらに発展課題として、 (4) 各都道府県の経年変化を「同一県が異なる年で異なる集合に属する」マルチセット問題として扱う、 (5) 集合演算の包除原理を 3 集合以上で実装し公式と計算結果が一致することを確認、 (6) 「人口」「経済」「産業」など複数指標で集合を定義し、 多次元的な集合比較を行うことで、 集合論を実データ分析の武器として身につけられる。

11. 集合論の哲学的・基礎論的論点

Zermelo-Fraenkel 集合論 (ZFC) は現代数学の標準的基礎。 連続体仮説、 選択公理、 Russell のパラドックス (set of all sets that don't contain themselves) などの哲学的問題は、 集合論の限界と魅力を示す。 これらは直接データサイエンスに使わないが、 「集合とは何か」の理解を深める。 Russell のパラドックスは「自分自身を含まない集合の集合」を考えると矛盾が生じるという問題で、 これを解決するため公理的集合論 (ZFC) が整備された。 選択公理は「任意の空でない集合の族から各集合の代表を 1 つずつ選べる」という直感的に正しそうな主張だが、 Banach-Tarski のパラドックスのような反直感的結果も導く。 これらは数学基礎論の魅力的な探求対象である。

12. 締めくくり: 集合論はデータサイエンスの共通言語

集合論は単独で学ぶより、 SQL・pandas・ML・統計・可視化のすべての場面で「集合演算として何が起きているか」を意識的に追うことで真価を発揮する。 SSDSE-B-2026 のような実データで、 都道府県の組み合わせを集合演算で操作する練習が、 抽象的概念と実務スキルを結びつける最良の方法である。 統計学では確率空間が「標本空間 (集合) + 事象の σ-加法族 (集合の集合) + 確率測度」として定義され、 集合論なしには確率論すら定義できない。 機械学習の学習データ・検証データ・テストデータの分割、 交差検証の fold 設計、 サンプリング戦略 — すべて集合演算の応用である。 集合論を「共通言語」として身につければ、 異なる分野・ツール・抽象度をまたいで思考を統合できるようになる。

⚠️ よくある落とし穴 10 件

⚠️ 1. 空集合 ∅ の扱い
∅ ⊆ A は任意の A について真。 ∅ ∩ A = ∅、 ∅ ∪ A = A。 「空集合だから無視していい」と考えると、 数学的帰納法・最小元の議論で誤る。 Python の set() もこの性質を満たす。
⚠️ 2. 可算と非可算の混同
「無限なら無限」と一括に扱うと、 ルベーグ積分・確率測度論で破綻。 有理数 ℚ は可算、 実数 ℝ は非可算(カントールの対角線論法)。 確率測度は可算加法性 $P(\cup A_n) = \sum P(A_n)$ のみ要求し、 非可算和には対応しない。
⚠️ 3. 重複の扱い(set vs multiset)
数学の集合は重複を持たない({1,1,2} = {1,2})。 統計の「サンプル」は重複可なので multiset (collections.Counter) を使う。 Python の set([1,1,2]) も自動的に重複を除去するので注意。
⚠️ 4. 順序の有無
集合 {1,2,3} = {3,2,1}(順序なし)。 順序が大事なら順序対 (a,b) または タプルを使う。 Python の set は順序保証なし、 list は順序あり、 Python 3.7+ の dict は挿入順保持。
⚠️ 5. 写像 (関数) が well-defined か
「1 つの入力に対し 1 つの出力」が写像の条件。 多価関数(√x = ±... など)はそのままでは写像ではない。 機械学習の損失関数も 関数として well-defined でないと最適化が定義できない。
⚠️ 6. ラッセルのパラドックス
「自分自身を要素にしない集合の集合 R = {x : x ∉ x}」を考えると R ∈ R ⇔ R ∉ R の矛盾発生。 これが素朴集合論を破綻させ、 ZFC 公理系誕生のきっかけ。 実務では「ユニバースを明示する」習慣で回避。
⚠️ 7. NULL / NaN の集合演算
SQL の NULL は「等しいかどうか不定」のため、 WHERE x IN (NULL) は常に偽。 pandas の NaN も同様。 集合演算前に dropna()COALESCE で前処理を。
⚠️ 8. 全体集合 U を省略する
補集合 Aᶜ は U に依存する。 「47 都道府県」を U とするか「日本全国民」を U とするかで Aᶜ は別物。 議論の冒頭で U を明示
⚠️ 9. 部分集合 ⊆ と元 ∈ の混同
$1 \in \{1, 2\}$ は真、 $1 \subseteq \{1, 2\}$ は偽(1 は要素であって部分集合ではない)。 $\{1\} \subseteq \{1, 2\}$ は真。 数学初学者の最頻出ミス。
⚠️ 10. 集合と数列の混同
{1, 2, 3, ..., 100} は集合(100 個の要素)、 1, 2, 3, ..., 100 は数列(順序あり)。 「データ列」と「データ集合」を混同して算法を選ぶと、 順序依存処理が消滅する事故が起きる。

🗺 集合論の概念マップ

上位概念下位・派生応用先
公理数学基礎論ZF, ZFC, NBG, MK数学全般の基盤
演算集合演算∪, ∩, \, △, ᶜ, ×, 𝒫SQL, pandas, NumPy
構造集合 + 演算群、 環、 体、 束、 位相空間抽象代数、 トポロジー
関係$A \times B$ の部分集合関数、 同値関係、 順序関係RDBMS、 関数型言語
濃度集合の「大きさ」有限・可算・連続体濃度確率測度、 ルベーグ積分
論理記号論理命題論理、 述語論理、 ブール代数プログラミング論理、 AI 推論
圏論集合論の一般化射、 関手、 自然変換Haskell、 関数型 ML
集合論 命題論理 関係代数 SQL 位相空間論 A/B テスト集合演算 ファジィ集合 確率測度論

🔗 隣接手法への橋渡し

「集合論」は 確率論・統計学・データベース・論理学の共通基盤 として、 上流の数学的厳密性と下流の SQL や Pandas 操作を結ぶ抽象言語である。 ベン図で直感を掴み、 包含関係や演算則を確率や集約処理にそのまま転用できる。

⬆️ 上流: 論理・記号の基礎

⬌ 並列: 他の数学的構造

⬇️ 下流: 応用先

集合論は確率・データベース・ベン図のすべての土台で、 ∈ ⊂ ∪ ∩ の記号を読めるようになるだけで統計・SQL・論理回路が一段深く理解できる。

🌳 手法選択フロー

「集合」をどう扱うかは、 要素の重複と順序の有無で判断する。

  1. 重複を許すか? No (集合) → set/frozenset、 Yes (多重集合) → Counter or list
  2. 順序が意味を持つか? No (集合・順序無関係) → set、 Yes (列) → list/tuple
  3. 演算で頻出するのは? 和 (∪) → A | B、 積 (∩) → A & B、 差 (\) → A - B、 対称差 (Δ) → A ^ B

SSDSE-B-2026 で「人口減少地域」と「高齢化地域」の共通県を抽出する場合は set(pop_decline) & set(aging) で集合演算が直接書ける。

🔍 解説深化:集合は「条件のスナップショット」— 指示関数と時間変化

本文ではベン図・包除原理・ド・モルガンの法則など「ある時点で固定された集合」の演算を扱いました。 ここでは一歩進めて、 データ分析の現場で使う集合がほぼすべて 内包的定義 $\{x \in U \mid P(x)\}$ —「述語 P(条件式)+閾値+時点」で決まるスナップショット— であることに注目します。 述語・閾値・時点のどれか 1 つが動くと、 同じ名前の集合でも中身は別物になります。

💡 直感:指示関数 — 集合と統計をつなぐ 0/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 県中)38352823

境界付近には 兵庫県 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 に合わせると、 この「やや負の関連」の判定を再現できます。

🚀 発展:重なりの測り方と「0/1 をやめる」一般化

🔗 関連ページ