Làm thế nào để in đẹp một numpy.array mà không cần ký hiệu khoa học và với độ chính xác nhất định?


331

Tôi tò mò, liệu có cách nào để in định dạng numpy.arrays, ví dụ, theo cách tương tự như sau:

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

Nếu tôi muốn in numpy.arrayphao, nó sẽ in một số số thập phân, thường ở định dạng 'khoa học', khá khó đọc ngay cả đối với các mảng có chiều thấp. Tuy nhiên, numpy.arrayrõ ràng phải được in dưới dạng một chuỗi, tức là với %s. đó có phải là cách giải quyết?


cuộc thảo luận này cũng có thể thu hút những người kết thúc ở đây thông qua tìm kiếm google.
Foad

Câu trả lời:


557

Bạn có thể sử dụng set_printoptionsđể đặt độ chính xác của đầu ra:

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]

suppressngăn chặn việc sử dụng ký hiệu khoa học cho số lượng nhỏ:

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

Xem tài liệu cho set_printoptions cho các tùy chọn khác.


Để áp dụng các tùy chọn in cục bộ , sử dụng NumPy 1.15.0 trở lên, bạn có thể sử dụng trình quản lý bối cảnh numpy.printoptions . Ví dụ: bên trong with-suite precision=3suppress=Trueđược đặt:

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]

Nhưng bên ngoài các with-suitetùy chọn in được quay lại cài đặt mặc định:

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

Nếu bạn đang sử dụng phiên bản NumPy trước đó, bạn có thể tự tạo trình quản lý bối cảnh. Ví dụ,

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]

Để ngăn không cho số không bị tước khỏi phần cuối của phao:

np.set_printoptionsbây giờ có một formattertham số cho phép bạn chỉ định một chức năng định dạng cho từng loại.

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

mà in

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

thay vì

[ 0.078  0.48   0.413  0.83   0.776  0.102  0.513  0.462  0.335  0.712]

Có cách nào để áp dụng định dạng cho chỉ câu lệnh in cụ thể (trái ngược với việc đặt định dạng đầu ra chung được sử dụng bởi tất cả các câu lệnh in) không?
bph

7
@Hiett: Không có chức năng NumPy để đặt tùy chọn in cho chỉ một print, nhưng bạn có thể sử dụng trình quản lý bối cảnh để tạo một cái gì đó tương tự. Tôi đã chỉnh sửa bài viết ở trên để hiển thị những gì tôi muốn nói.
unutbu

2
np.set_printoptions(precision=3)đàn áp của bạn các số không kết thúc .. làm thế nào để bạn hiển thị chúng như thế này [ 0.078 0.480 0.413 0.830 0.776 0.102 0.513 0.462 0.335 0.712]?
Norfeldt

2
@Norfeldt: Tôi đã thêm một cách để làm điều này ở trên.
unutbu

1
Điều này làm việc tuyệt vời. Là một lưu ý phụ, bạn cũng có thể sử dụng set_printoptionsnếu bạn muốn biểu diễn chuỗi và không nhất thiết phải sử dụng print. Bạn chỉ có thể gọi __str__()ví dụ mảng numpy và bạn sẽ nhận được chuỗi được định dạng theo bản in bạn đặt.
Jayesh

40

Bạn có thể nhận được một tập hợp con của np.set_printoptionschức năng từ np.array_strlệnh, chỉ áp dụng cho một câu lệnh in duy nhất.

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

Ví dụ:

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

37

Unutbu đã đưa ra một câu trả lời thực sự đầy đủ (họ cũng nhận được +1 từ tôi), nhưng đây là một thay thế 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']

Là một hàm (sử dụng format()cú pháp để định dạng):

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

Sử dụng:

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

Chỉ mục của mảng có thể truy cập trong chuỗi định dạng:

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

15

FYI Numpy 1.15 (ngày phát hành đang chờ xử lý) sẽ bao gồm trình quản lý bối cảnh để đặt tùy chọn in cục bộ . Điều này có nghĩa là những điều sau đây sẽ hoạt động giống như ví dụ tương ứng trong câu trả lời được chấp nhận (bởi unutbu và Neil G) mà không phải viết trình quản lý bối cảnh của riêng bạn. Ví dụ, sử dụng ví dụ của họ:

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]

12

Viên ngọc làm cho tất cả quá dễ dàng để có được kết quả dưới dạng chuỗi (trong các phiên bản numpy ngày nay) được ẩn trong câu trả lời 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]'

8

Nhiều năm sau, một cái khác ở dưới. Nhưng để sử dụng hàng ngày tôi chỉ

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

6

Và đây là những gì tôi sử dụng, và nó không phức tạp:

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

3

Thật ngạc nhiên khi không thấy aroundphương pháp được đề cập - có nghĩa là không gây rối với các tùy chọn in.

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

2

Tôi thường muốn các cột khác nhau có định dạng khác nhau. Đây là cách tôi in một mảng 2D đơn giản bằng cách sử dụng một số định dạng bằng cách chuyển đổi (các lát) mảng NumPy của tôi thành một 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,:]))

1

numpy.char.modcũng có thể hữu ích, tùy thuộc vào chi tiết của ứng dụng của bạn, ví dụ: numpy.char.mod('Value=%4.2f', numpy.arange(5, 10, 0.1))sẽ trả về một chuỗi chuỗi với các phần tử "Giá trị = 5,00", "Giá trị = 5,10", v.v. (như một ví dụ hơi khó hiểu).


1

Các mảng numpy có phương thức round(precision)trả về một mảng numpy mới với các phần tử được làm tròn tương ứng.

import numpy as np

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

1
Điều này làm việc cho tôi khi chuyển mảng cho một nhãn hiệu matplotlib, cảm ơn
Hans

1

Tôi thấy rằng định dạng float thông thường {: 9.5f} hoạt động chính xác - loại bỏ các ký hiệu điện tử giá trị nhỏ - khi hiển thị danh sách hoặc một mảng bằng vòng lặp. Nhưng định dạng đó đôi khi không thể loại bỏ ký hiệu điện tử của nó khi một trình định dạng có một vài mục trong một câu lệnh in. Ví dụ:

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

Kết quả của tôi cho thấy lỗi trong các trường hợp 4, 5 và 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

Tôi không có lời giải thích cho điều này, và do đó tôi luôn sử dụng một vòng lặp cho đầu ra nổi của nhiều giá trị.


1

tôi sử dụng

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

Không khó để sửa đổi nó cho mảng đa chiều.


0

Một tùy chọn khác là sử dụng decimalmô-đun:

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']
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.