-2

Follow with me for a second:

a = np.zeros((4, 4, 3), 'int')  

for n in range(4):
    for m in range(4):
        a[n, m] = n + m

Then we print(a.shape) and get (4, 4, 3)

Finally, we print(a)

[[[0 0 0]
  [1 1 1]
  [2 2 2]
  [3 3 3]]

 [[1 1 1]
  [2 2 2]
  [3 3 3]
  [4 4 4]]

 [[2 2 2]
  [3 3 3]
  [4 4 4]
  [5 5 5]]

 [[3 3 3]
  [4 4 4]
  [5 5 5]
  [6 6 6]]]

This looks confusing. What is going on?

Let's reformat this by hand by pasting into Sublime and rearranging:

[

  [     [0 0 0]    [1 1 1]    [2 2 2]    [3 3 3]     ]

  [     [1 1 1]    [2 2 2]    [3 3 3]    [4 4 4]     ]

  [     [2 2 2]    [3 3 3]    [4 4 4]    [5 5 5]     ]

  [     [3 3 3]    [4 4 4]    [5 5 5]    [6 6 6]     ]

]

First annoying thing to notice, is that the outermost [ ] should be IGNORED.

As in:

[  # <- get rid of this

  [     [0 0 0]    [1 1 1]    [2 2 2]    [3 3 3]     ]

  [     [1 1 1]    [2 2 2]    [3 3 3]    [4 4 4]     ]

  [     [2 2 2]    [3 3 3]    [4 4 4]    [5 5 5]     ]

  [     [3 3 3]    [4 4 4]    [5 5 5]    [6 6 6]      ]

] # <- get rid of this

QUESTION:

Why did the printout give me this? I didn't specify the shape to be (1, 4, 4, 3), but looking at it clearly, that's what it's showing me. Am I right to consider this confusing and unnecessary? Sure, it's ONE array and maybe deserved to be presented as such but this is not helpful when it comes time to read the output of the array on the computer screen.

Second thing:

Let me just run thru these dimensions, one at a time, in my head and by hand. Again, please bear with me.

First axis / dimension / index, which is (4, ): 4 containers

enter image description here

Second axis / dimension / index, which is ( , 4, ):: 4 containers nested within the prior dimension's containers:

enter image description here

Third axis / dimension / index, which is ( , , 3): 3 containers nested within the prior dimension's containers:

enter image description here

There are numbers in this innermost container of containers:

enter image description here

AND BOOM. Thanks for reading this far. But there was a setup / trick up there when I wrote '3 containers nested'...

QUESTION Why isn't the final above image correct? Because what python shows me instead is this:

enter image description here

What happened to the innermost brackets?

It's like a prank that numpy is pulling on us -- "You eyes need to focus on [ ] for the first two dimensions...but after that, you need to forget about those brackets and instead now you are looking at some datum instead of a container."

My question is also a proposal that numpy's printouts are changed. This feels inconsistent and I just don't see the reason for it. I'm hoping someone can make a good argument on why both of these inconsistencies are actually consistent.

Monica Heddneck
  • 2,973
  • 10
  • 55
  • 89
  • 2
    I'm voting to close this question because it doesn't look like the Stack Overflow "ask question" -> "get answer" -> "done" model is working here. We're getting extended discussions in the comments, which aren't meant for that, and while the posted answers are all correct, none of them seem to be clearing up the questioner's confusion. It looks like this would work better in a chat room or on some discussion forum. – user2357112 May 10 '18 at 23:15

3 Answers3

1
In [73]: a = np.zeros((4, 4, 3), 'int')  
    ...: 
    ...: for n in range(4):
    ...:     for m in range(4):
    ...:         a[n, m] = n + m
    ...:         
In [74]: a.shape
Out[74]: (4, 4, 3)

The display of a is perfectly consistent with the equivalent nested list. The grouping of lines differs, but the number of square brackets is the same:

