# 3-3-2-8. Slicing ndarrays

As we mentioned earlier,

in addition to accessing individual elements one at a time,

we can access subsets of NumPy arrays with slicing.

Slicing is performed by combining indices with a colon inside the brackets.

In general, you will come across three ways of slicing.

First, slicing from a starting index to an ending index.

Second, slicing from a starting index to the end of the array,

by leaving this blank, or slicing from the beginning of

the array to an ending index, by leaving this part blank.

In the first and third methods,

the ending index is always excluded.

While here, the starting index is always included.

NumPy arrays can be multidimensional.

So, when slicing, you usually have to specify a slice for each dimension of the array.

Let’s see some examples of slicing,

with a rank two array.

Here is a four by five array that contains integers from one to 20.

Let’s say, you wanted to grab this subset from the array, these nine values.

Here is one way we can do this.

The part before the comma,

specifies what indices you want to grab from the rows,

and the part after the comma specifies what indices you want to grab from the columns.

Remember, the starting index is included and the ending index is excluded.

And indexing always starts with zero.

So, the first row is zero and the second column is one.

So, this grabs the rows one, two, and three.

And this part grabs the columns two, three, and four.

Here is another way we can accomplish that same thing.

Remember, if we don’t include an ending index after the colon,

it will just go all the way to the last index.

Let’s try to grab another subset that uses these same columns,

but instead of the last three rows,

grabs the first three rows.

This grabs this subset.

Remember, not including a starting index before

the colon just makes it go all the way to the beginning of the array.

So, this grabs the rows zero, one, and two.

For our next example,

let’s try to select all the elements in the third row.

If we leave both sides of the colon blank,

this will just grab all the rows in the array.

So, X, colon, comma,

two will get all the rows in column two.

So, zero, one, two it would grab this column.

If we want to select all the elements in the third column but

return it in a rank two array, we can do this.

Notice that when we first selected all the elements in the third column this way,

the slice returned a rank one array instead of a rank two array.

But slicing X like this,

in a slightly different way,

can get us a rank two NumPy array.

It’s important to note that when we perform slices on

NumPy arrays and save them into new variables,

like we did here, the data is not actually copied into the new variable.

This is one feature that often causes confusion for beginners.

So, we’ll look into this in more detail.

In these examples, the slice of the original array X,

is not copied into the variable Z.

Rather, X and Z are now just two different names for the same array.

We say that slicing only creates a view of the original array.

This means, if you make any changes in Z,

you’ll also be changing the elements in X.

Let’s see an example with that four by five array.

We’ll select the elements over here again,

and assign that to the variable Z.

Now, we’ll change the last element in Z to 555.

Now, if we print X,

we can see that it has also been affected by this change.

If we want to create a new NumPy array that contains a copy of the values in the slice,

we need to use NumPy’s Copy function.

This function can also be used as a method,

as we saw before with the reshape function.

Let’s repeat this example with the copy command.

Here’s X again, we’ll create a copy of the same slice using the copy function.

We can also use Copy as a method like this.

If we change the last element in Z to 555,

we can see that X has not been changed.

By using the Copy command,

we are creating a new NumPy array,

that is completely independent of the original.

It’s often useful to use an array as indices to make slices,

select, or change elements in another NumPy array.

Let’s see some examples.

Let’s create a rank one array that will serve as indices to select elements from X.

We’ll use this indices NumPy array to select the second and fourth row of X.

Now, we’ll use the same array to select the second and fourth column of X.

NumPy also offers built-in functions to select specific elements within NumPy arrays.

For example, NumPy’s diag function can extract elements along the diagonal of an array.

We can also print the elements above the main diagonal of X by setting a parameter,

K equal to one.

This grabs the elements one, seven,13, and 19.

If K is a negative number,

this will grab the values below the main diagonal, five,11, and 17.

By default, K is zero,

which is why it gets the main diagonal.

It’s also often useful to extract only the unique elements in a NumPy array.

We can find the unique elements in an array by using NumPy’s Unique function.

