【问题标题】:How to pretty-print a numpy.array without scientific notation and with given precision?如何在没有科学记数法和给定精度的情况下漂亮地打印 numpy.array?
【发布时间】:2011-02-22 22:08:57
【问题描述】:

我很好奇,是否有任何方法可以打印格式化的numpy.arrays,例如,以类似于以下的方式:

x = 1.23456
print '%.3f' % x

如果我想打印浮点数的numpy.array,它会打印几个小数,通常是“科学”格式,即使是低维数组也很难阅读。但是,numpy.array 显然必须打印为字符串,即使用%s。有解决方案吗?

【问题讨论】:

  • this discussion 也可能对那些通过谷歌搜索结束的人感兴趣。

标签: python numpy python-2.x pretty-print


【解决方案1】:

你可以使用set_printoptions来设置输出的精度:

import numpy as np
x=np.random.random(10)
print(x)
# [ 0.07837821  0.48002108  0.41274116  0.82993414  0.77610352  0.1023732
#   0.51303098  0.4617183   0.33487207  0.71162095]

np.set_printoptions(precision=3)
print(x)
# [ 0.078  0.48   0.413  0.83   0.776  0.102  0.513  0.462  0.335  0.712]

suppress 禁止对小数使用科学记数法:

y=np.array([1.5e-10,1.5,1500])
print(y)
# [  1.500e-10   1.500e+00   1.500e+03]
np.set_printoptions(suppress=True)
print(y)
# [    0.      1.5  1500. ]

请参阅docs for set_printoptions 了解其他选项。


要在本地应用打印选项,使用 NumPy 1.15.0 或更高版本,您可以使用 numpy.printoptions 上下文管理器。 比如在with-suiteprecision=3suppress=True里面设置:

x = np.random.random(10)
with np.printoptions(precision=3, suppress=True):
    print(x)
    # [ 0.073  0.461  0.689  0.754  0.624  0.901  0.049  0.582  0.557  0.348]

但在with-suite 之外,打印选项恢复为默认设置:

print(x)    
# [ 0.07334334  0.46132615  0.68935231  0.75379645  0.62424021  0.90115836
#   0.04879837  0.58207504  0.55694118  0.34768638]

如果您使用的是早期版本的 NumPy,您可以创建上下文管理器 你自己。例如,

import numpy as np
import contextlib

@contextlib.contextmanager
def printoptions(*args, **kwargs):
    original = np.get_printoptions()
    np.set_printoptions(*args, **kwargs)
    try:
        yield
    finally: 
        np.set_printoptions(**original)

x = np.random.random(10)
with printoptions(precision=3, suppress=True):
    print(x)
    # [ 0.073  0.461  0.689  0.754  0.624  0.901  0.049  0.582  0.557  0.348]

为了防止从浮点数末尾剥离零:

np.set_printoptions 现在有一个formatter 参数,允许您为每种类型指定格式函数。

np.set_printoptions(formatter={'float': '{: 0.3f}'.format})
print(x)

打印出来的

[ 0.078  0.480  0.413  0.830  0.776  0.102  0.513  0.462  0.335  0.712]

而不是

[ 0.078  0.48   0.413  0.83   0.776  0.102  0.513  0.462  0.335  0.712]

【讨论】:

  • 有没有办法只将格式应用于特定的打印语句(而不是设置 all 打印语句使用的一般输出格式)?
  • @Hiett:没有 NumPy 函数可以仅为一个 print 设置打印选项,但您可以使用上下文管理器来进行类似的操作。我已经编辑了上面的帖子以说明我的意思。
  • 你的np.set_printoptions(precision=3) 抑制结束零.. 你如何让它们像这样显示[ 0.078 0.480 0.413 0.830 0.776 0.102 0.513 0.462 0.335 0.712]
  • @Norfeldt:我在上面添加了一种方法。
  • 这很好用。附带说明一下,如果您想要字符串表示,也可以使用set_printoptions,而不必使用print。您只需调用 numpy 数组实例的__str__(),您将根据您设置的打印选项获得格式化字符串。
