Pythonの数値を2進法、8進法、16進法の表記に変換する

以前の記事で、 pythonで、2進法/8進法/16進法で数値を定義する というのを書きました。
今回はその逆に、10進法の数値を2進法、8進法、16進法での表記に変換します。
(なお、結果的にデータ型は文字列になってしまいます。)

これには、組み込み関数として実装されている bin(), oct(), hex()を使います。


num = 23456
print(bin(num))
# 0b101101110100000
print(oct(num))
# 0o55640
print(hex(num))
# 0x5ba0

先頭の0b等の有無の調整や、16進法でアルファベットを大文字/小文字のどちらで表記するかの制御なども行いたい場合、
format関数が使えます。
ずらっと並べると次のような感じ。


print(format(num, "b"))
# 101101110100000
print(format(num, "#b"))
# 0b101101110100000
print(format(num, "o"))
# 55640
print(format(num, "#o"))
# 0o55640
print(format(num, "x"))
# 5ba0
print(format(num, "#x"))
# 0x5ba0
print(format(num, "X"))
# 5BA0
print(format(num, "#X"))
# 0X5BA0

16進法(hex)の場合に、hではなくxを使うところに注意が必要です。

globで手軽にファイル名の一覧を取得する

特定のディレクトリの配下にあるファイルの一覧が欲しい場面というのはよくあります。
サブディレクトリの探索等少々高度なことをする時はもっと違うライブラリを使ったほうがいいのですが、
特定ディレクトリ直下の特定のパターンのファイル名のファイルの一覧を取得する時などは、
glob を使うと便利です。

ドキュメント: glob — Unix 形式のパス名のパターン展開

次の例はカレントディレクトリ直下のテキストファイルをリストアップしたもの。


import glob
glob.glob("./*.txt")
# ['./text1.txt', './text2.txt']

ご覧の通り、ワイルドカードとして*が使えます。また、?も使えます。
パスの指定は相対パス、絶対パスの両方に対応していて、イメージ通りの挙動をしてくれるのでとても手軽です。

scipyで定積分

タイトルの通り、scipyで定積分を計算する方法の紹介です。

とりあえず今回は $\frac{4}{1+x^2}$ を 区間$[0,1]$で積分しみてみましょう。
なお、この答えは$\pi$になります。

scipyで定積分をする時は integrate モジュールに定義されている、quad という関数を使います。
ドキュメント: scipy.integrate.quad


import scipy.integrate as integrate


def f(x):
    return 4/(1+x**2)


print(integrate.quad(f, 0, 1))
# (3.1415926535897936, 3.4878684980086326e-14)

ご覧通り、結果はタプルで戻ってきます。
一つ目の要素が積分の答えであり、確かに円周率ぽい値になっています。
そして、二つ目の要素は、誤差の推定値です。

これはscipyが代数的に積分を計算しているのではなく、
数値計算で結果を返しているため、どうしても誤差が発生するためです。

NetworkXの辺の書式を設定する

前回の記事がNetworkXの頂点の書式についての記事だったので今回は辺の書式です。

ドキュメントは同じ場所です。
ドキュメント: draw_networkx

有向グラフの場合は矢印の形などもう少し項目が多いのですが、
無向グラフの場合は、太さと色とスタイル(単線、破線、ドットなど)が設定項目になります。

このうち、太さ(width) と 色(edge_color) は単一の値だけではなく、
辺の数と同じ長さの配列で指定することができます。

配列で指定した値は、 G.edge で取得できる辺の一覧の順番と対応するように設定されます。
(初めてNetworkXをいじった時はこの辺りをしらず、思った設定ができずにいました。)

細かいですがドキュメントにデフォルトの色は’r’ (赤)と書いてありますが、これはおそらくドキュメントの誤りです。
(何も指定しないと黒になります。)

edge_color (color string, or array of floats (default=’r’))

styleに指定できるのは次の4種類です。(スタイルの指定は辺別ではなく、全体で一つ指定する必要があります。)
solid|dashed|dotted|dashdot

それでは適当なグラフで実行してみましょう。


import networkx as nx
import matplotlib.pyplot as plt

# グラフを生成
G = nx.Graph()
G.add_cycle(range(5))

# 辺の順番を確認
print(G.edges)
# [(0, 1), (0, 4), (1, 2), (2, 3), (3, 4)]

# 可視化
nx.draw_networkx(
    G,
    edge_color=["r", "g", "m", "c", "y"],
    width=[1, 2, 3, 4, 5],
    style= "dashdot",
)
plt.show()

出力がこちら。