Here’s a three by three array with repeated values.

We can see the unique values like this.

앞서 언급했듯이,

개별 요소에 한 번에 하나씩 액세스하는 것 외에도

슬라이싱을 통해 NumPy 배열의 하위 집합에 액세스할 수 있습니다.

슬라이싱은 인덱스를 괄호 안에 콜론과 결합하여 수행됩니다.

일반적으로 슬라이싱에는 세 가지 방법이 있습니다.

먼저 시작 인덱스에서 끝 인덱스로 슬라이싱합니다.

둘째, 시작 인덱스에서 배열의 끝까지 슬라이싱,

이 공백을 남겨두거나 시작 부분에서 슬라이스하여

이 부분을 공백으로 두어 배열을 끝 인덱스로 바꿉니다.

첫 번째와 세 번째 방법에서,

끝 인덱스는 항상 제외됩니다.

여기에 있는 동안 시작 인덱스는 항상 포함됩니다.

NumPy 배열은 다차원일 수 있습니다.

따라서 슬라이스할 때 일반적으로 배열의 각 차원에 대해 슬라이스를 지정해야 합니다.

슬라이싱의 몇 가지 예를 살펴보겠습니다.

2순위 배열로.

다음은 1에서 20까지의 정수를 포함하는 4×5 배열입니다.

예를 들어 배열에서 이 하위 집합, 즉 9개의 값을 가져오려고 한다고 가정해 보겠습니다.

여기 우리가 할 수 있는 한 가지 방법이 있습니다.

쉼표 앞 부분,

행에서 가져올 인덱스를 지정하고,

쉼표 뒤의 부분은 열에서 가져올 인덱스를 지정합니다.

시작 인덱스는 포함되고 종료 인덱스는 제외된다는 것을 기억하십시오.

그리고 인덱싱은 항상 0으로 시작합니다.

따라서 첫 번째 행은 0이고 두 번째 열은 1입니다.

따라서 행 1, 2, 3을 가져옵니다.

그리고 이 부분은 2, 3, 4열을 잡습니다.

여기에 동일한 작업을 수행할 수 있는 또 다른 방법이 있습니다.

콜론 뒤에 끝 인덱스를 포함하지 않으면

마지막 인덱스까지 계속 이동합니다.

이러한 동일한 열을 사용하는 다른 하위 집합을 가져오도록 합시다.

하지만 마지막 세 행 대신

처음 세 행을 가져옵니다.

이것은 이 하위 집합을 잡습니다.

시작 인덱스를 포함하지 않음을 기억하십시오.

콜론은 배열의 시작 부분으로 이동합니다.

따라서 이것은 행 0, 1 및 2를 가져옵니다.

다음 예에서는

세 번째 행의 모든 ​​요소를 ​​선택하려고 합니다.

콜론의 양쪽을 공백으로 두면

이것은 배열의 모든 행을 잡습니다.

따라서 X, 콜론, 쉼표,

2는 2열의 모든 행을 가져옵니다.

그래서, 0, 1, 2는 이 열을 잡을 것입니다.

세 번째 열의 모든 요소를 ​​선택하고 싶지만

2순위 배열로 반환하면 이렇게 할 수 있습니다.

이 방법으로 세 번째 열의 모든 요소를 ​​처음 선택했을 때,

슬라이스가 2순위 배열 대신 1순위 배열을 반환했습니다.

하지만 이렇게 X를 자르면

조금 다른 방식으로,

2순위 NumPy 배열을 얻을 수 있습니다.

슬라이스를 수행할 때

NumPy 배열을 만들고 새 변수에 저장합니다.

여기서 했던 것처럼 데이터는 실제로 새 변수에 복사되지 않습니다.

이것은 초보자에게 종종 혼동을 일으키는 기능 중 하나입니다.

따라서 이에 대해 더 자세히 살펴보겠습니다.

이 예에서 원래 배열 X의 슬라이스,

변수 Z에 복사되지 않습니다.

