Python 3 で数学を。

Python 3 とライブラリで数学の問題を解いていきます。統計学や機械学習はときどき。

Python (Python 3) で数学をやるにはどうしたらいいか。その22. 集合。"3人揃えばあとはケンカするだけさ!"

このシリーズの過去記事は以下にまとめてある

py3math.hatenablog.com

当記事について

当ブログ筆者も、Python で数学をやるにはどうしたらいいか悩んでいた時期があるから、昔の自分に向けて書いたような記事。

対象とする読者

Python の入門書を一冊か二冊、一通りやった人で、Python の基本的な構文や基本的な用語がだいたいわかっている人。

そして、公式サイトを読む努力をちゃんとする人。

集合をやってみよう

集合は、Python の標準ライブラリに便利なものがいろいろと用意されているが、ここでは NumPy を使用する。

では、早速、対話モードから:

>>> import numpy as np

例題として、U = {x | x は 16 以下の自然数} とし、その部分集合 A, B を、A = {2, 4, 6, 8, 10}, B = {4, 8, 12, 16} とする、をやってみよう (ただし、{} は取り扱いが難しい面があるからここではリストにする)。

まず全体集合 U を用意しよう。

>>> U = list(range(1, 17))
>>> U
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]

部分集合 A を用意しよう。リスト内包表記で書こう。

>>> A = [i for i in U if i < 11 and i % 2 == 0]
>>> A
[2, 4, 6, 8, 10]

上は、簡単に日本語で説明すれば、U のなかに 11 よりも小さく、かつ、2 で割り切れるものがあればリストにしている (換言すれば、U にある 10 以下の 2 の倍数)。

部分集合 B を用意しよう。これもリスト内包表記で書こう。

>>> B = [i for i in U if i % 4 == 0]
>>> B
[4, 8, 12, 16]

上は、これも簡単に日本語で説明すれば、U のなかに 4 で割り切れるものがあればリストにしている (換言すれば、U にある 4 の倍数)。

さて、ここまでで諸々の準備ができたから、まずは AB の共通部分 (または交わり、 A ∩ B) を探してみよう。NumPy の intersect1d() を使用する。

>>> np.intersect1d(A, B)
array([4, 8])
>>> print(np.intersect1d(A, B))
[4 8]

AB の和集合 (または結び、A ∪ B) を探してみよう。NumPy の union1d() を使用する。

>>> np.union1d(A, B)
array([ 2,  4,  6,  8, 10, 12, 16])
>>> print(np.union1d(A, B))
[ 2  4  6  8 10 12 16]

A の補集合は、NumPy の setdiff1d() を使用する。使い方は、引数を setdiff1d(全体集合 U, A) のようにする。

>>> np.setdiff1d(U, A)
array([ 1,  3,  5,  7,  9, 11, 12, 13, 14, 15, 16])
>>> print(np.setdiff1d(U, A))
[ 1  3  5  7  9 11 12 13 14 15 16]

B の補集合も同じように書く。

>>> np.setdiff1d(U, B)
array([ 1,  2,  3,  5,  6,  7,  9, 10, 11, 13, 14, 15])
>>> print(np.setdiff1d(U, B))
[ 1  2  3  5  6  7  9 10 11 13 14 15]

以上が、基本的な使い方だ。

3 数の場合には少し工夫がいる。

まず、標準ライブラリから functoolsreduce() をインポートしよう。

>>> from functools import reduce

新たに、全体集合 U と 部分集合 A, B, C を作成しよう。

>>> U = list(range(1, 601))
>>> A = [i for i in U if i % 2 == 0]
>>> B = [i for i in U if i % 3 == 0]
>>> C = [i for i in U if i % 5 == 0]

ABC の共通部分 (または交わり、 A ∩ B ∩ C) を探す場合、以下のようにする。

>>> reduce(np.intersect1d, [A, B, C])
array([ 30,  60,  90, 120, 150, 180, 210, 240, 270, 300, 330, 360, 390,420, 450, 480, 510, 540, 570, 600])
>>> print(reduce(np.intersect1d, [A, B, C]))
[ 30  60  90 120 150 180 210 240 270 300 330 360 390 420 450 480 510 540 570 600]

reduce(適用する関数, [適用する変数1, 2, 3, ...]) などと書く。これは "畳み込む" などとも表現される。

(つづく)。

参考文献 (数式を参考)

沖田の数学1Aをはじめからていねいに 数と式 集合と論証 2次関数編 (東進ブックス 大学受験 名人の授業)