Bagaimana cara mencetak numpy.array dengan cantik tanpa notasi ilmiah dan dengan presisi yang diberikan?

332

Saya ingin tahu, apakah ada cara untuk mencetak yang diformat numpy.arrays, misalnya dengan cara yang mirip dengan ini:

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

Jika saya ingin mencetak numpy.arrayfloat, ia mencetak beberapa desimal, seringkali dalam format 'ilmiah', yang agak sulit dibaca bahkan untuk array dimensi rendah. Namun, numpy.arraytampaknya harus dicetak sebagai string, yaitu dengan %s. Apakah ada solusi untuk ini?

camillio
sumber
diskusi ini juga mungkin menarik bagi mereka yang berakhir di sini melalui pencarian google.
Isi

Jawaban:

558

Anda dapat menggunakan set_printoptionsuntuk mengatur presisi 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]

Dan suppressmenekan penggunaan notasi ilmiah untuk jumlah kecil:

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

Lihat dokumen untuk set_printoptions untuk opsi lain.


Untuk menerapkan opsi cetak secara lokal , menggunakan NumPy 1.15.0 atau lebih baru, Anda dapat menggunakan manajer konteks numpy.printoptions . Misalnya, di dalam with-suite precision=3dan suppress=Truediatur:

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]

Tetapi di luar with-suiteopsi cetak kembali ke pengaturan default:

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

Jika Anda menggunakan NumPy versi sebelumnya, Anda dapat membuat sendiri pengelola konteks. Sebagai contoh,

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]

Untuk mencegah nol dilucuti dari ujung pelampung:

np.set_printoptionssekarang memiliki formatterparameter yang memungkinkan Anda menentukan fungsi format untuk setiap jenis.

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

yang mencetak

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

dari pada

[ 0.078  0.48   0.413  0.83   0.776  0.102  0.513  0.462  0.335  0.712]
unutbu
sumber
adakah cara untuk menerapkan pemformatan hanya untuk pernyataan cetak spesifik (sebagai lawan dari pengaturan format output umum yang digunakan oleh semua pernyataan cetak)?
bph
7
@Hiett: Tidak ada fungsi NumPy untuk mengatur opsi cetak hanya untuk satu print, tetapi Anda bisa menggunakan manajer konteks untuk membuat sesuatu yang serupa. Saya telah mengedit posting di atas untuk menunjukkan apa yang saya maksud.
unutbu
2
Anda np.set_printoptions(precision=3)menekan angka nol .. bagaimana Anda membuatnya ditampilkan seperti ini [ 0.078 0.480 0.413 0.830 0.776 0.102 0.513 0.462 0.335 0.712]?
Norfeldt
2
@Norfeldt: Saya telah menambahkan cara untuk melakukan ini di atas.
unutbu
1
Ini sangat bagus. Sebagai catatan tambahan, Anda juga dapat menggunakan set_printoptionsjika Anda menginginkan representasi string dan tidak harus digunakan print. Anda bisa memanggil __str__()instance array numpy dan Anda akan mendapatkan string yang diformat sesuai dengan opsi print yang Anda atur.
Jayesh
40

Anda bisa mendapatkan subset np.set_printoptionsfungsionalitas dari np.array_strperintah, yang hanya berlaku untuk satu pernyataan cetak.

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

Sebagai contoh:

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
sumber
37

Unutbu memberikan jawaban yang sangat lengkap (mereka juga mendapat +1 dari saya), tapi di sini ada alternatif 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']

Sebagai fungsi (menggunakan format()sintaks untuk memformat):

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

Pemakaian:

>>> 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 array dapat diakses dalam 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']
Caleb Hattingh
sumber
15

FYI Numpy 1.15 (tanggal rilis tertunda) akan menyertakan manajer konteks untuk pengaturan opsi cetak secara lokal . Ini berarti bahwa berikut ini akan bekerja sama dengan contoh yang sesuai dalam jawaban yang diterima (oleh unutbu dan Neil G) tanpa harus menulis manajer konteks Anda sendiri. Misalnya, menggunakan contoh mereka:

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
sumber
12

Permata yang membuatnya sangat mudah untuk mendapatkan hasil sebagai string (dalam versi numpy hari ini) disembunyikan dalam jawaban 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]'
hamogu
sumber
8

Bertahun-tahun kemudian, satu lagi di bawah. Tapi untuk penggunaan sehari-hari saya hanya

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
sumber
6

Dan inilah yang saya gunakan, dan itu sangat tidak rumit:

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

Terkejut tidak melihat aroundmetode yang disebutkan - berarti tidak mengotak dengan opsi cetak.

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]]
Nona Palmer
sumber
2

Saya sering ingin kolom yang berbeda memiliki format yang berbeda. Berikut adalah cara saya mencetak larik 2D sederhana menggunakan beberapa variasi dalam pemformatan dengan mengubah (irisan) larik NumPy saya menjadi 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,:]))
AstroFloyd
sumber
1

numpy.char.modmungkin juga berguna, tergantung pada detail aplikasi Anda misalnya: numpy.char.mod('Value=%4.2f', numpy.arange(5, 10, 0.1))akan mengembalikan array string dengan elemen "Value = 5.00", "Value = 5.10" dll. (sebagai contoh yang agak dibuat-buat).

jtniehof
sumber
1

Array numpy memiliki metode round(precision)yang mengembalikan array numpy baru dengan elemen dibulatkan sesuai.

import numpy as np

x = np.random.random([5,5])
print(x.round(3))
Turki
sumber
1
Ini bekerja untuk saya ketika meneruskan array ke matlotlib ylabel, terima kasih
Hans
1

Saya menemukan bahwa format float biasa {: 9.5f} berfungsi dengan baik - menekan notasi elektronik bernilai kecil - ketika menampilkan daftar atau array menggunakan loop. Tetapi format itu terkadang gagal menekan e-notasinya ketika seorang formatter memiliki beberapa item dalam satu pernyataan cetak. Sebagai contoh:

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

Hasil saya menunjukkan bug dalam kasus 4, 5, dan 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

Saya tidak punya penjelasan untuk ini, dan karena itu saya selalu menggunakan loop untuk keluaran mengambang dari beberapa nilai.

Mike Lampton
sumber
1

saya menggunakan

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

Tidak sulit untuk memodifikasinya untuk array multi dimensi.

albapa
sumber
0

Namun pilihan lain adalah menggunakan decimalmodul:

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
sumber