오히려 X와 Z는 이제 동일한 배열에 대한 두 개의 다른 이름일 뿐입니다.

슬라이싱은 원래 배열의 보기만 생성한다고 말합니다.

즉, Z를 변경하면

X의 요소도 변경합니다.

4×5 배열의 예를 살펴보겠습니다.

여기에서 요소를 다시 선택하겠습니다.

그리고 그것을 변수 Z에 할당합니다.

이제 Z의 마지막 요소를 555로 변경합니다.

이제 X를 인쇄하면

이 변경 사항에도 영향을 미쳤음을 알 수 있습니다.

슬라이스 값의 복사본을 포함하는 새 NumPy 배열을 생성하려는 경우,

NumPy의 Copy 기능을 사용해야 합니다.

이 함수는 메서드로도 사용할 수 있으며,

우리가 reshape 기능으로 전에 본 것처럼.

복사 명령을 사용하여 이 예를 반복해 보겠습니다.

여기 다시 X가 있습니다. 복사 기능을 사용하여 동일한 슬라이스의 복사본을 만들 것입니다.

Copy를 이와 같은 방법으로 사용할 수도 있습니다.

Z의 마지막 요소를 555로 변경하면,

X가 변경되지 않았음을 알 수 있습니다.

복사 명령을 사용하여

우리는 새로운 NumPy 배열을 만들고 있습니다.

그것은 원본과 완전히 독립적입니다.

배열을 인덱스로 사용하여 슬라이스를 만드는 것이 종종 유용합니다.

다른 NumPy 배열의 요소를 선택하거나 변경합니다.

몇 가지 예를 살펴보겠습니다.

X에서 요소를 선택하기 위한 인덱스 역할을 하는 1순위 배열을 만들어 보겠습니다.

이 인덱스 NumPy 배열을 사용하여 X의 두 번째 및 네 번째 행을 선택합니다.

이제 동일한 배열을 사용하여 X의 두 번째 및 네 번째 열을 선택합니다.

NumPy는 또한 NumPy 배열 내에서 특정 요소를 선택하는 내장 함수를 제공합니다.

예를 들어 NumPy의 diag 함수는 배열의 대각선을 따라 요소를 추출할 수 있습니다.

기억하십시오, X는 이것이었습니다.

매개변수를 설정하여 X의 주 대각선 위에 있는 요소를 인쇄할 수도 있습니다.

K는 1과 같습니다.

이것은 요소 1, 7, 13 및 19를 가져옵니다.

K가 음수이면,

이것은 주 대각선, 5, 11 및 17 아래의 값을 가져옵니다.

기본적으로 K는 0이고,

이것이 주 대각선을 얻는 이유입니다.

NumPy 배열에서 고유한 요소만 추출하는 것도 종종 유용합니다.

NumPy의 Unique 함수를 사용하여 배열에서 고유한 요소를 찾을 수 있습니다.

다음은 반복되는 값을 가진 3×3 배열입니다.

이렇게 고유한 값을 볼 수 있습니다.

Slicing ndarrays

As we mentioned earlier, in addition to being able to access individual elements one at a time, NumPy provides a way to access subsets of ndarrays. This is known as slicing. Slicing is performed by combining indices with the colon : symbol inside the square brackets. In general you will come across three types of slicing:

1. ndarray[start:end]
2. ndarray[start:]
3. ndarray[:end]


The first method is used to select elements between the start and end indices. The second method is used to select all elements from the start index till the last index. The third method is used to select all elements from the first index till the end index. We should note that in methods one and three, the end index is excluded. We should also note that since ndarrays can be multidimensional, when doing slicing you usually have to specify a slice for each dimension of the array.

We will now see some examples of how to use the above methods to select different subsets of a rank 2 ndarray.

#### Example 1. Slicing in a 2-D ndarray

# We create a 4 x 5 ndarray that contains integers from 0 to 19
X = np.arange(20).reshape(4, 5)

# We print X
print()
print('X = \n', X)
print()

# We select all the elements that are in the 2nd through 4th rows and in the 3rd to 5th columns
Z = X[1:4,2:5]