【解决方案2】:

您可以从np.array_str 命令获取np.set_printoptions 功能的子集,该功能仅适用于单个打印语句。

http://docs.scipy.org/doc/numpy/reference/generated/numpy.array_str.html

例如:

In [27]: x = np.array([[1.1, 0.9, 1e-6]]*3)

In [28]: print x
[[  1.10000000e+00   9.00000000e-01   1.00000000e-06]
 [  1.10000000e+00   9.00000000e-01   1.00000000e-06]
 [  1.10000000e+00   9.00000000e-01   1.00000000e-06]]

In [29]: print np.array_str(x, precision=2)
[[  1.10e+00   9.00e-01   1.00e-06]
 [  1.10e+00   9.00e-01   1.00e-06]
 [  1.10e+00   9.00e-01   1.00e-06]]

In [30]: print np.array_str(x, precision=2, suppress_small=True)
[[ 1.1  0.9  0. ]
 [ 1.1  0.9  0. ]
 [ 1.1  0.9  0. ]]

【讨论】:

  • 可能是最简单有效的选项,因为它不会在 printoptions 中引入永久性更改,也不需要昂贵的循环或 with 构造。格式化元素的可能性应该直接集成到numpy中(不明白为什么不是这样)。
【解决方案3】:

Unutbu 给出了一个非常完整的答案(他们也得到了我的 +1),但这里有一个低技术的替代方案:

>>> x=np.random.randn(5)
>>> x
array([ 0.25276524,  2.28334499, -1.88221637,  0.69949927,  1.0285625 ])
>>> ['{:.2f}'.format(i) for i in x]
['0.25', '2.28', '-1.88', '0.70', '1.03']

作为函数(使用format() 语法进行格式化):

def ndprint(a, format_string ='{0:.2f}'):
    print [format_string.format(v,i) for i,v in enumerate(a)]

用法:

>>> ndprint(x)
['0.25', '2.28', '-1.88', '0.70', '1.03']

>>> ndprint(x, '{:10.4e}')
['2.5277e-01', '2.2833e+00', '-1.8822e+00', '6.9950e-01', '1.0286e+00']

>>> ndprint(x, '{:.8g}')
['0.25276524', '2.283345', '-1.8822164', '0.69949927', '1.0285625']

数组的索引可以在格式字符串中访问:

>>> ndprint(x, 'Element[{1:d}]={0:.2f}')
['Element[0]=0.25', 'Element[1]=2.28', 'Element[2]=-1.88', 'Element[3]=0.70', 'Element[4]=1.03']

