~(チルダ)の意味
前回、PythonのPandasで列名が重複している列を取り除く方法を紹介しました。
今回は前回出てきた~(チルダ)が何者なのか、その役割を探るために色々と試してみようと思います。
ちなみに前回出てきたのはこんな感じでした。
import pandas as pd
a = [1, 2, 3, 4, 5]
b = [2, 4, 6, 8, 10]
c = [3, 6, 9, 12, 15]
d = [4, 8, 12, 16, 20]
e = [5, 10, 15, 20, 25]
df1 = pd.DataFrame({"a":a, "b":b, "c":c})
df2 = pd.DataFrame({"a":a, "d":d, "e":e})
df = pd.concat([df1, df2], axis=1)
print(df.columns.duplicated())
print(~df.columns.duplicated())
実行結果
[False False False True False False]
[ True True True False True True]
Bool値(True/False)の出力に対して~(チルダ)をつけると、その値が逆になるというものでした。
ということでなんとなく値が逆になるという意識があるのですが、それが一体どういうものなのか、色々と試していきましょう。
Int型に対しての~(チルダ)
まずは一つ目にInt型に対して「~」を使ってみます。
a = 1
print(~a)
実行結果
-2
なんと「1」に対して「~」を使ったところ「-2」となってしまいました。
bool値のようにTrueがFalseという反対のものになるというのなら「1」の反対は「-1」ではないだろうかと考えます。
もう一つ値を変えて試してみましょう。
a = -10
print(~a)
実行結果
9
「-10」に対して「~」を使うと「9」となりました。
つまり「a」という値に対して「~」を使うと「-(a+1)」となるようです。
でなぜこのようなことになるかというのはこちらの記事が詳しいのでよかったらどうぞ。
エラーとなる例:Str型、Float型、List型、Dict型
ここからはエラーとなる例を紹介します。
まずはStr型やFloat型、List型、Dict型に関してはそのまま「~」を付けるとエラーになります。
a = "a"
print(~a)
実行結果
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[7], line 3
1 a = "a"
----> 3 print(~a)
TypeError: bad operand type for unary ~: 'str'
a = 1.5
print(~a)
実行結果
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[8], line 3
1 a = 1.5
----> 3 print(~a)
TypeError: bad operand type for unary ~: 'float'
a = [1, 2, 3]
print(~a)
実行結果
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[12], line 3
1 a = [1, 2, 3]
----> 3 print(~a)
TypeError: bad operand type for unary ~: 'list'
a = {"x":0, "y":1, "z":2}
print(~a)
実行結果
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[2], line 3
1 a = {"x":0, "y":1, "z":2}
----> 3 print(~a)
TypeError: bad operand type for unary ~: 'dict'
ただしList型とDict型に関してはInt型の要素を指定した場合はInt型の時の処理と同じように「-(a+1)」されます。
a = [1, 2, 3]
print(~a[0])
実行結果
-2
a = {"x":0, "y":1, "z":2}
print(~a["x"])
実行結果
-1
Int型に似ているFloat型で「~」が使えないのはなかなか不思議ですが、とりあえずほとんどの型では使えないようです。
Bool型に対しての~(チルダ)
Bool型に対して「~」を使うとTrueがFalseに、FalseがTrueになるかと思いましたが、実は違ったようです。
a = True
print(~a)
実行結果
-2
Trueの値に「~」をつけたら「-2」という出力が得られました。
Int型で出力されるということは実はTrue、Falseは何らかのInt型の数値が割り当てられているものと考えられます。
ということでInt型に戻してみましょう。
a = True
b = False
print(int(a))
print(int(b))
実行結果
1
0
これで分かる通り元々True、Falseには「1」、「0」というInt型の値が振られているようです。
そのためTrueに「~」を付けると「-2」という結果が得られたわけです。
ついでにFalseに「~」を付けた結果を見てみましょう。
a = False
print(~a)
実行結果
-1
「0」に「~」を付けることで「-(0 + 1)」、つまり「-1」ということでInt型の処理と同じ結果が得られました。
numpyに対しての~(チルダ)
ただbool値に対して「~」を付けて、「-2」や「-1」といった値が得られてもなかなか使い勝手が良くありません。
素直にTrueならFalse、FalseならTrueを返して欲しいものです。
そうするためには実はnumpyを使います。
import numpy as np
a = np.array(True)
print(~a)
実行結果
False
前回Pandasでbool値に「~」を使ったところTrue/Falseの値が逆になりましたが、Pandasはnumpyにパッケージとして依存している部分もあるため、同じ振る舞いをするのだと思います。
ちなみにnumpyのリストの場合は「~」を使うと要素の全てが「-(a+1)」となります。
import numpy as np
a = np.array([1, 2, 3])
print(~a)
実行結果
[-2 -3 -4]
もちろんStr型やFloat型が入っているとエラーとなります。
import numpy as np
a = np.array([1, "a", 3])
print(~a)
実行結果
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[8], line 5
1 import numpy as np
3 a = np.array([1, "a", 3])
----> 5 print(~a)
TypeError: ufunc 'invert' not supported for the input types, and the inputs
could not be safely coerced to any supported types according to the casting
rule ''safe''
import numpy as np
a = np.array([1, 1.5, 3])
print(~a)
実行結果
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[9], line 5
1 import numpy as np
3 a = np.array([1, 1.5, 3])
----> 5 print(~a)
TypeError: ufunc 'invert' not supported for the input types, and the inputs
could not be safely coerced to any supported types according to the casting
rule ''safe''
また便利な利用例としては「isnan」でnanを見つけ出し、「~」でnanでないものを抽出するのに使うのが便利です。
import numpy as np
a = np.array([1, np.nan, 3])
print(np.isnan(a))
print(~np.isnan(a))
実行結果
[False True False]
[ True False True]
ということで今回は「~(チルダ)」を使った際の振る舞いに関して勉強してみました。
次回は一時ファイルを作成する「tempfile」モジュールを紹介します。
ではでは今回はこんな感じで。
コメント