漂亮地打印一个NumPy数组,没有科学符号,并具有给定的精度

我如何打印格式化的NumPy数组以类似于这样的方式:

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

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

555840 次浏览

使用numpy.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. ]

在本地应用打印选项,使用NumPy 1.15.0或更高版本,你可以使用numpy.printoptions上下文管理器。 例如,在with-suite中,precision=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的早期版本,您可以创建上下文管理器 你自己。例如,< / p >
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]

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']

几年后,下面又有一个。但对于日常使用,我只是

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

这是我用的,它很简单:

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

numpy.char.mod也可能有用,这取决于你的应用程序的细节,例如:numpy.char.mod('Value=%4.2f', numpy.arange(5, 10, 0.1))将返回一个包含元素“Value=5.00”,“Value=5.10”等的字符串数组(作为一个有点做作的例子)。

使用np.array_str仅对单个打印语句应用格式化。它提供了np.set_printoptions功能的一个子集。

例如:

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. ]]

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

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,:]))
gem使它太容易获得一个字符串的结果(在今天的numpy版本中)隐藏在denis answer中: np.array2string < / p >
>>> 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]'

还有一个选项是使用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']

很惊讶没有看到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]]

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

import numpy as np


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

供参考,Numpy 1.15(发布日期待定)将包括一个上下文管理器,用于在本地设置打印选项。这意味着下面的工作将与公认的答案中相应的示例相同(由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]

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

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

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

我使用

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

对多维数组进行修改并不难。