从Pandas聚合结果中格式化/抑制科学计数法

278

如何修改 pandas 中 groupby 操作输出的科学计数法格式以适应极大数字?

我知道如何在 Python 中进行字符串格式化,但是在这里应用它时感到困惑。

df1.groupby('dept')['data1'].sum()

dept
value1       1.192433e+08
value2       1.293066e+08
value3       1.077142e+08

如果我将其转换为字符串,这将抑制科学计数法,但现在我想知道如何格式化字符串并添加小数点。

sum_sales_dept.astype(str)

3
可能是抑制Pandas中的科学计数法?的重复问题。 - Dan Allan
3
我看到了那个问题,但我不确定它如何帮助我。 我只想保留当前的数据类型float,并在结果中显示所有小数,而不是科学计数法。 - horatio1701d
那可能只是一个显示问题。但如果您认为您的问题与Dan链接中的问题有所不同,则需要发布更多关于您的问题的信息,最好附带一个能够重现问题的小数据集。此外,您的结果上的dtypes是什么? - TomAugspurger
虽然从技术上来说,这个问题并不是一个重复的问题,但是另一个问题的答案可以同时完成这个问题的目标,并且在千位数之间添加逗号,而且字符更少! - Josiah Yoder
尽管目前在pandas中抑制科学计数法?被标记为与此问题重复,但它的最佳答案比这个问题更好,因为它还在千位数之间添加了逗号。因此,我支持上述建议将重复标记撤销 - Josiah Yoder
9个回答

393

当然,我在评论中提供的答案并不是很有帮助。你可以像这样指定自己的字符串转换器。

In [25]: pd.set_option('display.float_format', lambda x: '%.3f' % x)

In [28]: Series(np.random.randn(3))*1000000000
Out[28]: 
0    -757322420.605
1   -1436160588.997
2   -1235116117.064
dtype: float64

我不确定这是最优的方法,但它能够工作。

仅为了美观而将数字转换为字符串似乎不是一个好主意,但如果你有充分的理由,那么这是一种可行的方式:

In [6]: Series(np.random.randn(3)).apply(lambda x: '%.3f' % x)
Out[6]: 
0     0.026
1    -0.482
2    -0.694
dtype: object

1
谢谢,丹。你知道如何重置pandas选项吗? - Josh
4
要暂时设置 pandas 中的选项,您可以使用 pandas.option_context(请参见 http://pandas.pydata.org/pandas-docs/stable/generated/pandas.option_context.html)。 - muellermarkus
2
通常情况下,这不是为了美观的目的,而是为了通过视觉皮层更快地浏览大型数字数据框中的信息。 - matanster
pd.set_option('display.float_format', lambda x: '%.3f' % x) 对我也起作用了。 - driven_spider
13
这个方法可行,而且你也可以使用更新的 f-string 标记。例如,如果你想要千位分隔符,可以这样写:pd.set_option('display.float_format', lambda x: f'{x:,.3f}') - 576i
pd.set_option('float_format', '{:.2f}'.format) 可以将 Pandas 数据框中的浮点数格式化为两位小数。 - Muhammad Yasirroni

178

这是另一种做法,与Dan Allan的答案类似,但不使用lambda函数:

这是另一种方法,类似于Dan Allan的答案,但不需要使用lambda函数:

>>> pd.options.display.float_format = '{:.2f}'.format
>>> Series(np.random.randn(3))
0    0.41
1    0.99
2    0.10
>>> pd.set_option('display.float_format', '{:.2f}'.format)

3
我认为使用格式化字符串会更容易被不太熟悉Python的团队成员接受,他们可能不理解lambda函数。 - Steven C. Howell

47

您可以使用round函数仅针对特定数据帧来抑制科学计数法:

df1.round(4)

或者你可以通过以下方式全局地禁止它:

pd.options.display.float_format = '{:.4f}'.format

30

如果您想要在Jupyter笔记本单元格中样式化数据框的输出,您可以按数据帧设置显示样式:

df = pd.DataFrame({'A': np.random.randn(4)*1e7})
df.style.format("{:.1f}")

在此输入图片描述

请查看此处的文档。


太好了。这怎么能仅应用于Pandas系列? - Bowen Liu

23

全局设置固定小数位数通常不是一个好主意,因为它不可能是所有数据的适当小数位数,无论大小。相反,尝试使用以下方法,这只会给您大量和非常小的值提供科学表示法(并添加千位分隔符,除非您省略了","):

pd.set_option('display.float_format', lambda x: '%,g' % x)

或者尝试使用以下方法几乎完全抑制科学计数法而不失精度:

pd.set_option('display.float_format', str)

1
谢谢!第一个选项在某些情况下会失败。 - Ethan

7

这个有用的评论基础上,这里提供一种解决方案,仅设置格式选项以显示结果,而不会永久更改选项:

with pd.option_context('display.float_format', lambda x: f'{x:,.3f}'):
    display(sum_sales_dept)

dept
value1  119,243,300.0
value2  129,306,600.0
value3  107,714,200.0

7

我有多个包含不同浮点数的数据框,感谢 Allan 的想法,使其长度变得动态。

pd.set_option('display.float_format', lambda x: f'%.{len(str(x%1))-2}f' % x)

这样做的缺点是,如果您在浮点数中有最后一个0,它将被截断。因此,它将不是0.000070,而是0.00007。


迄今为止最被低估的答案之一。 - Michael
你能稍微解释一下你在尝试做什么吗? 因为(lambda x: f'%.{len(str(x%1))-2}f' % x)(0.000070)返回'0.000'(而不是'0.00007'),而(lambda x: f'%.{len(str(x%1))-2}f' % x)(1.000070)返回'1.000070000000000014' - Cristian Ciupitu
我不知道为什么你会得到那样的结果。这个方法在我的电脑上是有效的。我的目标是检查多个数据框中数据的正确性。大部分数据都是长浮点数,所以它们被打印成科学计数法。我没有使用某些apply函数将其应用于每个数据框。我将其作为参数传递给了pd.set_options函数,在文件开头进行设置。我在那里做的是动态地检查小数位数。我通过减去整数部分来获取余数,并将其转换为字符串以计算长度。然后减去2,因为小数点在第二个位置。 - Full.Of.Life

0
如果您想使用这些值,例如作为csv.writer的一部分,可以在创建列表之前对数字进行格式化:
df['label'].apply(lambda x: '%.17f' % x).values.tolist()

0

我至少参考过这个问题十几次,因为我总是忘记如何做。使用 pandas.DataFrame.round 的一个更简单的解决方案(我发现)在此处没有被提到:

df.describe().round(5)

或者

df.column.describe().round(5)

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