Jak ładnie wydrukować tablicę numpy.array bez notacji naukowej i z określoną precyzją?

331

Jestem ciekawy, czy jest jakiś sposób wydrukowania sformatowanego numpy.arrays, np. W sposób podobny do tego:

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

Jeśli chcę wydrukować numpy.arrayliczby zmiennoprzecinkowe, drukuje kilka miejsc po przecinku, często w formacie „naukowym”, co jest raczej trudne do odczytania, nawet w przypadku tablic mało wymiarowych. Jednak numpy.arraynajwyraźniej musi być wydrukowany jako ciąg, tzn %s. Z. Czy jest na to jakieś rozwiązanie?

Camillio
źródło
ta dyskusja może również zainteresować tych, którzy znajdą się tutaj za pośrednictwem wyszukiwarki Google.
Foad

Odpowiedzi:

557

Możesz użyć, set_printoptionsaby ustawić dokładność wyjścia:

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]

I suppresswyklucza stosowanie notacji naukowej dla małych liczb:

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

Zobacz dokumentację set_printoptions dla innych opcji.


Aby zastosować opcje drukowania lokalnie , używając NumPy 1.15.0 lub nowszego, możesz użyć menedżera kontekstu numpy.printoptions . Na przykład wewnątrz with-suite precision=3i suppress=Truesą ustawione:

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]

Ale poza with-suiteopcjami drukowania powracają do ustawień domyślnych:

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

Jeśli używasz wcześniejszej wersji NumPy, możesz samodzielnie utworzyć menedżera kontekstu. Na przykład,

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]

Aby zapobiec usuwaniu zer z końca liczb zmiennoprzecinkowych:

np.set_printoptionsma teraz formatterparametr, który pozwala określić funkcję formatu dla każdego typu.

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

który drukuje

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

zamiast

[ 0.078  0.48   0.413  0.83   0.776  0.102  0.513  0.462  0.335  0.712]
unutbu
źródło
czy istnieje sposób zastosowania formatowania tylko do określonej instrukcji print (w przeciwieństwie do ustawienia ogólnego formatu wyjściowego używanego przez wszystkie instrukcje print)?
bph
7
@Hiett: Nie ma funkcji NumPy, która ustawiałaby opcje drukowania tylko dla jednej print, ale można użyć menedżera kontekstu, aby zrobić coś podobnego. Zredagowałem powyższy post, aby pokazać, co mam na myśli.
unutbu
2
twoje np.set_printoptions(precision=3)pomijanie zer końcowych ... jak sprawić, by wyświetlały się w ten sposób [ 0.078 0.480 0.413 0.830 0.776 0.102 0.513 0.462 0.335 0.712]?
Norfeldt
2
@Norfeldt: Dodałem sposób, aby to zrobić powyżej.
unutbu
1
To działa świetnie. Na marginesie, możesz również użyć, set_printoptionsjeśli chcesz reprezentację ciągu i niekoniecznie użyj print. Możesz po prostu wywołać __str__()instancję tablicy numpy, a otrzymasz sformatowany ciąg znaków zgodnie z ustawionymi opcjami drukowania.
Jayesh
40

Można uzyskać podzbiór np.set_printoptionsfunkcji z np.array_strpolecenia, które dotyczy tylko pojedynczej instrukcji print.

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

Na przykład:

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
źródło
37

Unutbu dał naprawdę kompletną odpowiedź (oni też dostali ode mnie +1), ale oto alternatywa lo-tech:

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

Jako funkcja (przy użyciu format()składni do formatowania):

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

Stosowanie:

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

Indeks tablicy jest dostępny w ciągu formatu:

>>> 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
źródło
15

FYI Numpy 1.15 (data wydania w toku) będzie zawierać menedżera kontekstu do ustawiania opcji drukowania lokalnie . Oznacza to, że poniższe będą działać tak samo jak odpowiadający przykład w zaakceptowanej odpowiedzi (przez unutbu i Neil G) bez konieczności pisania własnego menedżera kontekstu. Na przykład na podstawie ich przykładu:

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
źródło
12

Klejnot, który sprawia, że ​​zbyt łatwo jest uzyskać wynik jako ciąg (w dzisiejszych wersjach numpy), jest ukryty w denis odpowiedź: 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
źródło
8

Wiele lat później kolejny jest poniżej. Ale po prostu do codziennego użytku

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
źródło
6

A oto, czego używam i jest to dość nieskomplikowane:

print(np.vectorize("%.2f".__mod__)(sparse))
utdemir
źródło
3

Był zaskoczony, gdy nie aroundwspomniano o metodzie - oznacza to, że nie ma bałaganu przy opcji drukowania.

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]]
Panna Palmer
źródło
2

Często chcę, aby różne kolumny miały różne formaty. Oto, w jaki sposób drukuję prostą tablicę 2D, używając pewnej różnorodności w formatowaniu, konwertując (plastry) mojej tablicy NumPy na krotkę:

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
źródło
1

numpy.char.modmoże być również przydatny, w zależności od szczegółów twojej aplikacji, np .: numpy.char.mod('Value=%4.2f', numpy.arange(5, 10, 0.1))zwróci tablicę ciągów z elementami „Wartość = 5,00”, „Wartość = 5.10” itd. (jako nieco wymyślony przykład).

jtniehof
źródło
1

Tablice numpy mają metodę, round(precision)która zwraca nową tablicę numpy z odpowiednio zaokrąglonymi elementami.

import numpy as np

x = np.random.random([5,5])
print(x.round(3))
Eftefan
źródło
1
Działa to dla mnie, gdy przekazałem tablicę do ylabel Matplotlib, dzięki
Hans
1

Uważam, że zwykły format zmiennoprzecinkowy {: 9.5f} działa poprawnie - tłumiąc e-notacje o małej wartości - podczas wyświetlania listy lub tablicy za pomocą pętli. Ale ten format czasami nie tłumi swojej notacji elektronicznej, gdy formatyzator ma kilka pozycji w pojedynczej instrukcji drukowania. Na przykład:

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

Moje wyniki pokazują błąd w przypadkach 4, 5 i 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

Nie mam na to wytłumaczenia, dlatego zawsze używam pętli do zmiennoprzecinkowego generowania wielu wartości.

Mike Lampton
źródło
1

używam

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

Nie jest trudno zmodyfikować go dla tablic wielowymiarowych.

albapa
źródło
0

Jeszcze inną opcją jest użycie decimalmodułu:

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
źródło