[Numpy 강좌 – 3] 넘파이(Numpy)를 이용한 배열의 인덱싱(indexing)과 슬라이싱(Slicing) 이해하기

1. Numpy 인덱싱

 

Numpy 배열 인덱싱(indexing)은 리스트 인덱싱과 매우 유사하게 작동합니다. 인덱싱(Indexing)은 특정 위치의 데이터에 접근하는 것을 의미합니다. 인덱싱을 이용해 특정 위치에 있는 값을 가져오거나 설정할 수 있습니다.

 

아래 코드는 numpy 배열에 대한 기본적인 인덱싱 방법을 설명하는 코드입니다. 1에서 5까지의 정수 원소를 포함한 1차원 넘파이 배열 arr을 생성합니다. 그리고 인덱싱을 통해 첫 번째 원소와 마지막 원소에 접근하고, 접근한 원소를 출력합니다. 배열의 인덱스는 0부터 시작하며, -1은 배열의 마지막 원소를 가리킵니다.

 

배열의 원소에 접근하여 읽는것 뿐만 아니라 원소를 직접 변경할 수도 있습니다. 첫 번째 원소의 값을 10으로 변경합니다. 그리고 변경한 후의 배열을 출력합니다.

 

import numpy as np

# 인덱싱 기본
arr = np.array([1, 2, 3, 4, 5])
print("Original array: ", arr)
print("First element: ", arr[0])  # 첫 번째 원소
print("Last element: ", arr[-1])  # 마지막 원소

arr[0] = 10  # 첫 번째 원소 값을 변경
print("Array after modification: ", arr)

 

 


2. 다차원 배열의 인덱싱

 

Numpy에서는 다차원 배열을 생성하고 사용할 수 있습니다. 이러한 다차원 배열에서 인덱싱은 각 차원에 대해 독립적으로 작동합니다. 다차원 배열의 경우, 콤마로 구분된 인덱스 튜플을 사용하여 인덱싱합니다. 예를 들어 2차원 배열에서는 두 개의 인덱스가 필요합니다. 첫 번째 인덱스는 행을, 두 번째 인덱스는 열을 가리킵니다.

 

아래 코드에서 2차원 넘파이 배열 arr를 생성합니다. 이 배열은 3x3 크기로, 3개의 행과 3개의 열로 구성되어 있습니다. 배열의 (1, 1) 위치에 접근하여 원소를 출력합니다. 배열의 인덱스는 0부터 시작하므로 (1, 1)은 실제로 두 번째 행과 두 번째 열에 위치한 원소를 가리킵니다. 배열의 (0, 0) 위치에 있는 원소의 값을 10으로 변경합니다. 이 위치는 첫 번째 행의 첫 번째 열에 해당하는 원소를 가리킵니다.

 

arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print("Original array: \n", arr)
print("Element at position (1,1): ", arr[1, 1])  # (1,1) 위치의 원소

arr[0, 0] = 10  # (0,0) 위치의 원소 값을 변경
print("Array after modification: \n", arr)

 


3. 불리언 인덱싱 (Boolean indexing)

 

불리언 인덱싱은 배열의 각 원소에 대한 불리언(True/False)값을 이용해 인덱싱하는 방법입니다. 이 방법은 특정 조건을 만족하는 원소만 선택하고 싶을 때 유용하게 사용할 수 있습니다.

 

아래 코드는 불리언 인덱싱의 예시 코드입니다. 1차원 넘파이 배열을 생성하고 배열의 원소 중 2보다 큰 원소들만 선택하여 출력 합니다. arr > 2는 배열의 각 원소에 대해 2보다 큰지의 여부를 불리언 값으로 반환합니다. 이 불리언 배열은 원래의 arr 배열에 인덱스로 사용되어, True에 해당하는 위치의 원소들만 선택합니다.

 

arr = np.array([1, 2, 3, 4, 5])
print("Original array: ", arr)
print("Elements greater than 2: ", arr[arr > 2])  # 2보다 큰 원소들

 

 


4. 슬라이싱과 View 개념

 

슬라이싱은 배열의 일부분을 선택하는 방법을 의미합니다. 넘파이 배열에서 슬라이싱을 수행하면, 그 결과는 원래 배열의 뷰(View)가 됩니다. 뷰는 원래 배열의 데이터를 참조하는 객체를 말하며, 뷰를 수정하면 원래 배열의 데이터도 수정됩니다. 이러한 특징은 메모리를 효율적으로 사용할 수 있게 해주지만, 원본 데이터를 변경하게 될 수 있으므로 주의 해야합니다.

 

아래 코드는 슬라이싱의 예시 입니다. 1차원 배열을 생성하고, 배열의 인덱스 1에서 인덱스 3까지의 슬라이스를 생성합니다. 슬라이싱에서 콜론( : )기호를 사용하여 시작 인덱스와 종료 인덱스를 지정할 수 있으며, 종료 인덱스는 슬라이스에 포함되지 않습니다. 슬라이스의 첫 번째 원소 값을 10으로 변경합니다. 원소 값을 변경한 후의 슬라이스와 원래 배열을 출력합니다. 원래 배열에서도 첫 번째 인덱스 원소의 값이 변경된 겂을 확인할 수 있습니다. 이는 slice_arr가 arr의 뷰이며, slice_arr를 수정하면 arr도 함께 수정되기 때문입니다.

 

arr = np.array([1, 2, 3, 4, 5])
print("Original array: ", arr)

slice_arr = arr[1:4]  # 인덱스 1에서 3까지의 슬라이스
print("Slice of the array: ", slice_arr)

slice_arr[0] = 10  # 슬라이스의 첫 번째 원소 값을 변경
print("Slice after modification: ", slice_arr)
print("Original array after modification: ", arr)  # 원래 배열도 변경됨