In [75]: a
Out[75]: 
array([[[0, 0, 0],
        [1, 1, 1],
        [2, 2, 2],
        [3, 3, 3]],

       [[1, 1, 1],
        [2, 2, 2],
        [3, 3, 3],
        [4, 4, 4]],

       [[2, 2, 2],
        [3, 3, 3],
        [4, 4, 4],
        [5, 5, 5]],

       [[3, 3, 3],
        [4, 4, 4],
        [5, 5, 5],
        [6, 6, 6]]])

That's 4 4x3 blocks of numbers.

In [76]: a.tolist()
Out[76]: 
[[[0, 0, 0], [1, 1, 1], [2, 2, 2], [3, 3, 3]],
 [[1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4]],
 [[2, 2, 2], [3, 3, 3], [4, 4, 4], [5, 5, 5]],
 [[3, 3, 3], [4, 4, 4], [5, 5, 5], [6, 6, 6]]]

Out[75] is the repr of the array; the str is:

In [77]: print(a)
[[[0 0 0]
  [1 1 1]
  [2 2 2]
  [3 3 3]]

 [[1 1 1]
  [2 2 2]
  [3 3 3]
  [4 4 4]]

 [[2 2 2]
  [3 3 3]
  [4 4 4]
  [5 5 5]]

 [[3 3 3]
  [4 4 4]
  [5 5 5]
  [6 6 6]]]

Maybe things will be clearer if I display one 'block' of the array:

In [78]: print(a[0,...])
[[0 0 0]
 [1 1 1]
 [2 2 2]
 [3 3 3]]
In [79]: print(a[0,...].tolist())
[[0, 0, 0], [1, 1, 1], [2, 2, 2], [3, 3, 3]]