【讨论】:

    【解决方案4】:

    仅供参考 Numpy 1.15(发布日期待定)将include a context manager for setting print options locally。这意味着以下内容将与the accepted answer(由 unutbu 和 Neil G 编写)中的相应示例相同,而无需编写您自己的上下文管理器。例如,使用他们的例子:

    x = np.random.random(10)
    with np.printoptions(precision=3, suppress=True):
        print(x)
        # [ 0.073  0.461  0.689  0.754  0.624  0.901  0.049  0.582  0.557  0.348]
    

    【讨论】:

      【解决方案5】:

      使获取结果作为字符串变得非常容易(在今天的 numpy 版本中)的 gem 隐藏在 denis 答案中: np.array2string

      >>> import numpy as np
      >>> x=np.random.random(10)
      >>> np.array2string(x, formatter={'float_kind':'{0:.3f}'.format})
      '[0.599 0.847 0.513 0.155 0.844 0.753 0.920 0.797 0.427 0.420]'
      

      【讨论】:

        【解决方案6】:

        多年后,下面是另一个。但对于日常使用,我只是

        np.set_printoptions( threshold=20, edgeitems=10, linewidth=140,
            formatter = dict( float = lambda x: "%.3g" % x ))  # float arrays %.3g
        

        ''' printf( "... %.3g ... %.1f  ...", arg, arg ... ) for numpy arrays too
        
        Example:
            printf( """ x: %.3g   A: %.1f   s: %s   B: %s """,
                           x,        A,        "str",  B )
        
        If `x` and `A` are numbers, this is like `"format" % (x, A, "str", B)` in python.
        If they're numpy arrays, each element is printed in its own format:
            `x`: e.g. [ 1.23 1.23e-6 ... ]  3 digits
            `A`: [ [ 1 digit after the decimal point ... ] ... ]
        with the current `np.set_printoptions()`. For example, with
            np.set_printoptions( threshold=100, edgeitems=3, suppress=True )
        only the edges of big `x` and `A` are printed.
        `B` is printed as `str(B)`, for any `B` -- a number, a list, a numpy object ...
        
        `printf()` tries to handle too few or too many arguments sensibly,
        but this is iffy and subject to change.
        
        How it works:
        numpy has a function `np.array2string( A, "%.3g" )` (simplifying a bit).
        `printf()` splits the format string, and for format / arg pairs
            format: % d e f g
            arg: try `np.asanyarray()`
        -->  %s  np.array2string( arg, format )
        Other formats and non-ndarray args are left alone, formatted as usual.
        
        Notes:
        
        `printf( ... end= file= )` are passed on to the python `print()` function.
        
        Only formats `% [optional width . precision] d e f g` are implemented,
        not `%(varname)format` .
        
        %d truncates floats, e.g. 0.9 and -0.9 to 0; %.0f rounds, 0.9 to 1 .
        %g is the same as %.6g, 6 digits.
        %% is a single "%" character.
        
        The function `sprintf()` returns a long string. For example,
            title = sprintf( "%s  m %g  n %g  X %.3g",
                            __file__, m, n, X )
            print( title )
            ...
            pl.title( title )
        
        Module globals:
        _fmt = "%.3g"  # default for extra args
        _squeeze = np.squeeze  # (n,1) (1,n) -> (n,) print in 1 line not n
        
        See also:
        http://docs.scipy.org/doc/numpy/reference/generated/numpy.set_printoptions.html
        http://docs.python.org/2.7/library/stdtypes.html#string-formatting
        
        '''
        # http://stackoverflow.com/questions/2891790/pretty-printing-of-numpy-array
        
        
        #...............................................................................
        from __future__ import division, print_function
        import re
        import numpy as np
        
        __version__ = "2014-02-03 feb denis"
        
        _splitformat = re.compile( r'''(
            %
            (?<! %% )  # not %%
            -? [ \d . ]*  # optional width.precision
            \w
            )''', re.X )
            # ... %3.0f  ... %g  ... %-10s ...
            # -> ['...' '%3.0f' '...' '%g' '...' '%-10s' '...']
            # odd len, first or last may be ""
        
        _fmt = "%.3g"  # default for extra args
        _squeeze = np.squeeze  # (n,1) (1,n) -> (n,) print in 1 line not n
        
        #...............................................................................
        def printf( format, *args, **kwargs ):
            print( sprintf( format, *args ), **kwargs )  # end= file=
        
        printf.__doc__ = __doc__
        
        
        def sprintf( format, *args ):
            """ sprintf( "text %.3g text %4.1f ... %s ... ", numpy arrays or ... )
                %[defg] array -> np.array2string( formatter= )
            """
            args = list(args)
            if not isinstance( format, basestring ):
                args = [format] + args
                format = ""
        
            tf = _splitformat.split( format )  # [ text %e text %f ... ]
            nfmt = len(tf) // 2
            nargs = len(args)
            if nargs < nfmt:
                args += (nfmt - nargs) * ["?arg?"]
            elif nargs > nfmt:
                tf += (nargs - nfmt) * [_fmt, " "]  # default _fmt
        
            for j, arg in enumerate( args ):
                fmt = tf[ 2*j + 1 ]
                if arg is None \
                or isinstance( arg, basestring ) \
                or (hasattr( arg, "__iter__" ) and len(arg) == 0):
                    tf[ 2*j + 1 ] = "%s"  # %f -> %s, not error
                    continue
                args[j], isarray = _tonumpyarray(arg)
                if isarray  and fmt[-1] in "defgEFG":
                    tf[ 2*j + 1 ] = "%s"
                    fmtfunc = (lambda x: fmt % x)
                    formatter = dict( float_kind=fmtfunc, int=fmtfunc )
                    args[j] = np.array2string( args[j], formatter=formatter )
            try:
                return "".join(tf) % tuple(args)
            except TypeError:  # shouldn't happen
                print( "error: tf %s  types %s" % (tf, map( type, args )))
                raise
        
        
        def _tonumpyarray( a ):
            """ a, isarray = _tonumpyarray( a )
                ->  scalar, False
                    np.asanyarray(a), float or int
                    a, False
            """
            a = getattr( a, "value", a )  # cvxpy
            if np.isscalar(a):
                return a, False
            if hasattr( a, "__iter__" )  and len(a) == 0:
                return a, False
            try:
                # map .value ?
                a = np.asanyarray( a )
            except ValueError:
                return a, False
            if hasattr( a, "dtype" )  and a.dtype.kind in "fi":  # complex ?
                if callable( _squeeze ):
                    a = _squeeze( a )  # np.squeeze
                return a, True
            else:
                return a, False
        
        
        #...............................................................................
        if __name__ == "__main__":
            import sys
        
            n = 5
            seed = 0
                # run this.py n= ...  in sh or ipython
            for arg in sys.argv[1:]:
                exec( arg )
            np.set_printoptions( 1, threshold=4, edgeitems=2, linewidth=80, suppress=True )
            np.random.seed(seed)
        
            A = np.random.exponential( size=(n,n) ) ** 10
            x = A[0]
        
            printf( "x: %.3g  \nA: %.1f  \ns: %s  \nB: %s ",
                        x,         A,         "str",   A )
            printf( "x %%d: %d", x )
            printf( "x %%.0f: %.0f", x )
            printf( "x %%.1e: %.1e", x )
            printf( "x %%g: %g", x )
            printf( "x %%s uses np printoptions: %s", x )
        
            printf( "x with default _fmt: ", x )
            printf( "no args" )
            printf( "too few args: %g %g", x )
            printf( x )
            printf( x, x )
            printf( None )
            printf( "[]:", [] )
            printf( "[3]:", [3] )
            printf( np.array( [] ))
            printf( [[]] )  # squeeze
        

        【讨论】:

          【解决方案7】:

          这是我使用的,非常简单:

          print(np.vectorize("%.2f".__mod__)(sparse))
          

          【讨论】:

            【解决方案8】:

            很惊讶没有看到提到around 方法 - 意味着没有弄乱打印选项。

            import numpy as np
            
            x = np.random.random([5,5])
            print(np.around(x,decimals=3))
            
            Output:
            [[0.475 0.239 0.183 0.991 0.171]
             [0.231 0.188 0.235 0.335 0.049]
             [0.87  0.212 0.219 0.9   0.3  ]
             [0.628 0.791 0.409 0.5   0.319]
             [0.614 0.84  0.812 0.4   0.307]]
            

            【讨论】:

            • 但这确实意味着每次要打印数组时都要创建第二个副本,这可能会阻止某些用例。
            【解决方案9】:

            numpy 数组有 round(precision) 方法,它返回一个新的 numpy 数组,其中元素相应地四舍五入。

            import numpy as np
            
            x = np.random.random([5,5])
            print(x.round(3))
            

            【讨论】:

            • 在将数组传递给 matplotlib ylabel 时,这对我有用,谢谢
            【解决方案10】:

            我经常希望不同的列具有不同的格式。以下是我如何通过将我的 NumPy 数组(切片)转换为元组来使用多种格式打印一个简单的二维数组:

            import numpy as np
            dat = np.random.random((10,11))*100  # Array of random values between 0 and 100
            print(dat)                           # Lines get truncated and are hard to read
            for i in range(10):
                print((4*"%6.2f"+7*"%9.4f") % tuple(dat[i,:]))
            

            【讨论】:

              【解决方案11】:

              我发现在使用循环显示列表或数组时,通常的浮点格式 {:9.5f} 可以正常工作——抑制小值电子符号。但是当格式化程序在单个打印语句中有多个项目时,该格式有时无法抑制其电子符号。例如:

              import numpy as np
              np.set_printoptions(suppress=True)
              a3 = 4E-3
              a4 = 4E-4
              a5 = 4E-5
              a6 = 4E-6
              a7 = 4E-7
              a8 = 4E-8
              #--first, display separate numbers-----------
              print('Case 3:  a3, a4, a5:             {:9.5f}{:9.5f}{:9.5f}'.format(a3,a4,a5))
              print('Case 4:  a3, a4, a5, a6:         {:9.5f}{:9.5f}{:9.5f}{:9.5}'.format(a3,a4,a5,a6))
              print('Case 5:  a3, a4, a5, a6, a7:     {:9.5f}{:9.5f}{:9.5f}{:9.5}{:9.5f}'.format(a3,a4,a5,a6,a7))
              print('Case 6:  a3, a4, a5, a6, a7, a8: {:9.5f}{:9.5f}{:9.5f}{:9.5f}{:9.5}{:9.5f}'.format(a3,a4,a5,a6,a7,a8))
              #---second, display a list using a loop----------
              myList = [a3,a4,a5,a6,a7,a8]
              print('List 6:  a3, a4, a5, a6, a7, a8: ', end='')
              for x in myList: 
                  print('{:9.5f}'.format(x), end='')
              print()
              #---third, display a numpy array using a loop------------
              myArray = np.array(myList)
              print('Array 6: a3, a4, a5, a6, a7, a8: ', end='')
              for x in myArray:
                  print('{:9.5f}'.format(x), end='')
              print()
              

              我的结果显示了案例 4、5 和 6 中的错误:

              Case 3:  a3, a4, a5:               0.00400  0.00040  0.00004
              Case 4:  a3, a4, a5, a6:           0.00400  0.00040  0.00004    4e-06
              Case 5:  a3, a4, a5, a6, a7:       0.00400  0.00040  0.00004    4e-06  0.00000
              Case 6:  a3, a4, a5, a6, a7, a8:   0.00400  0.00040  0.00004  0.00000    4e-07  0.00000
              List 6:  a3, a4, a5, a6, a7, a8:   0.00400  0.00040  0.00004  0.00000  0.00000  0.00000
              Array 6: a3, a4, a5, a6, a7, a8:   0.00400  0.00040  0.00004  0.00000  0.00000  0.00000
              

              我对此没有任何解释,因此我总是使用循环来实现多个值的浮动输出。

              【讨论】:

                【解决方案12】:

                我用

                def np_print(array,fmt="10.5f"):
                    print (array.size*("{:"+fmt+"}")).format(*array)
                

                多维数组修改并不难。

                【讨论】:

                  【解决方案13】:

                  numpy.char.mod 也可能有用,具体取决于您的应用程序的详细信息,例如:numpy.char.mod('Value=%4.2f', numpy.arange(5, 10, 0.1)) 将返回一个字符串数组,其中包含元素“Value=5.00”、“Value=5.10”等(作为一个有点人为的例子) .

                  【讨论】:

                    【解决方案14】:

                    另一个选择是使用decimal 模块:

                    import numpy as np
                    from decimal import *
                    
                    arr = np.array([  56.83,  385.3 ,    6.65,  126.63,   85.76,  192.72,  112.81, 10.55])
                    arr2 = [str(Decimal(i).quantize(Decimal('.01'))) for i in arr]
                    
                    # ['56.83', '385.30', '6.65', '126.63', '85.76', '192.72', '112.81', '10.55']
                    

                    【讨论】:

                      猜你喜欢
                      • 2013-04-12
                      • 1970-01-01
                      • 1970-01-01
                      • 2019-02-28
                      • 1970-01-01
                      • 2011-09-29
                      • 2012-11-30
                      相关资源
                      最近更新 更多