如何在Pandas DataFrame的to_string输出中换行长列名?

3 投票
2 回答
96 浏览
提问于 2025-04-14 17:23

考虑这个例子:

import pandas as pd

df = pd.DataFrame({
  "LIDSA": [0, 1, 2, 3],
  "CAE": [3, 5, 7, 9],
  "FILA": [1, 2, 3, 4], # 2 is default, so table idx 1 is default
  "VUAMA": [0.5, 1.0, 1.5, 2.0],
})
df_colnames = { # https://stackoverflow.com/q/48243818
  "LIDSA": "Lorem ipsum dolor sit amet",
  "CAE": "Consectetur adipiscing elit",
  "FILA": "Fusce imperdiet libero arcu",
  "VUAMA": "Vitae ultricies augue molestie ac",
}

# "Pandas autodetects the size of your terminal window if you set pd.options.display.width = 0" https://stackoverflow.com/q/11707586
with pd.option_context('display.max_rows', None, 'display.max_columns', None, 'display.width', 0, 'max_colwidth', 20, 'display.float_format', "{:.2f}".format):
  df_str = df.rename(df_colnames,axis=1).to_string()

print(df_str)

这段代码在终端输出时,显示的宽度是111个字符:

   Lorem ipsum dolor sit amet  Consectetur adipiscing elit  Fusce imperdiet libero arcu  Vitae ultricies augue
 molestie ac
0                           0                            3                            1
        0.50
1                           1                            5                            2
        1.00
2                           2                            7                            3
        1.50
3                           3                            9                            4
        2.00

结果是,只有最后一列的内容被换行了(相应的值也跟着换行)。我希望每个长的列名在大约20个字符的时候就换行,这样输出的值也能对应换行,像这样:

   Lorem ipsum dolor      Consectetur  Fusce imperdiet    Vitae ultricies
            sit amet  adipiscing elit      libero arcu  augue molestie ac
0                  0                3                1               0.50
1                  1                5                2               1.00
2                  2                7                3               1.50
3                  3                9                4               2.00

我原以为设置 'max_colwidth', 20 就能实现这个效果,但显然没有。

我甚至尝试在长列名中添加明确的换行符,但它们只显示为 \n,列名还是在一行里(这在Pandas列名中的换行中也有提到)。

那么,在Pandas中,是否有办法让长列名在输出为普通文本字符串时“自动换行”呢?

2 个回答

1

Pandas这个库没有提供一个简单的方法来自动换行或分行显示长列名。当你把一个数据表(DataFrame)转换成字符串时,设置叫做max_colwidth的选项只影响表格里的数据,而不影响列标题。如果你尝试在列名中添加换行符,你会发现它并没有改变标题的显示方式;相反,你会在输出中看到"\n"这样的字符,这显然不是你想要的效果。

如果想让列名换行显示,你需要自己动手,稍微想一些办法。具体步骤是:

1. 写一个函数,这个函数可以把长列名分成几个小部分,每部分要足够短(比如,不超过20个字符),这样就能单独放在一行上。

2. 用这个函数处理所有的列名,然后调整你的数据表显示方式,让这些多行的列名看起来正常。

这个方法需要你手动修改列名,在你想换行的地方加上换行符,然后确保数据表的字符串表示(也就是你打印出来的内容)能正确显示这些换行。这主要是为了在你实际打印或展示数据表之前,先准备好数据和显示设置。

import pandas as pd

# Original DataFrame
df = pd.DataFrame({
    "LIDSA": [0, 1, 2, 3],
    "CAE": [3, 5, 7, 9],
    "FILA": [1, 2, 3, 4],
    "VUAMA": [0.5, 1.0, 1.5, 2.0],
})

# Dictionary with long column names
df_colnames = {
    "LIDSA": "Lorem ipsum dolor sit amet",
    "CAE": "Consectetur adipiscing elit",
    "FILA": "Fusce imperdiet libero arcu",
    "VUAMA": "Vitae ultricies augue molestie ac",
}

# Custom function to word-wrap text
def word_wrap(text, max_width):
    """
    Word-wrap text at a specified width. Attempts to break lines at word boundaries
    where possible.
    """
    words = text.split()
    lines = []
    current_line = []
    current_length = 0

    for word in words:
        if current_length + len(word) <= max_width:
            current_line.append(word)
            current_length += len(word) + 1  # +1 for space
        else:
            lines.append(' '.join(current_line))
            current_line = [word]
            current_length = len(word) + 1
    lines.append(' '.join(current_line))  # Add the last line

    return '\n'.join(lines)

# Apply word-wrap to column names
wrapped_colnames = {col: word_wrap(name, 20) for col, name in df_colnames.items()}

# Rename DataFrame columns
df = df.rename(columns=wrapped_colnames)

# Print the DataFrame with modified display settings
with pd.option_context('display.max_rows', None, 'display.max_columns', None, 'display.width', 0, 'max_colwidth', 20, 'display.float_format', "{:.2f}".format):
    print(df.to_string())
5

你可以使用 textwrap.wraptabulate 来实现这个功能:

#  pip install tabulate
from textwrap import wrap
from tabulate import tabulate

df_colnames_wrap = {k: '\n'.join(wrap(v, 20))
                    for k,v in df_colnames.items()}

print(tabulate(df.rename(columns=df_colnames_wrap),
               headers='keys', tablefmt='plain'))

输出结果:

      Lorem ipsum dolor        Consectetur    Fusce imperdiet      Vitae ultricies
               sit amet    adipiscing elit        libero arcu    augue molestie ac
 0                    0                  3                  1                  0.5
 1                    1                  5                  2                  1
 2                    2                  7                  3                  1.5
 3                    3                  9                  4                  2

使用浮点数格式化:

print(tabulate(df.rename(columns=df_colnames_wrap)
                 .convert_dtypes(),
               headers='keys', tablefmt='plain',
               floatfmt='.2f'
              ))

输出结果:

      Lorem ipsum dolor        Consectetur    Fusce imperdiet      Vitae ultricies
               sit amet    adipiscing elit        libero arcu    augue molestie ac
 0                    0                  3                  1                 0.50
 1                    1                  5                  2                 1.00
 2                    2                  7                  3                 1.50
 3                    3                  9                  4                 2.00

撰写回答