How do I print formatted NumPy arrays in a way similar to this:
x = 1.23456
print('%.3f' % x)
If I want to print the numpy.ndarray
of floats, it prints several decimals, often in 'scientific' format, which is rather hard to read even for low-dimensional arrays. However, numpy.ndarray
apparently has to be printed 开发者_运维技巧as a string, i.e., with %s
. Is there a solution for this?
Use numpy.set_printoptions
to set the precision of the output:
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]
And suppress
suppresses the use of scientific notation for small numbers:
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. ]
To apply print options locally, using NumPy 1.15.0 or later, you could use the numpy.printoptions
context manager.
For example, inside the with-suite
precision=3
and suppress=True
are set:
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]
But outside the with-suite
the print options are back to default settings:
print(x)
# [ 0.07334334 0.46132615 0.68935231 0.75379645 0.62424021 0.90115836
# 0.04879837 0.58207504 0.55694118 0.34768638]
If you are using an earlier version of NumPy, you can create the context manager yourself. For example,
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]
To prevent zeros from being stripped from the end of floats:
np.set_printoptions
now has a formatter
parameter which allows you to specify a format function for each type.
np.set_printoptions(formatter={'float': '{: 0.3f}'.format})
print(x)
which prints
[ 0.078 0.480 0.413 0.830 0.776 0.102 0.513 0.462 0.335 0.712]
instead of
[ 0.078 0.48 0.413 0.83 0.776 0.102 0.513 0.462 0.335 0.712]
Use np.array_str
to apply formatting to only a single print statement. It gives a subset of np.set_printoptions
's functionality.
For example:
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. ]]
Unutbu gave a really complete answer (they got a +1 from me too), but here is a lo-tech alternative:
>>> 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']
As a function (using the format()
syntax for formatting):
def ndprint(a, format_string ='{0:.2f}'):
print [format_string.format(v,i) for i,v in enumerate(a)]
Usage:
>>> 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']
The index of the array is accessible in the format string:
>>> 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']
FYI Numpy 1.15 (release date pending) will include a context manager for setting print options locally. This means that the following will work the same as the corresponding example in the accepted answer (by unutbu and Neil G) without having to write your own context manager. E.g., using their example:
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]
The gem that makes it all too easy to obtain the result as a string (in today's numpy versions) is hidden in denis answer:
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]'
Years later, another one is below. But for everyday use I just
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
The numpy arrays have the method round(precision)
which returns a new numpy array with elements rounded accordingly.
import numpy as np
x = np.random.random([5,5])
print(x.round(3))
And here is what I use, and it's pretty uncomplicated:
print(np.vectorize("%.2f".__mod__)(sparse))
Was surprised to not see around
method mentioned - means no messing with print options.
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]]
I often want different columns to have different formats. Here is how I print a simple 2D array using some variety in the formatting by converting (slices of) my NumPy array to a tuple:
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,:]))
I find that the usual float format {:9.5f} works properly -- suppressing small-value e-notations -- when displaying a list or an array using a loop. But that format sometimes fails to suppress its e-notation when a formatter has several items in a single print statement. For example:
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()
My results show the bug in cases 4, 5, and 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
I have no explanation for this, and therefore I always use a loop for floating output of multiple values.
I use
def np_print(array,fmt="10.5f"):
print (array.size*("{:"+fmt+"}")).format(*array)
It's not difficult to modify it for multi-dimensional arrays.
numpy.char.mod
may also be useful, depending on the details of your application e.g.:numpy.char.mod('Value=%4.2f', numpy.arange(5, 10, 0.1))
will return a string array with elements "Value=5.00", "Value=5.10" etc. (as a somewhat contrived example).
Yet another option is to use the decimal
module:
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']
精彩评论