리스트의 경우처럼 인덱싱과 슬라이싱을 이용하여 어레이 항목들을 확인, 수정할 수 있으며, 새로운 어레이를 생성할 수 있다. 여기서는 어레이의 인덱싱과 슬라이싱의 다양한 활용을 배운다.
In [1]:
import numpy as np
In [2]:
a = np.arange(10)
a
Out[2]:
In [3]:
a[0], a[2], a[-1]
Out[3]:
In [4]:
a[::-1]
Out[4]:
In [5]:
a[2:9:3] # [시작:끝:계단]
Out[5]:
In [6]:
a[:4]
Out[6]:
In [7]:
a[1:3]
Out[7]:
In [8]:
a[::2]
Out[8]:
In [9]:
a[3:]
Out[9]:
다차원 어레이에서 사용되는 인덱싱과 슬라이싱은 해당 어레이의 차원에 맞추어 작동한다. 즉, 어레이의 차원과 상응하는 튜플 형식으로 인덱싱과 슬라이싱 정보를 사용해야 한다.
In [10]:
b = [[0, 1, 2], [3, 4, 5]]
기본적으로 b
는 길이가 2인 리스트이다.
In [11]:
len(b)
Out[11]:
b
에서 0
을 뽑아내고자 할 경우 인덱싱을 두 번 연속해서 사용해야 하는데,
이는 0
이 b
의 첫째 항목의 첫째 항목이기 때문이다. 즉,
In [12]:
b[0][0]
Out[12]:
5
의 경우 둘째 항목의 셋째 항목이다.
In [13]:
b[1][2]
Out[13]:
반면에 b
를 이차원 어레이로 다루어 보자.
In [14]:
b = np.array([[0, 1, 2], [3, 4, 5]])
b
Out[14]:
2차원 어레이의 경우 인덱스를 행과 열의 개념을 이용하여 아래와 같은 방식으로 사용하면 된다.
[0, 0]
을 사용한다.
In [15]:
b[0, 0]
Out[15]:
[1, 2]
를 사용한다.
In [16]:
b[1,2]
Out[16]:
주의: 인덱스는 0부터 시작한다.
보다 다양한 예제들을 이용하여 어레이 인덱싱을 연습해보자.
아래 코드에서 정의된 d는 2차원 어레이이며, 대각선에 0, 1, 2를 담고 있다.
In [17]:
d = np.diag(np.arange(3))
d
Out[17]:
1
의 위치는 1행, 1열이므로 [1, 1]
을 이용한다.
In [18]:
d[1, 1]
Out[18]:
In [19]:
d[2, 1] = 10
d
Out[19]:
주의:
그렇다면 d[2]
는 무엇을 의미할까?
d
를 리스트라 생각하면 된다. 즉, d의 2번 항목인 [0, 10, 2]
어레이를 가리킨다.
In [20]:
d[2]
Out[20]:
np.arange
함수를 이용하여 길이가 36인 어레이를 생성한 다음에
shape 값을 변경하여 2차원 어레이를 생성한다.
In [21]:
a = np.arange(36)
a.shape = (6,6)
a
Out[21]:
In [22]:
a = np.arange(36).reshape((6,6))
a
Out[22]:
이제 각 행별로 4의 배수를 더하면 원하는 어레이가 얻어지는 성질을 이용한다. 어레이와 숫자의 연산은 각 항목별로 실행된다는 점을 이용한다.
In [23]:
a = np.arange(36).reshape((6,6))
for i in range(len(a)):
for j in range(6):
a[i, j] = a[i, j] + 4*i
a
Out[23]:
어레이의 연산은 항목별로 이루어진다는 점에 착안한다면 아래와 같이 코드를 작성할 수 있다.
주의: a[i]
는 a
어레이의 i
번 행을 가리킨다. 예를 들어,
a[2] = array([12, 13, 14, 15, 16, 17])
이다. 따라서 a[2] + 4*2
는 a[2]
의 각각의 항목에 8을 더해주는 식으로 계산된다.
a[2] + 4*2 = array([20, 21, 22, 23, 24, 25])
In [24]:
a = np.arange(36).reshape((6,6))
for i in range(len(a)):
a[i] = a[i] + 4*i
a
Out[24]:
In [25]:
a = np.arange(6) + np.arange(0, 51, 10)[:, np.newaxis]
a
Out[25]:
In [26]:
a[0, 3:5]
Out[26]:
In [27]:
a[4:, 4:]
Out[27]:
In [28]:
a[:, 2]
Out[28]:
In [29]:
a[2::2, ::2]
Out[29]:
In [30]:
np.random.seed(5)
이제 0과 20 사이에서 무작위로 15개의 정수를 3 x 5
행렬의 모양으로 생성하자.
In [31]:
a = np.random.randint(0, 20, size=(3, 5))
a
Out[31]:
a
의 항목들이 3의 배수 여부를 알려주는 어레이는 다음처럼 생성할 수 있다.
In [32]:
mask = (a % 3 == 0)
mask
Out[32]:
주의: 어레이의 연산은 항목별로 실행된다.
In [33]:
a % 3
Out[33]:
또한 두 어레이의 모양이 다르면 브로드캐스팅 기능을 이용하여 두 어레이의 모양을 가능하면 통일시킨다. 물론, 모양의 통일이 불가능하면 오류가 발생한다. 브로드캐스팅에 대해서는 다음 시간에 자세히 배운다.
아래 코드에서 a % 3
은 3 x 5
모양의 2차원 어레이 인 반면에 숫자 0은 어레이가 전혀 아니다.
하지만 숫자 0으로 이루어진 3 x 5
모양의 어레이로 모양을 만들면 두 어레이가 동일한 모양을 갖게 되고,
따라서 항목별로 비교가 가능해진다.
사실은 a % 3
도 이와 같은 방식으로 이해할 수 있다.
즉, 먼저 3으로 이루어진 3 x 5
모양의 어레이로 만든 다음에 두 어레이 간의 나머지 연산을 실행한다.
In [34]:
a % 3 == 0
Out[34]:
이제 a
의 항목들 중에서 mask
의 항목들 중 True
가 위치한 곳과 동일한 곳에 위치한 항목들만 뽑아서 1차원 어레이를 만들어 준다.
즉, a
의 항목들 중에서 3의 배수인 숫자들만 뽑아서 어레이로 만들어서 리턴한다.
In [35]:
multiple_3 = a[mask]
multiple_3
Out[35]:
다음처럼 보다 간단한 구현이 가능하다.
In [36]:
a[a % 3 == 0]
Out[36]:
In [37]:
a[a % 3 == 0] = -1
a
Out[37]:
슬라이싱을 이용하여 아래 기능을 수행하는 함수 odd_numbers
와 even_numbers
를 구현하라.
odd_numbers
함수는 양의 정수 n
을 입력 받아 0부터 n까지의 정수 중에서 홀수를 역순으로
담은 1차원 어레이를 리턴한다.
In [31]: odd_numbers(10)
Out[31]: array([9, 7, 5, 3, 1])
even_numbers
함수는 양의 정수 n
을 입력 받아 0부터 n까지의 정수 중에서 짝수를
담은 1차원 어레이를 리턴한다.
In [32]: even_numbers(10)
Out[32]: array([0, 2, 4, 6, 8, 10])
힌트: arange()
, 함수와 슬라이싱을 적절히 활용한다.
In [38]:
def odd_numbers(n):
odds = np.arange(1, n, 2)
return odds[::-1]
odd_numbers(10)
Out[38]:
In [39]:
def even_numbers(n):
evens = np.arange(0, n+1, 2)
return evens
even_numbers(10)
Out[39]: