こんな人にオススメ
pythonで2次元データを出力する際にキレイにしたい!
何か良い方法はない?
ということで、今回はかなり地味であるがpythonの出力時に2次元データを表形式にする方法について解説する。手っ取り早いのがtabulate
モジュールを使用するという方法で、グリッドを入れたりLaTeX形式にしたりとできる幅が広くなる。
超簡単に表っぽく出力するならnumpy
のままでもいい。これでもいいのであれば今回の記事はあまり役に立たないかもしれないが、最後まで見ていただけると幸いだ。
# [[-3 -2 -1 0] # [ 1 2 3 4] # [ 5 6 7 8]]
python環境は以下。
- Python 3.9.4
- tabulate 0.8.9
- numpy 1.20.3
- pandas 1.2.4
tabulate
モジュールをインストール
tabulate
モジュールは標準ライブラリではなく、さらにanaconda
のインストール時点でもインストールされるものでもない。したがって、自ら入手しなければならない。
anaconda経由
入手の方法は簡単で、「anaconda tabulate」と検索すればanacondaのtabulate
のサイトがヒットするだろう。そのサイトのインストール項目の一番上のコードとかをコピーして自分のpython環境下でペースト&実行すればいい。
一応、2021年6月12日時点でのanaconda
のtabulate
のInstallersのコード一覧を書いておく。執筆者自身はこれらの違いがわからないのでとりあえず一番上にした(はず)。ご自身の環境に合わせてコードを選択していただければと思う。
conda install -c conda-forge tabulate conda install -c conda-forge/label/gcc7 tabulate conda install -c conda-forge/label/cf201901 tabulate conda install -c conda-forge/label/cf202003 tabulate
pip経由
執筆者はpip
を使用していないので全然わからんが、シンプルに「python tabulate」と検索するとtabulate
のサイトに飛べるので、そこの「Installation」項目の以下のコードから入れられると思う。
pip install tabulate
ただし、WindowsとLinux系では異なるっぽいのでそれぞれで調べていただけると確実だ。
tabulate
で表を作成
本題のtabulate
での表作成。
データの準備
import numpy as np from tabulate import tabulate headers = ['header1', 'header2', 'header3', 'header4'] tabular_data = np.arange(-3, 9).reshape(-1, 4) print(headers) # ['header1', 'header2', 'header3', 'header4'] print(tabular_data) # [[-3 -2 -1 0] # [ 1 2 3 4] # [ 5 6 7 8]] print(type(tabular_data)) # <class 'numpy.ndarray'>
今回使用するデータは3行4列でそれぞれの列にヘッダとしてheader1
, header2
, ...と名称をつけた。配列の型はnumpy.ndarray
。
表形式で出力
tablefmts = [ "plain", "simple", "github", "grid", "fancy_grid", "pipe", "orgtbl", "jira", "presto", "pretty", "psql", "rst", "mediawiki", "moinmoin", "youtrack", "html", "unsafehtml", "latex", "latex_raw", "latex_booktabs", "latex_longtable", "textile", "tsv" ] for fmt in tablefmts: table = tabulate(tabular_data=tabular_data, headers=headers, tablefmt=fmt) print(f"{fmt}\\n{table}\\n\\n")
書式として使用できるのは合計23種類で、それぞれtabulate
の引数tablefmt
で指定。引数tabular_data
が表のデータ部分、headers
がヘッダ部分を表す。実際の出力を以下に示す。
さすがに23種類もあると表示に困る。ちなみにhtml
とunsafehtml
は記事上で使用するとしっかりと表になる。
HTML↓
header1 | header2 | header3 | header4 |
---|---|---|---|
-3 | -2 | -1 | 0 |
1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 |
unsafehtml↓
header1 | header2 | header3 | header4 |
---|---|---|---|
-3 | -2 | -1 | 0 |
1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 |
tabulate
の書式と出力情報
tabulate
のデフォルトの書式と引数の有無による出力の変化を調べる。
tablefmt
のデフォルト値はsimple
# simpleの出力確認 table = tabulate(tabular_data=tabular_data, headers=headers, tablefmt='simple') print(f"simple\\n{table}\\n\\n") # simple # header1 header2 header3 header4 # --------- --------- --------- --------- # -3 -2 -1 0 # 1 2 3 4 # 5 6 7 8 # デフォルトの書式はsimple table = tabulate(tabular_data=tabular_data, headers=headers) print(f"simple\\n{table}\\n\\n") # simple # header1 header2 header3 header4 # --------- --------- --------- --------- # -3 -2 -1 0 # 1 2 3 4 # 5 6 7 8
引数tablefmt
のデフォルト値はsimple
。なので、tablefmt
に何も入れなければsimple
と同じ出力となる。
また、引数headers
を省略するとヘッダが消える。これは当たり前。一方でtabular_data
を省略することはできない。
# ヘッダを無くすとヘッダが表示されなくなる table = tabulate(tabular_data, tablefmt='simple') print(f"simple\\n{table}\\n\\n") # simple # -- -- -- - # -3 -2 -1 0 # 1 2 3 4 # 5 6 7 8 # -- -- -- - # データ部分は省略できない table = tabulate(headers=headers) # table = tabulate(headers=headers) # TypeError: tabulate() missing 1 required positional argument: 'tabular_data'
latex
とlatex_raw
書式でlatex
とlatex_raw
という2種類の$\LaTeX$が存在していた。これらは数式などを挿入することでその違いが明らかになる。
表中に数式を入れる
tabular_data = np.arange(-3, 9).reshape(-1, 4).astype(str) tabular_data[1][1] = '10^2' tabular_data[1][3] = '10^{-2}' tabular_data[2][0] = r'\\int_0^\\infty\\ dx\\ x' print(tabular_data) # [['-3' '-2' '-1' '0'] # ['1' '10^2' '3' '10^{-2}'] # ['\\\\int_0^\\\\infty\\\\ dx\\\\ x' '6' '7' '8']]
とりあえず表中で以下の項目を入れ替えた。最後の式に意味はない。
- $10^2$
- $10^{-2}$
- $\int_0^\infty\ dx\ x$
それぞれ出力して違いを確認
for fmt in ['latex', 'latex_raw']: table = tabulate(tabular_data=tabular_data, headers=headers, tablefmt=fmt) print(f"{fmt}\\n{table}\\n\\n") # latex # \\begin{tabular}{llrl} # \\hline # header1 & header2 & header3 & header4 \\\\ # \\hline # -3 & -2 & -1 & 0 \\\\ # 1 & 10\\^{}2 & 3 & 10\\^{}\\{-2\\} \\\\ # \\textbackslash{}int\\_0\\^{}\\textbackslash{}infty\\textbackslash{} dx\\textbackslash{} x & 6 & 7 & 8 \\\\ # \\hline # \\end{tabular} # latex_raw # \\begin{tabular}{llrl} # \\hline # header1 & header2 & header3 & header4 \\\\ # \\hline # -3 & -2 & -1 & 0 \\\\ # 1 & 10^2 & 3 & 10^{-2} \\\\ # \\int_0^\\infty\\ dx\\ x & 6 & 7 & 8 \\\\ # \\hline # \\end{tabular}
それぞれの違いを見れば一目瞭然だが、latex
ではバックスラッシュ\\
やアンダースコア_
を$\LaTeX$上でも表示するように**\\textbackslash{}
だったり\\_
と表現している。**
一方で、latex_raw
ではそれぞれがしっかりと数式として機能するようにそのままの文章として表示されている。
したがって、latex
は入力した文字そのままで表示したい場合、latex_raw
は入力した文字は数式として表示したい場合に使用できる。
簡単に表にするならpandas
でいいやん
ここまででtabulate
を使用した表の作成を見てきてが、そもそもデータもヘッダもあるならpandas
で良くね?という意見があるだろう。
そう、pandas
で問題ない。ただし、pandas
の場合はキレイに線を追加するのが面倒。シンプルに表っぽく出力するならpandas
で十分。
import pandas as pd headers = ['header1', 'header2', 'header3', 'header4'] tabular_data = np.arange(-3, 9).reshape(-1, 4).astype(str) df = pd.DataFrame(data=tabular_data, columns=headers) print(df) # header1 header2 header3 header4 # 0 -3 -2 -1 0 # 1 1 2 3 4 # 2 5 6 7 8
一応、デフォルトだとインデックスとして行番号が振られているので、index
を無効にする。
print(df.to_string(index=False)) # header1 header2 header3 header4 # -3 -2 -1 0 # 1 2 3 4 # 5 6 7 8
なお、.style.hide_index()
をすれば同様にインデックスと非表示にすることができるようだが、うまくいかなかった。
df = pd.DataFrame(data=tabular_data, columns=headers) df = df.style.hide_index() print(df) # <pandas.io.formats.style.Styler object at 0x11ba38550>
引数をdf
にする
最後に、元データがpandas
のDataFrame
の時のtabulate
の出力について調べる。
tabular_data
もheaders
もdf
にした場合はキレイに出力される。
# どちらもdfにするのはセーフ df = pd.DataFrame(data=tabular_data, columns=headers) table = tabulate(tabular_data=df, headers=df, tablefmt='simple') print(f"simple\\n{table}\\n\\n") # simple # header1 header2 header3 header4 # -- --------- --------- --------- --------- # 0 -3 -2 -1 0 # 1 1 2 3 4 # 2 5 6 7 8
ヘッダを無くすともちろんデータのみの表示となる。
# ヘッダを無くすとデータのみ表示 table = tabulate(tabular_data=df, tablefmt='simple') print(f"simple\\n{table}\\n\\n") # simple # - -- -- -- - # 0 -3 -2 -1 0 # 1 1 2 3 4 # 2 5 6 7 8 # - -- -- -- -
前述のようにtabular_data
を省くのはエラー。
# tabular_dataを省くのはエラー table = tabulate(headers=df, tablefmt='simple') # table = tabulate(headers=df, tablefmt='simple') # TypeError: tabulate() missing 1 required positional argument: 'tabular_data'
出力を整理して情報を整理
執筆者自身、デバッグをうまく使いこなせていない。その代わりにひたすらprintしまくることで出力を確認している。この時にデータが複雑だったり多かったりすると確認するのが面倒。
そんな時には本記事のように出力をキレイな表形式に変換することで情報を整理することができると思う。
また、データを$\LaTeX$やHTMLに出力する際にも本記事のtabulateで予め出力しておくことで楽にコピペすることができる。実際に執筆者も$\LaTeX$に貼り付けるときに使用したことがある。
うまくモジュールや関数を利用してどんどん楽になりましょう。
関連記事
-
-
【辞書の結合】dictのマージ
続きを見る
-
-
【python3.7以降&dictのkeys】ネスト(入れ子)されたdictのkeys一覧をカッコで出力
続きを見る
-
-
【python3&四捨五入】四捨五入すると1.5も2.5も2.0になる問題
続きを見る
-
-
【Python3.10&パターンマッチ】match文を試してみる
続きを見る