# We print Z
print('Z = \n', Z)

# We can select the same elements as above using method 2
W = X[1:,2:5]

# We print W
print()
print('W = \n', W)

# We select all the elements that are in the 1st through 3rd rows and in the 3rd to 4th columns
Y = X[:3,2:5]

# We print Y
print()
print('Y = \n', Y)

# We select all the elements in the 3rd row
v = X[2,:]

# We print v
print()
print('v = ', v)

# We select all the elements in the 3rd column
q = X[:,2]

# We print q
print()
print('q = ', q)

# We select all the elements in the 3rd column but return a rank 2 ndarray
R = X[:,2:3]

# We print R
print()
print('R = \n', R)


X =
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]]

Z =
[[ 7 8 9]
[12 13 14]
[17 18 19]]

W =
[[ 7 8 9]
[12 13 14]
[17 18 19]]

Y =
[[ 2 3 4]
[ 7 8 9]
[12 13 14]]

v = [10 11 12 13 14]

q = [ 2 7 12 17]

R =
[[ 2]
[ 7]
[12]
[17]]

Notice that when we selected all the elements in the 3rd column, variable q above, the slice returned a rank 1 ndarray instead of a rank 2 ndarray. However, slicing X in a slightly different way, variable R above, we can actually get a rank 2 ndarray instead.

It is important to note that when we perform slices on ndarrays and save them into new variables, as we did above, the data is not copied into the new variable. This is one feature that often causes confusion for beginners. Therefore, we will look at this in a bit more detail.

In the above examples, when we make assignments, such as:

Z = X[1:4,2:5]


the slice of the original array X is not copied in the variable Z. Rather, X and Z are now just two different names for the same ndarray. We say that slicing only creates a view of the original array. This means that if you make changes in Z you will be in effect changing the elements in X as well. Let’s see this with an example:

#### Example 2. Slicing and editing elements in a 2-D ndarray

# We create a 4 x 5 ndarray that contains integers from 0 to 19
X = np.arange(20).reshape(4, 5)

# We print X
print()
print('X = \n', X)
print()

# We select all the elements that are in the 2nd through 4th rows and in the 3rd to 4th columns
Z = X[1:4,2:5]

# We print Z
print()
print('Z = \n', Z)
print()

# We change the last element in Z to 555
Z[2,2] = 555

# We print X
print()
print('X = \n', X)
print()


X =
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]]

Z =
[[ 7 8 9]
[12 13 14]
[17 18 19]]

X =
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[ 10 11 12 13 14]
[ 15 16 17 18 555]]

We can clearly see in the above example that if we make changes to ZX changes as well.

## numpy.ndarray.copy

Syntax:

ndarray.copy(order='C')


It returns a copy of the array. More details about the arguments are available here.

However, if we want to create a new ndarray that contains a copy of the values in the slice we need to use the np.copy() function. The np.copy(ndarray) function creates a copy of the given ndarray. This function can also be used as a method, in the same way as we did before with the reshape function. Let’s do the same example we did before but now with copies of the arrays. We’ll use copy both as a function and as a method.

#### Example 3. Demonstrate the copy() function

# We create a 4 x 5 ndarray that contains integers from 0 to 19
X = np.arange(20).reshape(4, 5)

# We print X
print()
print('X = \n', X)
print()

# create a copy of the slice using the np.copy() function
Z = np.copy(X[1:4,2:5])

#  create a copy of the slice using the copy as a method
W = X[1:4,2:5].copy()

# We change the last element in Z to 555
Z[2,2] = 555

# We change the last element in W to 444
W[2,2] = 444

# We print X
print()
print('X = \n', X)

# We print Z
print()
print('Z = \n', Z)

# We print W
print()
print('W = \n', W)


X =
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]]

X =
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]]

Z =
[[ 7 8 9]
[ 12 13 14]
[ 17 18 555]]

W =
[[ 7 8 9]
[ 12 13 14]
[ 17 18 444]]

