美化 pandas 数据框的输出

239

我该如何将pandas数据框以漂亮的文本表格形式打印出来,就像下面这个例子一样?

+------------+---------+-------------+
| column_one | col_two |   column_3  |
+------------+---------+-------------+
|          0 |  0.0001 | ABCD        |
|          1 |  1e-005 | ABCD        |
|          2 |  1e-006 | long string |
|          3 |  1e-007 | ABCD        |
+------------+---------+-------------+
10个回答

344

我刚发现了一个满足这个需求的好工具,它被称为 tabulate

它可以打印表格数据并且能与DataFrame一起使用。

from tabulate import tabulate
import pandas as pd

df = pd.DataFrame({'col_two' : [0.0001, 1e-005 , 1e-006, 1e-007],
                   'column_3' : ['ABCD', 'ABCD', 'long string', 'ABCD']})

print(tabulate(df, headers='keys', tablefmt='psql'))

+----+-----------+-------------+
|    |   col_two | column_3    |
|----+-----------+-------------|
|  0 |    0.0001 | ABCD        |
|  1 |    1e-05  | ABCD        |
|  2 |    1e-06  | long string |
|  3 |    1e-07  | ABCD        |
+----+-----------+-------------+

注意:

要抑制所有类型数据的行索引,请传递 showindex="never"showindex=False


6
如果您无法访问最前沿技术,可以使用 tabulate([list(row) for row in df.values], headers=list(df.columns)) 来去掉索引。 - Pedro M Duarte
2
当行索引和列中存在层级结构时,程序的运行效果会不太好。 - Siddharth
请确保使用print(tabulate(df, **kwargs))而不是简单地使用tabulate(df, **kwargs);后者将显示所有新行\n.... - Dror
7
为了隐藏左侧索引列,可能需要添加 showindex=False - Arthur
1
我真的很希望 pandas 可以将 tabulate 作为可选依赖项捆绑在一起,并允许 df.to_tabular(*args, **kwargs) - BallpointBen

125

pandas >= 1.0

如果您想要一个内置函数将数据转储到一些 Github Markdown 中,现在您可以使用一个。请查看 to_markdown

df = pd.DataFrame({"A": [1, 2, 3], "B": [1, 2, 3]}, index=['a', 'a', 'b'])  
print(df.to_markdown()) 
                                               
|    |   A |   B |
|:---|----:|----:|
| a  |   1 |   1 |
| a  |   2 |   2 |
| b  |   3 |   3 |

这是在github上的样子:

enter image description here

请注意,to_markdown 在幕后调用 tabulate,因此您仍需要安装 tabulate 包。但这意味着 to_markdown 可以通过关键字参数支持 20 多种不同的表格格式,这些参数会传递给 tabulate。例如,您可以使用 df.to_markdown(headers='keys', tablefmt='psql') 获得与 Romain's answer 相同的输出。

