カテゴリー

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のマージ

こんな人にオススメlistは+記号で配列の足し算(結合)ができるけど、dictってどうすれ ...

続きを見る

【python3.7以降&dictのkeys】ネスト(入れ子)されたdictのkeys一覧をカッコで出力

こんな人にオススメ dictとやらに手を出してすごい便利だと歓喜しているのですが、ネ ...

続きを見る

【python3&四捨五入】四捨五入すると1.5も2.5も2.0になる問題

こんな人にオススメ python3系で1.5を整数で四捨五入をするともちろん2が計算される。一方 ...

続きを見る

【Python3.10&パターンマッチ】match文を試してみる

こんな人にオススメ 2021年10月4日にpython3.10がリリースされ、新機能としてパターンマッチが ...

続きを見る

スマホ

2023/1/21

【Galaxy S22 Ultraレビュー】これが最高峰

こんな人におすすめ 2022年最強のスマホGalaxy S22 Ultraって実際使った感じどうなの ...

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

2023/1/15

【SENNHEISER MOMENTUM True Wireless 3レビュー】高レベルでバランス型の高音質イヤホン

こんな人におすすめ SENNHEISER MOMENTUM True Wireless 3って実際のところどうなの? 評判は良い ...

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

2023/1/14

【SONY WF-1000XM4 vs SENNHEISER MTW3】MTW3を選んだ決定的な3つの理由

こんな人におすすめ 執筆者は「SONY WF-1000XM4」「SENNHEISER MOMENTUM True Wireless 3」両方を持っている ...

スマホ

2023/1/15

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

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

マウス

2023/1/5

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

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

マウス

2023/1/14

【Logicool MX ERGOカスタム】Logi Optionsのジェスチャーボタン設定内容

こんな人におすすめ Logicool MX ERGOをもっと上手に効率的に使いこなしたい。 ボ| ...

生活に役立つ

2023/1/8

【メガネ厳選】クソ便利に使っているサービスやアイテム達

このページでは執筆者「メガネ」が実際に使って便利だと感じているサ ...

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

2023/1/15

【SONY WF-1000XM4レビュー】神とゴミのハーフ&ハーフ

こんな人におすすめ SONYのフラグシップモデル「SONY WF-1000XM4」ってどれくらい性 ...

スイッチボット

2023/1/14

【SwitchBot Hub Mini】アプリにないエアコンなどの家電をその他で登録する方法

こんな人におすすめSwitchBot Hub Miniに我が家のエアコンを登録したいけど、SwitchBotア ...

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

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

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

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

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

  • この記事を書いた人

メガネ

ベンチャー企業のWebエンジニア駆け出し。独学のPythonで天文学系の大学院を修了→新卒を1.5年で辞める→転職→今に至る。
常時金欠のガジェット好きでM1 MacBook Pro x Galaxy S22 Ultraの狂人。

自己紹介と半生→変わって楽しいの繰り返し レビュー依頼などお問い合わせ Twitter@m_ten_pa

-Python基礎
-,