We can clearly see that by using the copy command, we are creating new ndarrays that are completely independent of each other.

It is often useful to use one ndarray to make slices, select, or change elements in another ndarray. Let’s see some examples:

#### Example 4 a. Use an array as indices to either make slices, select, or change elements

# We create a 4 x 5 ndarray that contains integers from 0 to 19
X = np.arange(20).reshape(4, 5)

# We create a rank 1 ndarray that will serve as indices to select elements from X
indices = np.array([1,3])

# We print X
print()
print('X = \n', X)
print()

# We print indices
print('indices = ', indices)
print()

# We use the indices ndarray to select the 2nd and 4th row of X
Y = X[indices,:]

# We use the indices ndarray to select the 2nd and 4th column of X
Z = X[:, indices]

# We print Y
print()
print('Y = \n', Y)

# We print Z
print()
print('Z = \n', Z)


X =
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]]

indices = [1 3]

Y =
[[ 5 6 7 8 9]
[15 16 17 18 19]]

Z =
[[ 1 3]
[ 6 8]
[11 13]
[16 18]]

#### Example 4 b. Use an array as indices to extract specific rows from a rank 2 ndarray.

import numpy as np
# Let's create a rank 2 ndarray
X = np.random.randint(1,20, size=(50,5))
print("Shape of X is: ", X.shape)


Shape of X is: (50, 5)

# Create a rank 1 ndarray that contains a randomly chosen 10 values between 0 to len(X) (50)
# The row_indices would represent the indices of rows of X
row_indices = np.random.randint(0,50, size=10)
print("Random 10 indices are: ", row_indices)


Random 10 indices are: [ 1 38 31 45 44 21 6 24 19 33]

# To Do 1 - Print those rows of X whose indices are represented by entire row_indices ndarray
# Hint - Use the row_indices ndarray to select specified rows of X
X_subset = X[row_indices, :]
print(X_subset)

# To Do 2 - Print those rows of X whose indices are present in row_indices[4:8]
X_subset = X[row_indices[4:8], :]
print(X_subset)


## numpy.diag

Syntax:

numpy.diag(array, k=0)


It extracts or constructs the diagonal elements. More details about the arguments are available here.

NumPy also offers built-in functions to select specific elements within ndarrays. For example, the np.diag(ndarray, k=N) function extracts the elements along the diagonal defined by N. As default is k=0, which refers to the main diagonal. Values of k > 0 are used to select elements in diagonals above the main diagonal, and values of k < 0 are used to select elements in diagonals below the main diagonal. Let’s see an example:

#### Example 5. Demonstrate the diag() function

# We create a 4 x 5 ndarray that contains integers from 0 to 24
X = np.arange(25).reshape(5, 5)

# We print X
print()
print('X = \n', X)
print()

# We print the elements in the main diagonal of X
print('z =', np.diag(X))
print()

# We print the elements above the main diagonal of X
print('y =', np.diag(X, k=1))
print()

# We print the elements below the main diagonal of X
print('w = ', np.diag(X, k=-1))


X =
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]
[20 21 22 23 24]]

z = [ 0 6 12 18 24]

y = [ 1 7 13 19]

w = [ 5 11 17 23]

## numpy.unique

Syntax:

numpy.unique(array, return_index=False, return_inverse=False, return_counts=False, axis=None)


It returns the sorted unique elements of an array. Details about additional optional arguments are available here.

It is often useful to extract only the unique elements in an ndarray. We can find the unique elements in an ndarray by using the np.unique() function. The np.unique(ndarray) function returns the unique elements in the given ndarray, as in the example below:

#### Example 6. Demonstrate the unique() function

# Create 3 x 3 ndarray with repeated values
X = np.array([[1,2,3],[5,2,8],[1,2,3]])

# We print X
print()
print('X = \n', X)
print()

# We print the unique elements of X
print('The unique elements in X are:',np.unique(X))


X =
[[1 2 3]
[5 2 8]
[1 2 3]]

The unique elements in X are: [1 2 3 5 8]