1
我使用了 to_markdown 将脚本中的 markdown 转换为文本,并将其导入到 glow - (github) 中,以在终端中呈现出漂亮的结果。(脚本在这里) - Sean Breckenridge
@SeanBreckenridge 的链接可能已损坏或无法从公共网络访问。 - cs95
啊,谢谢提醒;已经移动到另一个文件夹了。这是一个永久链接 - Sean Breckenridge
1
通过向 tabulate 传递更多参数,to_markdown 实际上支持20多种格式(https://github.com/astanin/python-tabulate#table-format)和许多其他关键字。 - Edward

62

如果你正在使用Jupyter笔记本,可以运行以下代码以交互方式显示数据框中的格式良好的表格。

此答案基于上面的to_html('temp.html')答案,但不是创建文件直接在笔记本中显示格式良好的表格:

from IPython.display import display, HTML

display(HTML(df.to_html()))

此代码的功劳归功于以下示例:在iPython Notebook中将DataFrame显示为表格


3
比使用tabulate更好。 - hzitoun
7
对我来说,即使只有 display(df) 看起来也很好。 - Gabriele
太棒了,我真的很喜欢这样。它不仅打印得漂亮,而且显示了所有的列和行...太好了... - Memin
不知道为什么,但这给了我 <IPython.core.display.HTML object> - akki
从IPython.display导入display; 对于大列,display(df)也运行良好。 - Dhvani Shah
这个解决方案对我来说不起作用。但是你分享的链接正是我在寻找的。谢谢你。 - AndreP

52

一个简单的方法是将输出作为 html,这是 pandas 默认支持的:pandas.DataFrame.to_html

df.to_html('temp.html')

1
这是一个被低估的回应。不需要额外的软件包。在我自己的情况下,我无法让tabulate打印我所需的具有两个索引的透视表。df.to_html-毫无问题。如果您需要将多个数据帧放入同一个HTML中,只需执行df1.to_html() + df2.to_html() +等等... - Dr Phil

15

您可以使用prettytable将表格呈现为文本。关键是将数据框转换为内存中的csv文件,并让prettytable读取它。以下是代码:

from StringIO import StringIO
import prettytable    

output = StringIO()
data_frame.to_csv(output)
output.seek(0)
pt = prettytable.from_csv(output)
print pt

这是哪个版本的pandas? - WAF
7
据我所知,prettytable 被普遍认为是被放弃的软件。很遗憾,因为它是一个不错的软件包。 :( - dmn
@dmn所以这个项目不再维护了? - muon
1
prettytable自2013年4月6日以来没有发布过版本。 tabulate是它的精神前任,有定期发布,最近一次更新于2019年1月24日。 - noddy
4
"prettytable" 已经被交由 jazzband 维护并重新启用!太棒了!https://github.com/jazzband/prettytable - Nick Crews

15

在Mark的回答后面,如果你因一些原因不使用Jupyter,例如你想在控制台上进行一些快速测试,那么可以使用DataFrame.to_string方法,该方法从Pandas 0.12(2014年)开始可用。

import pandas as pd

matrix = [(1, 23, 45), (789, 1, 23), (45, 678, 90)]
df = pd.DataFrame(matrix, columns=list('abc'))
print(df.to_string())

#  outputs:
#       a    b   c
#  0    1   23  45
#  1  789    1  23
#  2   45  678  90

3
如果您不需要处理数据,那么您不需要使用.to_string()方法,print(df)可以达到同样的效果。 - Spartan
1
这应该是最受欢迎和被接受的答案。开箱即用,易于使用(最重要的是,它有效!)。 - akki
1
这应该是最受欢迎和被接受的答案。它具有独特的功能,易于使用(最重要的是,它有效!)。 - undefined
3
@Jakob:确实,毕竟问题是关于漂亮打印的,但你可以更改显示的列数,全局地使用 pd.set_option('display.max_columns', None) 或者在代码块中使用 with pd.option_context(‘display.max_columns’, None): print(df) - Spartan
3
@Jakob:没错,毕竟问题是关于漂亮的打印输出,但你可以改变显示的列数,可以全局地使用pd.set_option('display.max_columns', None),或者使用with pd.option_context(‘display.max_columns’, None): print(df)这样的方式。 - undefined
显示剩余3条评论

8
我曾经使用Ofer的答案一段时间,在大多数情况下都非常好。不幸的是,由于pandas的to_csvprettytable的from_csv之间存在不一致性,我不得不以不同的方式使用prettytable。
一个失败的例子是包含逗号的数据框:
pd.DataFrame({'A': [1, 2], 'B': ['a,', 'b']})

Prettytable会引发以下形式的错误:

Error: Could not determine delimiter

以下函数处理此情况:
def format_for_print(df):    
    table = PrettyTable([''] + list(df.columns))
    for row in df.itertuples():
        table.add_row(row)
    return str(table)

如果您不关心索引,请使用:
def format_for_print2(df):    
    table = PrettyTable(list(df.columns))
    for row in df.itertuples():
        table.add_row(row[1:])
    return str(table)

你好, format_for_print() 函数似乎没有打印 Pandas DataFrame 的索引。我使用 df.index.name = 'index' 设置了索引,但这并没有打印带有名称的索引列。 - edesz

8
也许您正在寻找类似于这样的内容:
def tableize(df):
    if not isinstance(df, pd.DataFrame):
        return
    df_columns = df.columns.tolist() 
    max_len_in_lst = lambda lst: len(sorted(lst, reverse=True, key=len)[0])
    align_center = lambda st, sz: "{0}{1}{0}".format(" "*(1+(sz-len(st))//2), st)[:sz] if len(st) < sz else st
    align_right = lambda st, sz: "{0}{1} ".format(" "*(sz-len(st)-1), st) if len(st) < sz else st
    max_col_len = max_len_in_lst(df_columns)
    max_val_len_for_col = dict([(col, max_len_in_lst(df.iloc[:,idx].astype('str'))) for idx, col in enumerate(df_columns)])
    col_sizes = dict([(col, 2 + max(max_val_len_for_col.get(col, 0), max_col_len)) for col in df_columns])
    build_hline = lambda row: '+'.join(['-' * col_sizes[col] for col in row]).join(['+', '+'])
    build_data = lambda row, align: "|".join([align(str(val), col_sizes[df_columns[idx]]) for idx, val in enumerate(row)]).join(['|', '|'])
    hline = build_hline(df_columns)
    out = [hline, build_data(df_columns, align_center), hline]
    for _, row in df.iterrows():
        out.append(build_data(row.tolist(), align_right))
    out.append(hline)
    return "\n".join(out)


df = pd.DataFrame([[1, 2, 3], [11111, 22, 333]], columns=['a', 'b', 'c'])
print tableize(df)

输出: +-------+----+-----+ | a | b | c | +-------+----+-----+ | 1 | 2 | 3 | | 11111 | 22 | 333 | +-------+----+-----+

最佳答案,你能解释一下为什么它如此有效吗? - Farhan Hai Khan
1
这对于打印我的无服务器Dataproc作业分析摘要表格非常有帮助。我不想使用自定义容器来添加tabulate库。你真是救星! - L Co
1
这是一个惊人的答案!对于像这样的“简单”事情,不需要任何依赖项,但我也不想自己编码。表格也很漂亮。 - John Haberstroh
我非常喜欢这个答案,所以我添加了一个max_col_width参数,对于具有随机长值的表格应该很有帮助。 - John Haberstroh
我非常喜欢这个答案,我添加了一个max_col_width参数,对于具有随机长值的表格应该很有帮助。 - undefined

6

我使用rich库来实现这个功能,它的表格比基于.to_markdown()的表格看起来更美观。

import pandas as pd
from rich.console import Console
from rich.table import Table
df = pd.DataFrame({'col_two' : [0.0001, 1e-005 , 1e-006, 1e-007],
                   'column_3' : ['ABCD', 'ABCD', 'long string', 'ABCD']})
console = Console()
table = Table('Title')
table.add_row(df.to_string(float_format=lambda _: '{:.4f}'.format(_)))
console.print(table)

给你这个表格:

enter image description here

更多自定义选项请参阅文档:

https://rich.readthedocs.io/en/stable/tables.html


1
沿着这种方法,有一个名为rich-dataframe的工具。 - Wayne
我刚刚分叉了rich-dataframe代码,它可以轻松地放置在其他代码中,并且我对其进行了更改,这样只有当超过行或列的阈值时才会显示标题,我还删除了动画效果,这样如果您想要在Jupyter中使用它,则不会导致奇怪的间距。即使您不需要这两个自定义选项,但是查看我如何进行操作可能会帮助您按照自己的意愿进行自定义。请在我的fork 此处 查看。 - Wayne

2

更新:更好的解决方案是在单元格的最后一行直接放置数据框变量名,它会自动以漂亮的格式打印出来。

import pandas as pd
import numpy as np

df = pd.DataFrame({'Data1': np.linspace(0,10,11), 'Data2': np.linspace(10,0,11)})
df

这可能不是问题所问的。将变量放在末尾并不执行“print”函数,即结果不会持久存在,并且很容易被另一个对象调用覆盖。 - Bao Le

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接