0と1を結んでるのが一番細い赤い線で、次に0と4を結んでるが緑の線で、
と G.edges の値と対応して設定が反映されました。

NetworkXの頂点の書式を設定する

NetworkXのグラフを可視化するときに、もっと見た目を変えたいなと思うことは多々あると思います。
そのようなニーズに応えるために頂点と辺のそれぞれにいくつかのオプションが用意されています。
今回はその中から、頂点の書式に関するものをいくつか紹介します。

ドキュメント: draw_networkx

このページの node_xxx の形式で定義されているパラメーターがそれです。
この中から、node_size、node_color、node_shapeを使って、頂点の色や大きさを変えてプロットしてみましょう。
なお、node_shapeはグラフに対して1つですが、node_sizeとnode_colorは頂点ごとに設定を変えることができます。
ついでに font_family も設定して日本語のフォントを表示してみましょう。


# グラフの生成
G = nx.Graph()
for n in "あいうえお":
    G.add_node(n)

# 頂点の順番の確認。(node_size や node_color はこの順番で指定する)
print(G.nodes)
# ['あ', 'い', 'う', 'え', 'お']

nx.draw_networkx(
    G,
    node_shape="s",
    node_size=[100, 200, 300, 400, 500],
    node_color=["r", "g", "m", "c", "y"],
    font_family="IPAexGothic"
)
plt.show()

出力がこちら。

node_size はデフォルトが 300であることに注意しましよう。
node_shape には ‘so^>v<dph8’ のいずれかの文字が指定できます。

matplotlibでTableau風の色を使う

滅多なことでは使う機会がないと思うのですが、matplotlibで使える色名の中に、
Tableauのカラーパレット(Tableau 10)の色を指定するものがあるのを見つけたので紹介します。

参考:matplotlib.colors
こちらのページにひっそりと次の記載があります。

one of the Tableau Colors from the ‘T10’ categorical palette (the default color cycle): {‘tab:blue’, ‘tab:orange’, ‘tab:green’, ‘tab:red’, ‘tab:purple’, ‘tab:brown’, ‘tab:pink’, ‘tab:gray’, ‘tab:olive’, ‘tab:cyan’} (case-insensitive);

定数も用意されているのでそれを確認してみましょう。


import matplotlib.pyplot as plt
import matplotlib.colors as mcolors

mcolors.TABLEAU_COLORS
'''
OrderedDict([('tab:blue', '#1f77b4'),
             ('tab:orange', '#ff7f0e'),
             ('tab:green', '#2ca02c'),
             ('tab:red', '#d62728'),
             ('tab:purple', '#9467bd'),
             ('tab:brown', '#8c564b'),
             ('tab:pink', '#e377c2'),
             ('tab:gray', '#7f7f7f'),
             ('tab:olive', '#bcbd22'),
             ('tab:cyan', '#17becf')])
'''

matplotlibで色を指定する部分に”tab:blue”と入れてやればいつも見慣れたTableauの青が表示されます。
(“tab:olive”は何か違うような気がするのですが僕の環境のせいでしょうか)

せっかくなので、10本の棒グラフを用意して使ってみましょう。


x = range(1, 11)
y = range(10, 0, -1)
fig = plt.figure()
ax = fig.add_subplot(111, title="Tableau Colors")
ax.bar(x, y, color=mcolors.TABLEAU_COLORS)
plt.show()

出力はこちら。

NetworkXのノード位置の指定に用意された関数を使う

前の記事の続きです。
参考:NetworkXのグラフを可視化するときに頂点の座標を指定する
こちらの記事では、頂点を円形に並べるとき、三角関数を使って座標を指定しました。
それは自分の理解のためにやったのですが、実用上はあらかじめ用意さているレイアウト用の関数を使った方が楽です。

ドキュメント:Graph Layout
たとえば、
circular_layout
を使えば、円上にノードを配置できます。

次のコードのように使います。
グラフの構成と可視化結果は前回の記事と同じなので省略します。


pos = nx.circular_layout(G)
nx.draw_networkx(G, pos=pos, node_color="c")
plt.show()

NetworkXのグラフを可視化するときに頂点の座標を指定する

久々のNetworkXの記事です。
今回はグラフを可視化するときに、明示的に頂点の座標を指定する方法を紹介します。

ドキュメントの Docs » Reference » Drawing
のページを見ると、draw_networkxなどの可視化関数がposという引数を受け取ることがわかります。
ここに、{頂点:(x座標, y座標), …} という形式の辞書を渡してあげると、可視化するときにその座標にノードを配置できます。
これを使って頂点を格子点においたり、一直線に並べたりできます。

