Python - 美化打印误差条

8
我正在使用带有numpy、scipy和matplotlib的python进行数据评估。结果是我获得了平均值和拟合参数以及误差线。
我希望Python能够根据给定的精度自动对这些数据进行漂亮的打印格式。例如:
假设我得到的结果为,是否有一种方法可以在指定精度为2时自动将其格式化为<1.235(12)x10^-2>,即在误差线中计算精度,而不是在值中。
有人知道提供此功能的软件包吗?还是我必须自己实现?
是否有一种方法将其注入到Python字符串格式化机制中?即能够编写类似于<“%.2N”%(0.012345,0.0000123)>的代码。
我已经查看了numpy和scipy的文档并进行了谷歌搜索,但我找不到任何东西。我认为这对于处理统计数据的每个人都是有用的功能。
感谢您的帮助!
编辑:如Nathan Whitehead所请求,我将给出一些示例。
123 +- 1         ----precision 1----->  123(1)
123 +- 1.1       ----precision 2----->  123.0(11)
0.0123 +- 0.001  ----precision 1----->  0.012(1)
123.111 +- 0.123 ----precision 2----->  123.11(12)

为了清晰起见,十的幂被省略了。括号内的数字是标准误差的简写表示法。括号前面的数字的最后一位和括号里面的数字的最后一位必须处于相同的小数位上。我找不到一个好的在线解释这个概念的原因。唯一找到的是这篇德语维基百科文章here。然而,这是一个非常常见且非常方便的表示法。
编辑2: 我自己实现了简写表示法:
#!/usr/bin/env python
# *-* coding: utf-8 *-*

from math import floor, log10

# uncertainty to string
def un2str(x, xe, precision=2):
    """pretty print nominal value and uncertainty

    x  - nominal value
    xe - uncertainty
    precision - number of significant digits in uncertainty

    returns shortest string representation of `x +- xe` either as
        x.xx(ee)e+xx
    or as
        xxx.xx(ee)"""
    # base 10 exponents
    x_exp = int(floor(log10(x)))
    xe_exp = int(floor(log10(xe)))

    # uncertainty
    un_exp = xe_exp-precision+1
    un_int = round(xe*10**(-un_exp))

    # nominal value
    no_exp = un_exp
    no_int = round(x*10**(-no_exp))

    # format - nom(unc)exp
    fieldw = x_exp - no_exp
    fmt = '%%.%df' % fieldw
    result1 = (fmt + '(%.0f)e%d') % (no_int*10**(-fieldw), un_int, x_exp)

    # format - nom(unc)
    fieldw = max(0, -no_exp)
    fmt = '%%.%df' % fieldw
    result2 = (fmt + '(%.0f)') % (no_int*10**no_exp, un_int*10**max(0, un_exp))

    # return shortest representation
    if len(result2) <= len(result1):
        return result2
    else:
        return result1


if __name__ == "__main__":
    xs    = [123456, 12.34567, 0.123456, 0.001234560000, 0.0000123456]
    xes   = [   123,  0.00123, 0.000123, 0.000000012345, 0.0000001234]
    precs = [     1,        2,        3,              4,            1]

    for (x, xe, prec) in zip(xs, xes, precs):
        print '%.6e +- %.6e @%d --> %s' % (x, xe, prec, un2str(x, xe, prec))

输出:

1.234560e+05 +- 1.230000e+02 @1 --> 1.235(1)e5
1.234567e+01 +- 1.230000e-03 @2 --> 12.3457(12)
1.234560e-01 +- 1.230000e-04 @3 --> 0.123456(123)
1.234560e-03 +- 1.234500e-08 @4 --> 0.00123456000(1235)
1.234560e-05 +- 1.234000e-07 @1 --> 1.23(1)e-5

1
你能给更多的例子吗?我不理解 1.235(12) x 10^-2 是什么意思,以及它与 0.0123450.000123 的联系。 - Nathan Whitehead
当然,1.235(12) x 10^-21.235 x 10^-2 +- 0.0012 x 10^-2的简写符号。由于标准误差中指定了精度为2,原始数字0.012345被四舍五入。数字0.000123是我的结果的标准误差。我将在原帖中添加更多示例。 - Lemming
不错,但为了处理负数x,你应该在log10中取x的绝对值。 - Bobson Dugnutt
2个回答

2

由于x +- y不是标准类型(可能被看作具有实部x和虚部y的复数,但这并没有简化任何事情...),但您可以通过创建类型并覆盖字符串函数来完全控制其显示方式,例如:

class Res(object):
   def __init__(self, res, delta):
     self.res = res
     self.delta = delta

   def __str__(self):
     return "%f +- %f"%(self.res,self.delta)

if __name__ == '__main__':
   x = Res(0.2710,0.001)
   print(x)
   print(" a result: %s" % x)

你可以在__str__函数内部进行一些更加高级的操作...

谢谢,这是关于格式化字符串的一个开端。你知道传递参数的方法吗?例如,在 '%.4f' 中的 .4。我自己实现了速记符号,请参见编辑2。 - Lemming
抱歉没有完全阅读您的回复,是的,您也可以动态地创建格式化字符串,fmstr = "%.df" % (somenumber) 如果somenumber基于+-部分中数字的数量,那么这应该可以按照您想要的方式工作。 - bjarneh

2

对于仍然对这个问题感兴趣的人,可以查看 gvar 库,以及此处的示例(即OP所期望的行为的最后部分)。


已经过了很长时间,我无法再在原始用例上进行测试。但是,从文档和示例中看来,这似乎正是我所寻找的,并且更多。谢谢! - Lemming

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