Python3で順序を扱うときのちょっとした話(np.setdiff1d, np.allとnp.any)
1. np.setdiff1d()
とりあえず、以下の配列を使うので変数に入れておきます。ついでにnumpyとitertoolsもimportしておきましょう。
import numpy as np
import itertools
A = [(1, 2), (2, 3),(3, 4), (3, 2), (2, 1)]
B = [(1, 3), (2, 4), (4, 2), (3, 1)]
まず、リストAを昇順に並べた後に、重複してしまった要素を取り除く操作をしてみましょう。次のように書けますね。
C = [tuple(sorted(i)) for i in A]
# C = [(1, 2), (2, 3), (3, 4), (2, 3), (1, 2)]
D = list(set(C))
# D = [(2, 3), (1, 2), (3, 4)]
次に、こうして出来たリストDと重複する要素をAから抜き出した配列Eを抽出することを考えてみます。しかし、
E = np.setdiff1d(A, D)
としてしまうと、Eは空の配列になってしまいます。なぜなら、np.setdiff1d()はリストをフラットにしてユニークな要素のみを見ているからです。つまり、[1, 2, 3, 4]と[1, 2, 3, 4]の重複要素を取り除いて空になるわけです。
これを解決するには、素朴にnp.all()を使って、
E = A[~np.all(A==D, axis=1)]
# E = array([[3, 2],
# [2, 1]])
としましょう。
2. np.all()とnp.any()
さて、itertools.permutations()で1から4までの4個の自然数から2個を取り出して並べる順列を作ってみましょう。
F = [perm for perm in itertools.permutations(range(1,4+1), 2)]
# F = [(1, 2), (1, 3), (1, 4),
# (2, 1), (2, 3), (2, 4),
# (3, 1), (3, 2), (3, 4),
# (4, 1), (4, 2), (4, 3)]
となりますね。このタプルの中身を昇順に並べた後に、重複要素を取り除く操作を行いたいことはよくあると思います。これはさっきと同じように、
G = list(set([tuple(sorted(i)) for i in F]))
# G = [(2, 4), (1, 2), (3, 4), (1, 4), (2, 3), (1, 3)]
とすれば問題なく出来ます。では、リストFから特定の数字から始まる要素のみを抜き出すにはどうすればよいでしょう。つまり、(2, 何か)のような要素を抜き出す操作です。ここで、
H = np.array(F)
I = H[H==[2, True]]
# I = [2 1 2 2 1 1]
としてしまうと、[2 1 2 2 1 1]などという意味不明の配列が返されます。望む出力を得るためには、
J = H[~np.all(H!=[2, False], axis=1)]
# J = array([[2, 1],
# [2, 3],
# [2, 4]])
とします。直観的ではないですね。あれ、結局セットになってるnp.any()は使っていないのでは。
それはそれとして、次回は順列を作る流れでnp.lib.stride_tricks.as_strided()の話とか出来たらなぁと思っています。やらない気もします。