カテゴリー

Python基礎

【python&表出力】tabulateモジュールで出力を表形式にする

2021年6月12日

こんな人にオススメ

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
スポンサーリンク
スポンサーリンク

運営者のメガネと申します。TwitterInstagramも運営中。

自己紹介はこちらから、お問い合わせはこちらからお願いいたします。

運営者メガネ

tabulateモジュールをインストール

tabulateモジュールは標準ライブラリではなく、さらにanacondaのインストール時点でもインストールされるものでもない。したがって、自ら入手しなければならない。

anaconda経由

入手の方法は簡単で、「anaconda tabulate」と検索すればanacondaのtabulateのサイトがヒットするだろう。そのサイトのインストール項目の一番上のコードとかをコピーして自分のpython環境下でペースト&実行すればいい。

一応、2021年6月12日時点でのanacondatabulateの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種類もあると表示に困る。ちなみにhtmlunsafehtmlは記事上で使用するとしっかりと表になる。
HTML↓

header1header2header3header4
-3-2-10
1234
5678

unsafehtml↓

header1header2header3header4
-3-2-10
1234
5678

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'

latexlatex_raw

書式でlatexlatex_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にする

最後に、元データがpandasDataFrameの時のtabulateの出力について調べる。

tabular_dataheadersdfにした場合はキレイに出力される。

# どちらも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文を試してみる

続きを見る

関連コンテンツ

スポンサーリンク

Amazonのお買い物で損したない人へ

1回のチャージ金額通常会員プライム会員
¥90,000〜2.0%2.5%
¥40,000〜1.5%2.0%
¥20,000〜1.0%1.5%
¥5,000〜0.5%1.0%

Amazonギフト券にチャージすることでお得にお買い物できる。通常のAmazon会員なら最大2.0%、プライム会員なら2.5%還元なのでバカにならない。

ゲットしたポイントは通常のAmazonでのお買い物に使えるからお得だ。一度チャージしてしまえば、好きなタイミングでお買いものできる。

なお、有効期限は10年だから安心だ。いつでも気軽にAmazonでお買い物できる。

Amazonチャージはここから出来るで

もっとお得なAmazon Prime会員はこちらから

30日間無料登録

執筆者も便利に使わせてもらってる

スポンサーリンク

  • この記事を書いた人

メガネ

独学でpythonを学び天文学系の大学院を修了。 ガジェット好きでMac×Android使い。色んなスマホやイヤホンを購入したいけどお金がなさすぎて困窮中。 元々、人見知りで根暗だったけど、人生楽しもうと思って良い方向に狂ったために今も人生めちゃくちゃ楽しい。 pythonとガジェットをメインにブログを書いていますので、興味を持たれましたらちょこちょこ訪問してくだされば幸いです🥰。 自己紹介→変わって楽しいの繰り返し

-Python基礎
-,