いい感じに座標の辞書を作ってくれる関数もいくつか用意されているのですが、
今回は自分で直接円周上のてんを定義してやってみます。

まず一つ目の例は座標は指定せずにそのまま可視化したものです。


import matplotlib.pyplot as plt
import networkx as nx
import numpy as np

# 12個の頂点と、ランダムに引いた辺を持つグラフを定義
node_labels = "abcdefghijkl"
G = nx.Graph()
G.add_nodes_from(node_labels)
for i in range(len(G.nodes)):
    for j in range(i+1, len(G.nodes)):
        if np.random.uniform() < 0.3:
            G.add_edge(node_labels[i], node_labels[j])

# 座標を指定せずに描写する
nx.draw_networkx(G, node_color="c")
plt.show()

結果がこちら。頂点はある程度バラバラに配置されていますね。

次にグラフはそのままで座標を指定してみます。


# 各頂点に対して円周上の座標を割り当てる
pos = {
        n: (np.cos(2*i*np.pi/12), np.sin(2*i*np.pi/12))
        for i, n in enumerate(G.nodes)
    }
print(pos)
'''
{'a': (1.0, 0.0),
 'b': (0.8660254037844387, 0.49999999999999994),
 'c': (0.5000000000000001, 0.8660254037844386),
 'd': (6.123233995736766e-17, 1.0),
 'e': (-0.4999999999999998, 0.8660254037844388),
 'f': (-0.8660254037844387, 0.49999999999999994),
 'g': (-1.0, 1.2246467991473532e-16),
 'h': (-0.8660254037844388, -0.4999999999999998),
 'i': (-0.5000000000000004, -0.8660254037844384),
 'j': (-1.8369701987210297e-16, -1.0),
 'k': (0.5, -0.8660254037844386),
 'l': (0.8660254037844384, -0.5000000000000004)}
'''

# 指定した座標を用いてグラフを可視化する
nx.draw_networkx(G, pos=pos, node_color="c")
plt.show()

結果がこちらです。

きちんと円周上に頂点が並びました。

ダイス係数とシンプソン係数

集合の類似度を表す係数には、前回の記事で紹介したジャッカード係数のほか、
ダイス係数(Sørensen–Dice coefficient)と、シンプソン係数(Szymkiewicz–Simpson coefficient)というものがあります。
自分はジャッカード係数を使うことが多いので、あまり利用しないのですがこの二つも有名なもののようなので定義を紹介します。

まず、ダイス係数です。
ジャッカード係数と比較すると、二つの集合の和集合の要素の数の代わりに、二つの集合の要素数の平均を用いています。
$$
DSC(A, B) = \frac{2|A\cap B|}{|A| + |B|}
$$

続いて、シンプソン係数。
こちらは二つの集合の和集合の要素の数の代わりに、二つの集合の要素数のうち小さい方を用います。

$$
SSC(A, B) = \frac{|A\cap B|}{\min(|A|, |B|)}
$$

シンプソン係数は二つの集合のうち一方がもう一方に包含されている時、値が$1$になってしまうのが嫌なので利用を避けることが多いです。
この性質が便利な場面もあるのかもしれませんが、ぱっと思いつくものがない。

ジャッカード係数

二つの集合がどのくらい似ているのか表す指標である、ジャッカード係数(Jaccard index)を紹介します。

Wikipedia: Jaccard index

これは二つの集合$A, B$に対して、その共通部分の元の個数を、和集合の元の個数で割ったものです。
$A, B$のジャッカード係数$J(A, B)$を数式でと次のようになります。

$$
J (A, B) = \frac{|A \cap B|}{|A \cup B|}
$$
単に共通部分の大きさを数えるだけでなく、和集合の元の個数で割ることにより正規化していることがポイントです。
定義から明らかに、 $0\leq J (A, B) \leq 1$ であり、二つの集合に交わりが大きいほど値が大きくなります。
また、二つの集合がどちらも空集合の時は$1$と定義するそうです。(これは知らなかった)
空集合同士で等しいからそれを表現するためと考えると納得です。

よく似た概念に、ジャッカード距離(Jaccard distance)があります。
距離なので、二つの集合が似てるほど値が小さくなって欲しく、差が大きいほど値が大きくなって欲しいので、次のように定義されています。
$$
d_J(A, B) = 1 – J (A, B) = \frac{|A \cup B| – |A \cap B|}{|A \cup B|}
$$

自分はこれを自然言語処理で使うことが多くあります。
テキストを単語の集合としてテキストの類似度を測ったり、
単語を文字の集合として単語の類似を測ったりですね。