Wie kann man ein numpy.array ohne wissenschaftliche Notation und mit vorgegebener Präzision hübsch drucken?

331

Ich bin gespannt, ob es eine Möglichkeit gibt, formatiert zu drucken numpy.arrays , z. B. auf ähnliche Weise:

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

Wenn ich numpy.arrayFloats drucken möchte, werden mehrere Dezimalstellen gedruckt , häufig im "wissenschaftlichen" Format, das selbst für niedrigdimensionale Arrays schwer zu lesen ist. Muss aber numpy.arrayanscheinend als String gedruckt werden, dh mit %s. Gibt es dafür eine Lösung?

Camillio
quelle
Diese Diskussion könnte auch diejenigen interessieren, die hier über die Google-Suche landen.
Foad

Antworten:

557

Sie können verwenden set_printoptions, um die Genauigkeit der Ausgabe festzulegen:

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]

Und suppressunterdrückt die Verwendung der wissenschaftlichen Notation für kleine Zahlen:

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

Weitere Optionen finden Sie in den Dokumenten zu set_printoptions .


Um Druckoptionen lokal mit NumPy 1.15.0 oder höher anzuwenden, können Sie den Kontextmanager numpy.printoptions verwenden . Zum Beispiel sind innerhalb der with-suite precision=3und suppress=Truegesetzt:

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]

Außerhalb der with-suiteDruckoptionen werden jedoch die Standardeinstellungen wiederhergestellt:

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

Wenn Sie eine frühere Version von NumPy verwenden, können Sie den Kontextmanager selbst erstellen. Zum Beispiel,

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]

So verhindern Sie, dass Nullen vom Ende der Floats entfernt werden:

np.set_printoptionshat jetzt einen formatterParameter, mit dem Sie eine Formatfunktion für jeden Typ angeben können.

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

welche druckt

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

anstatt

[ 0.078  0.48   0.413  0.83   0.776  0.102  0.513  0.462  0.335  0.712]
unutbu
quelle
Gibt es eine Möglichkeit, die Formatierung nur auf die bestimmte Druckanweisung anzuwenden (im Gegensatz zum Festlegen eines allgemeinen Ausgabeformats, das von allen Druckanweisungen verwendet wird )?
bph
7
@Hiett: Es gibt keine NumPy-Funktion zum Festlegen von Druckoptionen für nur eine print, aber Sie können einen Kontextmanager verwenden, um etwas Ähnliches zu erstellen . Ich habe den obigen Beitrag bearbeitet, um zu zeigen, was ich meine.
Unutbu
2
Sie np.set_printoptions(precision=3)unterdrücken die Endnullen. Wie bringen Sie sie dazu, so angezeigt zu werden [ 0.078 0.480 0.413 0.830 0.776 0.102 0.513 0.462 0.335 0.712]?
Norfeldt
2
@Norfeldt: Ich habe oben eine Möglichkeit hinzugefügt, dies zu tun.
Unutbu
1
Das funktioniert super. Als Randnotiz können Sie auch verwenden, set_printoptionswenn Sie eine Zeichenfolgendarstellung möchten und nicht unbedingt verwenden möchten print. Sie können einfach __str__()die numpy-Array-Instanz aufrufen und erhalten die formatierte Zeichenfolge gemäß den von Ihnen festgelegten Druckoptionen.
Jayesh
40

Eine Teilmenge der np.set_printoptionsFunktionalität erhalten Sie von dernp.array_str Befehl abrufen, der nur für eine einzelne Druckanweisung gilt.

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

Zum Beispiel:

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. ]]
Daniel Golden
quelle
37

Unutbu gab eine wirklich vollständige Antwort (sie haben auch eine +1 von mir bekommen), aber hier ist eine 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']

Als Funktion (unter Verwendung der format()Syntax zur Formatierung):

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

Verwendungszweck:

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

Auf den Index des Arrays kann in der Formatzeichenfolge zugegriffen werden:

>>> 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']
Caleb Hattingh
quelle
15

FYI Numpy 1.15 (Veröffentlichungsdatum steht noch aus) enthält einen Kontextmanager zum lokalen Festlegen von Druckoptionen . Dies bedeutet, dass das Folgende genauso funktioniert wie das entsprechende Beispiel in der akzeptierten Antwort (von unutbu und Neil G), ohne dass Sie Ihren eigenen Kontextmanager schreiben müssen. ZB am Beispiel:

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]
Justin Lanfranchi
quelle
12

Das Juwel, das es allzu einfach macht, das Ergebnis als Zeichenfolge zu erhalten (in den heutigen Numpy-Versionen), ist in der Antwort von denis verborgen: 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]'
Hamogu
quelle
8

Jahre später ist ein anderer unten. Aber für den täglichen Gebrauch habe ich nur

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
denis
quelle
6

Und hier ist, was ich benutze, und es ist ziemlich unkompliziert:

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

War überrascht, die arounderwähnte Methode nicht zu sehen - bedeutet kein Durcheinander mit den Druckoptionen.

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]]
Miss Palmer
quelle
2

Ich möchte oft, dass verschiedene Spalten unterschiedliche Formate haben. So drucke ich ein einfaches 2D-Array unter Verwendung einer Vielzahl von Formatierungen, indem ich mein NumPy-Array in ein Tupel konvertiere:

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,:]))
AstroFloyd
quelle
1

numpy.char.modkann auch nützlich sein, abhängig von den Details Ihrer Anwendung, z. B.: numpy.char.mod('Value=%4.2f', numpy.arange(5, 10, 0.1))Gibt ein String-Array mit den Elementen "Wert = 5,00", "Wert = 5,10" usw. zurück (als etwas erfundenes Beispiel).

jtniehof
quelle
1

Die Numpy-Arrays haben die Methode, round(precision)die ein neues Numpy-Array mit entsprechend gerundeten Elementen zurückgibt.

import numpy as np

x = np.random.random([5,5])
print(x.round(3))
Ștefan
quelle
1
Dies funktionierte für mich, als ich das Array an ein Matplotlib-Ylabel weitergab, danke
Hans
1

Ich finde, dass das übliche Float-Format {: 9.5f} ordnungsgemäß funktioniert - das Unterdrücken von E-Notationen mit kleinen Werten -, wenn eine Liste oder ein Array mithilfe einer Schleife angezeigt wird. Dieses Format unterdrückt jedoch manchmal nicht seine E-Notation, wenn ein Formatierer mehrere Elemente in einer einzigen Druckanweisung enthält. Zum Beispiel:

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()

Meine Ergebnisse zeigen den Fehler in den Fällen 4, 5 und 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

Ich habe keine Erklärung dafür und verwende daher immer eine Schleife für die Floating-Ausgabe mehrerer Werte.

Mike Lampton
quelle
1

ich benutze

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

Es ist nicht schwierig, es für mehrdimensionale Arrays zu modifizieren.

Albapa
quelle
0

Eine weitere Option ist die Verwendung des decimalModuls:

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