This is the first block of [77] minus the first [.


A 1d array is displayed as:

In [80]: a[0,0,:].shape
Out[80]: (3,)
In [81]: a[0,0,:]
Out[81]: array([0, 0, 0])

I could add a dimension to that 1d array, making a 'column vector':

In [82]: a[0,0,:][:,None]
Out[82]: 
array([[0],
       [0],
       [0]])
In [83]: _.shape
Out[83]: (3, 1)

Notice that 2nd 1 dimension. [0] displays a 1d array, not an element of an array.


You write:

First axis / dimension / index, which is (4, ): 4 containers

But what contains those containers - an array or list. That's what the outer set of [] denotes. Using some sort of bracket to denote the outer container is consistent through out Python, whether it be a list, a tuple or a dictionary.

Third axis / dimension / index, which is ( , , 3): 3 containers

No, the third axis is displayed a 3 numbers, not containers. Just like a 3 element list of number is displayed as [1,2,3].

Part of your problem with the missing inner set of [] is that you have ignored the outer set. I must stress, the the numpy display is consistent with Python practice for other containers such as lists, tuples and dictionaries.

hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • Thank you for the answer...but I do understand the structure of the array completely. I just don't understand why if the 1st and 2nd axes are denoted their beginning and end by having square brackets, why doesn't the 3rd axis have them as well, ala `[ [ [0] [0] [0] ] . . ` – Monica Heddneck May 10 '18 at 21:55
  • Because that would denote an added size 1 dimension, a (4,4,3,1) shape. There is one set of [] for each dimension. `[1,2,3,4]` is a list with 4 items, numbers. `[[1],[2]]` is a list of 2 items, each of which is a list. – hpaulj May 10 '18 at 22:02
  • The [] are not the same as borders of cells of a table. They mark a row of cells, and high groupings. The cells themselves are separated by commas or paces. – hpaulj May 10 '18 at 22:29
  • "No, in the third axis is displayed 3 numbers, not containers" So, when is an axis actually a container, and when is an axis just some numbers? How do you separate the axis from what is inside the axis? If you showed me a cube in real life and we looked at the Z axis, and someone said, "No, the third axis (Z axis) of the cube is just 3 numbers" that wouldn't make any sense. The third axis of a cube is another dimension -- which I would think is represented by square brackets. The brackets we see here `[0 0 0]` are denoting the 2nd axis. Theres no brackets denoting the 3rd axis. Just scalars – Monica Heddneck May 10 '18 at 22:31
  • The last axis dimension is 3 and thus its shape is `(3,)`. That shape means its a single block of three numbers. If the shape was `(3,1)`, it would be a block of three blocks, where each block contains 1 number. You can say that the last axis is not a container and thus numbers corresponding to that axis will not be surrounded by brackets. If we were to follow your logic, and add brackets to scalars, then a `1` will be appended to every shape. That will be redundant. For example, `(4,3,3)` will become `(4,3,3,1)`. – Autonomous May 10 '18 at 23:23
  • `a[0,0,:]` isn't actually the 'last axis'. It is a 1d view of the 3d array. So are `a[0,:,2]`, and `a[:,1,0]`. – hpaulj May 11 '18 at 01:32
1

Maybe the best way of wrapping one's head around this is thinking in terms of the equivalent nested list:

>>> from pprint import pprint
>>> 
>>> L = a.tolist()
>>> pprint(L)
[[[0, 0, 0], [1, 1, 1], [2, 2, 2], [3, 3, 3]],
 [[1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4]],
 [[2, 2, 2], [3, 3, 3], [4, 4, 4], [5, 5, 5]],
 [[3, 3, 3], [4, 4, 4], [5, 5, 5], [6, 6, 6]]]

This has a few commas but apart from that it has the exact same structure as the printed array.

The first thing to observe: A nested list is still a list, so there should be one pair of brackets enclosing the entire thing.

This is a list of length 4. Its elements are nested lists themselves:

>>> A, B, C, D = L
>>> L == [A, B, C, D]
True
>>> A
[[0, 0, 0], [1, 1, 1], [2, 2, 2], [3, 3, 3]]

Again, each of those being a list should be enclosed in their own pair of brackets.

Each of these lists' elements are plain lists:

>>> A1, A2, A3, A4 = A
>>> pprint(A3)
[2, 2, 2]

In particular, there is no reason why these innermost lists' elements should have their own brackets.

Paul Panzer
  • 51,835
  • 3
  • 54
  • 99
0

Print the contents of a, rather than a itself. Brackets appear when printing any list, but they do not when printing the contents of the list.

Colin Hancey
  • 219
  • 2
  • 8
  • 1
    "Brackets appear when printing any list, but they do not when printing the contents of the list." This is pretty much the answer I was looking for. Would you agree that this convention is a little awkward when it comes to printing out `a` on the screen and trying to map the output back to shape it is in? – Monica Heddneck May 10 '18 at 21:47
  • @MonicaHeddneck I absolutely disagree with that, but it's down to personal preference I guess. Have you ever tried parsing JSON? – roganjosh May 10 '18 at 21:48
  • yes, plenty o that along with XML...but then my question was more about printing to the screen as opposed to the actual structure of any data. I understand the structure of the array in the question -- just not why it was printed to the screen as such – Monica Heddneck May 10 '18 at 21:49
  • "Brackets appear when printing any list, but they do not when printing the contents of the list." actually implies that the scalars **are actually** contained in their own separate, dare I say invisible, lists. – Monica Heddneck May 10 '18 at 21:51
  • I'm not sure that displaying the brackets is very useful, but this convention seems to be the most technically correct to me. Although, I hardly ever want the brackets. I think it's a preference of simplicity vs convenience. – Colin Hancey May 10 '18 at 21:51
  • 1
    @MonicaHeddneck then, at least for me, there'd have to be a fork in `print` functionality because I'd be completely lost if it started missing those brackets. I don't believe, and I could well be wrong, that the printed output of Python data structures should be useful to anyone other than the developer – roganjosh May 10 '18 at 21:51
  • @ColinHancey I feel like `print(a.shape)` is very common and very useful for developing and debugging – Monica Heddneck May 10 '18 at 21:53