1

(Windows 7,Python 3.4.5 |Anaconda 2.2.0 (64-bit)| (default, Jul 5 2016, 14:53:07) [MSC v.1600 64 bit (AMD64)])

I was trying to neatly print some data by using np.set_printoptions(precision= and it seems to be ignored. Why?

import numpy as np
np.set_printoptions(precision=4)

a=[[1,15.02],
[2,14.38],
[3,14.60]]

b=np.array(a)
print(b)
at=b.T
l=list(zip(at[0],at[1]))
print(l)

Output:

[[  1.    15.02]
 [  2.    14.38]
 [  3.    14.6 ]]
[(1.0, 15.02), (2.0, 14.380000000000001), (3.0, 14.6)]
Krischu
  • 1,024
  • 2
  • 15
  • 35
  • Because it's not an np-array anymore and numpy's printing-mechanic is not used? – sascha Dec 04 '17 at 16:43
  • And which printing mechanic should be applied in this case? – Krischu Dec 04 '17 at 16:59
  • You need to define your own i'm afraid, based on string-formatting like [this](https://stackoverflow.com/a/1567630/2320035), depending on your exact use-case. – sascha Dec 04 '17 at 17:04

2 Answers2

1

A problem of float :

In [118]:ref=decimal.Decimal('14.380000000000000000000000000000000000000000000000')

In [119]: decimal.Decimal(14.38)
Out[119]: Decimal('14.3800000000000007815970093361102044582366943359375')

In [120]: decimal.Decimal(14.38)-ref
Out[120]: Decimal('7.815970093361102044582366943E-16')

In [121]: decimal.Decimal(14.38-2**-50)-ref
Out[121]: Decimal('-9.947598300641402602195739746E-16')

This show that 14.380000000000001 is the best float64 approximation of 14.38 .

to workaround this fact, you can downgrade in np.float32 :

In [140]:tuple(zip(*np.array(a).T.astype(np.float32)))
Out[140]: ((1.0, 15.02), (2.0, 14.38), (3.0, 14.6))
B. M.
  • 18,243
  • 2
  • 35
  • 54
1
In [34]: a
Out[34]: [[1, 15.02], [2, 14.38], [3, 14.6]]
In [35]: b=np.array(a, dtype=float).T
In [36]: b
Out[36]: 
array([[  1.  ,   2.  ,   3.  ],
       [ 15.02,  14.38,  14.6 ]])
In [37]: list(zip(*b))
Out[37]: [(1.0, 15.02), (2.0, 14.380000000000001), (3.0, 14.6)]

However if I first past b through tolist:

In [38]: list(zip(*b.tolist()))
Out[38]: [(1.0, 15.02), (2.0, 14.38), (3.0, 14.6)]

In the first case the elements of the tuple still have np.float64 wrapper, while tolist extracts them all to native Python numbers:

In [39]: type(list(zip(*b))[1][1])
Out[39]: numpy.float64
In [40]: type(list(zip(*b.tolist()))[1][1])
Out[40]: float

item is another way of extracting the native number:

In [41]: list(zip(*b))[1][1]
Out[41]: 14.380000000000001
In [42]: list(zip(*b))[1][1].item()
Out[42]: 14.38

I can't say why the setprintoptions doesn't apply in the case of np.float64, but does with np.array.

As a general rule, it is better to use tolist() if you want to convert an array, and all its values, into a native Python list. Operations like list and zip aren't enough. They iterate on the first dimension of the array, but don't recursively convert the elements:

Partial conversion(s):

In [43]: list(b)
Out[43]: [array([ 1.,  2.,  3.]), array([ 15.02,  14.38,  14.6 ])]
In [44]: list(b[1])
Out[44]: [15.02, 14.380000000000001, 14.6]

Full conversion:

In [45]: b.tolist()
Out[45]: [[1.0, 2.0, 3.0], [15.02, 14.38, 14.6]]

Apparently the formatter for float64 shows all precision, regardless of the set_printoptions values:

In [58]: 14.380000000000001
Out[58]: 14.38
In [59]: np.array(14.380000000000001)
Out[59]: array(14.38)
In [60]: np.float64(14.380000000000001)
Out[60]: 14.380000000000001
In [61]: np.float32(14.380000000000001)
Out[61]: 14.38

An np.float64(...) object is, in many ways like a single item array, but different in subtle ways. Usually though we don't create such an object directly.

hpaulj
  • 221,503
  • 14
  • 230
  • 353