カテゴリー

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

運営者のメガネです。YouTubeTwitterInstagramも運営中。自己紹介お問い合わせページあります。

運営者メガネ

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↓

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'

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文を試してみる

続きを見る

ガジェット

2023/9/18

【デスクツアー2022下半期】モノは少なく、でも効率的に Desk Updating #0

今回はガジェットブロガーなのにデスク環境を構築していない執筆者の ...

ライフハック

2023/9/16

【Audible vs YouTube Premium】耳で聴く音声学習コンテンツを比較

ワイヤレスイヤホンが普及し耳で学習することへのハードルが格段に下 ...

完全ワイヤレスイヤホン(TWS)

2023/9/18

【SENNHEISER MOMENTUM True Wireless 3レビュー】全てが整ったイヤホン

今回は高音質・高機能なSENNHEISERのフラグシップ完全ワイヤレスイヤホン「SENNH ...

ライフハック

2023/3/11

【YouTube Premiumとは】メリットしかないから全員入れ

今回はYouTube Premiumを実際に使ってみてどうなのか、どんなメリット/デメリット ...

マウス

2023/8/17

【Logicool MX ERGOレビュー】疲れない作業効率重視トラックボールマウス

こんな人におすすめ トラックボールマウスの王道Logicool MX ERGOが気になるけどऩ ...

ベストバイ

2023/9/18

【ベストバイ2022】今年買って良かったモノのトップ10

2022年ベストバイ この1年を振り返って執筆者は何を買ったのか。ガジェッ& ...

スマホ

2023/1/15

【楽天モバイル×povo2.0の併用】月1,000円の保険付きデュアルSIM運用

こんな人におすすめ 楽天モバイルとpovo2.0のデュアルSIM運用って実際のとこ ...

マウス

2023/9/16

【Logicool MX ERGO vs MX Master 3】ERGOをメインにした決定的な理由

こんな疑問・お悩みを持っている人におすすめ 執筆者はLogicoolのハイエンӠ ...

macOSアプリケーション

2022/9/30

【Chrome拡張機能】便利で効率的に作業できるおすすめの拡張機能を18個紹介する

こんな人におすすめ Chromeの拡張機能を入れたいけど、調べても同じような ...

macOSアプリケーション

2023/5/3

【Automator活用術】Macで生産性を上げる作業の自動化術

今回はMacに標準でインストールされているアプリ「Automator」を使ってできる ...

Pythonを学びたいけど独学できる時間なんてない人へのすゝめ

執筆者は大学の研究室・大学院にて独学でPythonを習得した。

でも社会人になったら独学で行うには時間も体力もなくて大変だ。

時間がない社会人だからこそプロの教えを乞うのが効率的。

ここでは色んなタイプに合ったプログラミングスクールの紹介をする。

  • この記事を書いた人

メガネ

Webエンジニア駆け出し。独学のPythonで天文学系の大学院を修了。常時金欠のガジェット好きでM2 Pro MacBook Pro(30万円) x Galaxy S22 Ultra(17万円)使いの狂人。自己紹介と半生→変わって楽しいの繰り返しレビュー依頼など→お問い合わせ運営者情報、TwitterX@m_ten_pa、 YouTube@megatenpa、 Threads@megatenpa

-Python基礎
-,