pandas 显示:截断列显示而不是换行
pandas display: truncate column display rather than wrapping
列名过长,无论options如何设置,DataFrames都会显示得很乱。
信息:我在 Jupyter QtConsole,pandas 0.20.1,在启动时指定了以下相关选项:
pd.set_option('display.max_colwidth', 20)
pd.set_option('expand_frame_repr', False)
pd.set_option('display.max_rows', 25)
问题:如何在必要时截断 DataFrame 而不是将列换行到下一行,同时保持 expand_frame_repr=False
?
举个例子。同样,问题不取决于列数,而是取决于列的长度。
这不会导致问题:
df = pd.DataFrame(np.random.randn(1000, 1000),
columns=['col' + str(i) for i in range(1000)])
因为输出是完全可读的,看起来像:
具有长列名称的同一个 DataFrame 导致了我正在谈论的问题:
df = pd.DataFrame(np.random.randn(1000, 1000),
columns=['very_long_col_name_'
+ str(i) for i in range(1000)])
有什么方法可以使第二个输出与我缺少的第一个输出一致吗? (通过指定一个选项,而不是每次我想查看时都使用 .iloc
。)
使用max_columns
from string import ascii_letters
df = pd.DataFrame(np.random.randint(10, size=(5, 52)), columns=list(ascii_letters))
with pd.option_context(
'display.max_colwidth', 20,
'expand_frame_repr', False,
'display.max_rows', 25,
'display.max_columns', 5,
):
print(df.add_prefix('really_long_column_name_'))
really_long_column_name_a really_long_column_name_b ... really_long_column_name_Y really_long_column_name_Z
0 8 1 ... 1 9
1 8 5 ... 2 1
2 5 0 ... 9 9
3 6 8 ... 0 9
4 1 2 ... 7 1
[5 rows x 52 columns]
另一个想法...显然不是您想要的,但也许您可以根据需要进行调整。
d1 = df.add_suffix('_really_long_column_name')
with pd.option_context('display.max_colwidth', 4, 'expand_frame_repr', False):
mw = pd.get_option('display.max_colwidth')
print(d1.rename(columns=lambda x: x[:mw-3] + '...' if len(x) > mw else x))
a... b... c... d... e... f... g... h... i... j... ... Q... R... S... T... U... V... W... X... Y... Z...
0 6 5 5 5 8 3 5 0 7 6 ... 9 0 6 9 6 8 4 0 6 7
1 0 5 4 7 2 5 4 3 8 7 ... 8 1 5 3 5 9 4 5 5 3
2 7 2 1 6 5 1 0 1 3 1 ... 6 7 0 9 9 5 2 8 2 2
3 1 8 7 1 4 5 5 8 8 3 ... 3 6 5 7 1 0 8 1 4 0
4 7 5 6 2 4 9 7 9 0 5 ... 6 8 1 6 3 5 4 2 3 2
看起来它需要改进。 repr
函数中的相关代码似乎在这里:
max_rows = get_option("display.max_rows")
max_cols = get_option("display.max_columns")
show_dimensions = get_option("display.show_dimensions")
if get_option("display.expand_frame_repr"):
width, _ = console.get_console_size()
else:
width = None
self.to_string(buf=buf, max_rows=max_rows, max_cols=max_cols,
line_width=width, show_dimensions=show_dimensions)
所以要么你传递 expand_frame_repr=True
并且它换行,要么你传递 expand_frame_repr=False
而它不应该。不过代码好像有bug(这个应该是pandas 0.20.3 iirc):
在 pd.io.formats.format.DataFrameFormatter
中:
def _chk_truncate(self):
"""
Checks whether the frame should be truncated. If so, slices
the frame up.
"""
from pandas.core.reshape.concat import concat
# Column of which first element is used to determine width of a dot col
self.tr_size_col = -1
# Cut the data to the information actually printed
max_cols = self.max_cols
max_rows = self.max_rows
if max_cols == 0 or max_rows == 0: # assume we are in the terminal
# (why else = 0)
(w, h) = get_terminal_size()
self.w = w
self.h = h
if self.max_rows == 0:
dot_row = 1
prompt_row = 1
if self.show_dimensions:
show_dimension_rows = 3
n_add_rows = (self.header + dot_row + show_dimension_rows +
prompt_row)
# rows available to fill with actual data
max_rows_adj = self.h - n_add_rows
self.max_rows_adj = max_rows_adj
# Format only rows and columns that could potentially fit the
# screen
if max_cols == 0 and len(self.frame.columns) > w:
max_cols = w
if max_rows == 0 and len(self.frame) > h:
max_rows = h
看起来它打算做你想做的事,但没有完成。它根据列的 数量 检查 max_cols
,而不是列的总宽度。
所以你可以创建一个 show_df
函数来计算正确的列数并在 option_context
中显示它,就像 pi2Squared 的答案一样,或者在这里修复它(如果可能提交补丁你需要分发它)。
正如其他人所指出的,Pandas 本身似乎存在漏洞或设计不当,因此需要解决方法。
大多数情况下,数字列会出现此问题,因为数字相对较短。如果列标题中有空格,Pandas 会将列标题拆分为多行,因此您可以 "hack in" 通过在显示数据框时将空格插入数字列的列标题来实现正确的行为。我有一个 one-liner 可以做到这一点:
def colfix(df, L=5): return df.rename(columns=lambda x: ' '.join(x.replace('_', ' ')[i:i+L] for i in range(0,len(x),L)) if df[x].dtype in ['float64','int64'] else x )
显示您的数据框,只需输入
colfix(your_df)
请注意,重命名不会永久更改数据框,它只会在名称中添加空格,以便一次性显示它。
结果(在 Jupyter Notebook 中):
与colfix
:
没有:
列名过长,无论options如何设置,DataFrames都会显示得很乱。
信息:我在 Jupyter QtConsole,pandas 0.20.1,在启动时指定了以下相关选项:
pd.set_option('display.max_colwidth', 20)
pd.set_option('expand_frame_repr', False)
pd.set_option('display.max_rows', 25)
问题:如何在必要时截断 DataFrame 而不是将列换行到下一行,同时保持 expand_frame_repr=False
?
举个例子。同样,问题不取决于列数,而是取决于列的长度。
这不会导致问题:
df = pd.DataFrame(np.random.randn(1000, 1000),
columns=['col' + str(i) for i in range(1000)])
因为输出是完全可读的,看起来像:
具有长列名称的同一个 DataFrame 导致了我正在谈论的问题:
df = pd.DataFrame(np.random.randn(1000, 1000),
columns=['very_long_col_name_'
+ str(i) for i in range(1000)])
有什么方法可以使第二个输出与我缺少的第一个输出一致吗? (通过指定一个选项,而不是每次我想查看时都使用 .iloc
。)
使用max_columns
from string import ascii_letters
df = pd.DataFrame(np.random.randint(10, size=(5, 52)), columns=list(ascii_letters))
with pd.option_context(
'display.max_colwidth', 20,
'expand_frame_repr', False,
'display.max_rows', 25,
'display.max_columns', 5,
):
print(df.add_prefix('really_long_column_name_'))
really_long_column_name_a really_long_column_name_b ... really_long_column_name_Y really_long_column_name_Z
0 8 1 ... 1 9
1 8 5 ... 2 1
2 5 0 ... 9 9
3 6 8 ... 0 9
4 1 2 ... 7 1
[5 rows x 52 columns]
另一个想法...显然不是您想要的,但也许您可以根据需要进行调整。
d1 = df.add_suffix('_really_long_column_name')
with pd.option_context('display.max_colwidth', 4, 'expand_frame_repr', False):
mw = pd.get_option('display.max_colwidth')
print(d1.rename(columns=lambda x: x[:mw-3] + '...' if len(x) > mw else x))
a... b... c... d... e... f... g... h... i... j... ... Q... R... S... T... U... V... W... X... Y... Z...
0 6 5 5 5 8 3 5 0 7 6 ... 9 0 6 9 6 8 4 0 6 7
1 0 5 4 7 2 5 4 3 8 7 ... 8 1 5 3 5 9 4 5 5 3
2 7 2 1 6 5 1 0 1 3 1 ... 6 7 0 9 9 5 2 8 2 2
3 1 8 7 1 4 5 5 8 8 3 ... 3 6 5 7 1 0 8 1 4 0
4 7 5 6 2 4 9 7 9 0 5 ... 6 8 1 6 3 5 4 2 3 2
看起来它需要改进。 repr
函数中的相关代码似乎在这里:
max_rows = get_option("display.max_rows")
max_cols = get_option("display.max_columns")
show_dimensions = get_option("display.show_dimensions")
if get_option("display.expand_frame_repr"):
width, _ = console.get_console_size()
else:
width = None
self.to_string(buf=buf, max_rows=max_rows, max_cols=max_cols,
line_width=width, show_dimensions=show_dimensions)
所以要么你传递 expand_frame_repr=True
并且它换行,要么你传递 expand_frame_repr=False
而它不应该。不过代码好像有bug(这个应该是pandas 0.20.3 iirc):
在 pd.io.formats.format.DataFrameFormatter
中:
def _chk_truncate(self):
"""
Checks whether the frame should be truncated. If so, slices
the frame up.
"""
from pandas.core.reshape.concat import concat
# Column of which first element is used to determine width of a dot col
self.tr_size_col = -1
# Cut the data to the information actually printed
max_cols = self.max_cols
max_rows = self.max_rows
if max_cols == 0 or max_rows == 0: # assume we are in the terminal
# (why else = 0)
(w, h) = get_terminal_size()
self.w = w
self.h = h
if self.max_rows == 0:
dot_row = 1
prompt_row = 1
if self.show_dimensions:
show_dimension_rows = 3
n_add_rows = (self.header + dot_row + show_dimension_rows +
prompt_row)
# rows available to fill with actual data
max_rows_adj = self.h - n_add_rows
self.max_rows_adj = max_rows_adj
# Format only rows and columns that could potentially fit the
# screen
if max_cols == 0 and len(self.frame.columns) > w:
max_cols = w
if max_rows == 0 and len(self.frame) > h:
max_rows = h
看起来它打算做你想做的事,但没有完成。它根据列的 数量 检查 max_cols
,而不是列的总宽度。
所以你可以创建一个 show_df
函数来计算正确的列数并在 option_context
中显示它,就像 pi2Squared 的答案一样,或者在这里修复它(如果可能提交补丁你需要分发它)。
正如其他人所指出的,Pandas 本身似乎存在漏洞或设计不当,因此需要解决方法。
大多数情况下,数字列会出现此问题,因为数字相对较短。如果列标题中有空格,Pandas 会将列标题拆分为多行,因此您可以 "hack in" 通过在显示数据框时将空格插入数字列的列标题来实现正确的行为。我有一个 one-liner 可以做到这一点:
def colfix(df, L=5): return df.rename(columns=lambda x: ' '.join(x.replace('_', ' ')[i:i+L] for i in range(0,len(x),L)) if df[x].dtype in ['float64','int64'] else x )
显示您的数据框,只需输入
colfix(your_df)
请注意,重命名不会永久更改数据框,它只会在名称中添加空格,以便一次性显示它。
结果(在 Jupyter Notebook 中):
与colfix
:
没有: