3

My question may look too simple, but I am curious to know why this is available in Python.

Assume we have defined an array of size of (4,3):

import numpy as np
a=np.random.randint(15,size=(4,3))

The result would be something like below:

array([[ 7,  6,  1],
       [ 5,  3,  6],
       [12, 10, 11],
       [ 1,  3,  4]])

What is difference between:

a[0]

Result:
array([7, 6, 1])

and

a[0:1]

Result:
array([[7, 6, 1]])

As both of them return the same part of the matrix:

7, 6, 1

I do know that the difference is the shape as the former one is (3,) and the later one is sized of (1,3). But my question is that why we need to have these kinds of shapes. If you are familiar with Matlab, giving a range using colon gives you two rows, but in Python, it returns the same information with different shape. What is the point? what is the advantage?

Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
David
  • 1,343
  • 3
  • 12
  • 13
  • 1
    Python slices are half-open, while Matlab slices are closed. `0:1` in Python is `0:0` in Matlab. You're expecting two rows because you're using the wrong slice. – user2357112 May 07 '19 at 22:36
  • 1
    There's an important difference you've missed: the double brackets `[[...]]`. Meaning that `[[7,6,1]]` is an array with single element being an array of 3 elements. It's a nested array. In Python `arr[0]` returns first element while `arr[x:y]` returns a subarray from index x to index y-1. – freakish May 07 '19 at 22:36
  • Only true for a Numpy Array, right @freakish? – Pitto May 07 '19 at 22:48
  • @Pitto No, for all. – freakish May 07 '19 at 22:49
  • I am missing something, then... Slicing lists or strings doesn't return a list of lists @freakish http://www.codeskulptor.org/#user46_A8NoTJZ3E0yvh8i_2.py – Pitto May 07 '19 at 22:50
  • 1
    @Pitto That's because you didn't start with a list of lists. See what `a` is in OP's example. – freakish May 07 '19 at 22:52
  • Ah, damn, totally! :D Thanks @freakish – Pitto May 07 '19 at 23:08
  • MATLAB only has 2d matrices. `numpy` handles 0d and 1d. Also try the same indexing on a simple list. – hpaulj May 08 '19 at 02:51

5 Answers5

3

The reason is that you can be confident that array[x:y] always returns a subarray of the original array. So that you can use all the array methods on it. Say you have

map(lambda1, array[x:y])

Even if y-x == 1 or y-x == 0, you are guaranteed to have a array returned from array[x:y] and you can do map over it. Imagine if array[1:2] instead returned a single item i.e. array[1]. Then the behavior of the above code depends on what array[1] is, and it is probably not what you want.

nuts-n-bits
  • 143
  • 6
1

I will try to explain with a simplified example.

simple_matrix = [[0,1,2],[3,4,5],[6,7,8]]

The following code is printing a single element from this list of lists:

print (simple_matrix[0])

The element printed is a list, this is because the element at index 0 of simple_matrix is only a list:

>>> [0,1,2]

The use of slicing, like in the following example, returns not a single element but two. In this case it is simpler to expect a list of elements as return and that is exactly what we see as result:

print (simple_matrix[0:2])
>>> [[0, 1, 2], [3, 4, 5]]

What seems to puzzle you is this output:

print simple_matrix[0:1]
>>> [[0, 1, 2]]

You get this output because in this case your are not getting a single element from the list like we did in the 1st example but because you are slicing a list of lists.

This slice returns a list containing the sliced elements, in this case only the list [0, 1, 2].

Pitto
  • 8,229
  • 3
  • 42
  • 51
1

Colon notation is a shorthand for slicing, so start with a brief definition of terms with some trivial examples. I'd refer you to this great answer to start with understanding how slices work in general. This is contrasted with what I'll term "access notation", or accessing an array element like a[0].

Therefore, in your case, the difference is that your n-dimensional array can be accessed at dimension 0, which returns the series of columns in that row. In contrast, slicing your n-dimensional array from 0 to 1 gives a list containing dimensions 0 through-but-not-including 1, which will be a two-dimensional array where the first (and only) element is a series of columns in the first row.

With respect to shapes, it depends what you're doing with the data. For instance, if you needed to access multiple rows at once, it might make more sense to use a wider slice in one go, whereas access notation would require multiple statements or a loop.

A note about Numpy Arrays specifically

Slicing a traditional, one-dimensional array will always yield a subset of the original array, as a copy. In contrast, slicing an n-dimensional NP array will yield a view instead, which shares memory with the original array. Be careful, as modifying this slice will modify the original as well!

Hypaethral
  • 1,467
  • 16
  • 22
0

I believe the point you are confused about is that in python, when you take a splice of an array, it is inclusive of the start index but EXCLUSIVE of the end index. I believe that in Matlab both the start index and the end index are inclusive.

So for the example you gave: a[0:1] will take index 0, and not 1.

However, if you were you use a[0:2], you will get what is at indices 0 and 1, and get the result you seemed to be expecting.

This also explains why the shape is different, a[0:1] is doing exactly what you expect. It is giving you a list of rows, but that list only contains 1 row, hence the 1 in the shape (1, 3). Conversely, a[0] only gives you a single row, and not a list of rows. The row has 3 elements, and hence you get the shape (3,)

ejmejm
  • 86
  • 7
0

array[m:n] returns an array, array[0] returns an element of the array (this has bearing on NumPy stuff too, I promise, just read on):

> py -3
Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 17:00:18) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> array = [1,2,3]
>>> array[0]
1
>>> array[0:1]
[1]
>>>

This is why you get these results:

a[0]

Result:

array([7, 6, 1])

and

a[0:1]

Result:

array([[7, 6, 1]])

If you look carefully, the second returns an array that wraps a list of list of numbers, while the first returns an array that wraps a list of numbers.

djhaskin987
  • 9,741
  • 4
  • 50
  • 86