NumPy 인덱싱 소개

NumPyBeginner
지금 연습하기

소개

다시 오신 것을 환영합니다! NumPy 배열을 생성하는 방법을 이해했으니, 이제 배열 내의 데이터를 액세스하고 조작하는 방법을 배울 차례입니다. 이 실습에서는 NumPy 배열 내에서 데이터를 액세스하고 수정하는 주요 방법인 **인덱싱 (indexing)**을 탐구합니다.

배운 내용 복습

이전 실습에서 다음 내용을 배웠습니다.

  • 다양한 NumPy 함수를 사용하여 배열 생성 방법
  • 배열과 Python 리스트의 차이점
  • 배열 차원 (1D, 2D, 3D) 및 데이터 유형

이제 다음 내용을 배우게 됩니다.

  • 개별 요소 또는 요소 그룹 액세스 방법
  • 배열에서 특정 행, 열 또는 영역 추출 방법
  • 복잡한 데이터 필터링을 위한 고급 선택 기법 사용 방법
  • 인덱싱을 통한 배열 데이터 수정 방법

인덱싱이 중요한 이유

인덱싱은 다음과 같은 작업을 가능하게 하므로 데이터 조작의 기본입니다.

  • 분석을 위한 데이터 부분 집합 추출
  • 대규모 데이터셋의 특정 값 수정
  • 조건에 기반한 데이터 필터링
  • 선택된 요소에 대한 벡터화된 연산 수행

이러한 기술은 Python 에서의 모든 데이터 분석 또는 과학 컴퓨팅 작업에 필수적입니다.

이것은 가이드 실험입니다. 학습과 실습을 돕기 위한 단계별 지침을 제공합니다.각 단계를 완료하고 실무 경험을 쌓기 위해 지침을 주의 깊게 따르세요. 과거 데이터에 따르면, 이것은 초급 레벨의 실험이며 완료율은 94%입니다.학습자들로부터 100%의 긍정적인 리뷰율을 받았습니다.

1D 배열의 기본 인덱싱 및 슬라이싱

배열을 생성하는 방법을 알았으니, 이제 배열의 내용을 액세스하는 방법을 배워보겠습니다. 이 실습의 모든 작업은 indexing_practice.py 파일에서 진행됩니다.

배열 인덱싱 이해하기

0 기반 인덱싱

Python 리스트와 마찬가지로 NumPy 배열도 0 기반 인덱싱을 사용합니다. 이는 다음을 의미합니다.

  • 첫 번째 요소는 인덱스 0에 있습니다.
  • 두 번째 요소는 인덱스 1에 있습니다.
  • 이와 같이 계속됩니다...

배열 인덱스 시각화

x = [10, 20, 30, 40, 50] 배열의 경우:

Index:  0   1   2   3   4
Value: 10  20  30  40  50

따라서 x[0]10을, x[2]30을 반환합니다.

슬라이싱 구문

슬라이싱을 사용하면 start:stop:step 구문으로 요소 범위를 선택할 수 있습니다.

  • start: 슬라이스가 시작되는 인덱스 (포함)
  • stop: 슬라이스가 끝나는 인덱스 (제외)
  • step: 건너뛸 요소 수 (선택 사항, 기본값은 1)

일반적인 슬라이싱 패턴:

  • x[1:4]: 인덱스 1, 2, 3 의 요소
  • x[:3]: 처음 3 개 요소 (인덱스 0, 1, 2)
  • x[2:]: 인덱스 2 부터 끝까지
  • x[::2]: 인덱스 0 부터 시작하여 두 번째 요소마다
  • x[::-1]: 전체 배열 반전

먼저 편집기에서 indexing_practice.py 파일을 엽니다. 그런 다음 파일의 전체 내용을 다음 코드로 바꿉니다. 이 코드는 1D 배열을 생성하고 단일 요소 및 요소 슬라이스를 액세스하는 방법을 보여줍니다.

import numpy as np

## 0 부터 9 까지의 숫자로 1D 배열 생성
x = np.arange(10)
print("Original array:", x)

## 인덱스 2 의 단일 요소 액세스
element = x[2]
print("Element at index 2:", element)

## 인덱스 1 부터 인덱스 7 까지 (7 은 제외) 2 씩 건너뛰며 슬라이싱
a_slice = x[1:7:2]
print("Slice from 1 to 7 with step 2:", a_slice)

indexing_practice.py에 코드를 추가한 후 파일을 저장합니다. 이제 터미널에서 다음 명령을 실행하여 스크립트를 실행합니다.

python indexing_practice.py

다음과 같은 출력이 표시되어야 합니다. 지정된 인덱스의 요소와 결과 슬라이스가 포함된 원본 배열이 표시됩니다.

Original array: [0 1 2 3 4 5 6 7 8 9]
Element at index 2: 2
Slice from 1 to 7 with step 2: [1 3 5]

다차원 배열 인덱싱

이제 여러 차원을 가진 배열을 다뤄보겠습니다. NumPy 가 Python 리스트에 비해 진가를 발휘하는 부분입니다!

다차원 사고방식

2D 배열을 표 (Table) 처럼 생각하기

2D 배열은 스프레드시트나 표와 같습니다.

  • **행 (Rows)**은 첫 번째 차원 (가로) 입니다.
  • **열 (Columns)**은 두 번째 차원 (세로) 입니다.
  • 행과 열 인덱스를 모두 지정합니다: array[row, column]

2D 인덱싱 시각화

2D 배열의 경우:

array = [[10, 20, 30],
         [40, 50, 60],
         [70, 80, 90]]

Indices:     0,0  0,1  0,2
             1,0  1,1  1,2
             2,0  2,1  2,2
  • array[0, 0] → 10 (첫 번째 행, 첫 번째 열)
  • array[1, 2] → 60 (두 번째 행, 세 번째 열)
  • array[2, 1] → 80 (세 번째 행, 두 번째 열)

전체 행 또는 열 선택하기

  • array[0] 또는 array[0, :] → 전체 첫 번째 행 [10, 20, 30]
  • array[:, 1] → 전체 두 번째 열 [20, 50, 80]
  • 이는 중첩된 Python 리스트보다 훨씬 편리합니다!

2 차원 (2D) 배열로 이를 연습해 보겠습니다. indexing_practice.py 파일을 아래 코드로 업데이트하세요. 이 스크립트는 3x4 배열을 생성하고 단일 요소와 전체 행을 액세스하는 방법을 보여줍니다.

import numpy as np

## 2D 배열 생성 (3 행, 4 열)
x = np.arange(12).reshape(3, 4)
print("Original 2D array:\n", x)

## 1 행 2 열의 요소 액세스
element = x[1, 2]
print("\nElement at (1, 2):", element)

## 전체 첫 번째 행 (행 인덱스 0) 액세스
first_row = x[0]
print("\nFirst row:", first_row)

파일을 저장하고 터미널에서 다시 실행합니다.

python indexing_practice.py

출력에는 2D 배열과 선택한 특정 부분이 표시됩니다.

Original 2D array:
 [[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

Element at (1, 2): 6

First row: [0 1 2 3]

고급 인덱싱

기본 슬라이싱은 연속된 영역에 잘 작동하지만, 때로는 더 복잡한 선택이 필요합니다. NumPy 는 두 가지 강력한 고급 인덱싱 기법을 제공합니다.

정수 배열 인덱싱 (Integer Array Indexing)

인덱스 배열을 제공하여 임의의 요소를 선택합니다. 이는 위치를 사용하여 리스트에서 특정 항목을 선택하는 것과 같습니다.

실제 예시: 시험 점수가 있고 3, 7, 12 번 학생들의 점수를 확인하고 싶다고 가정해 봅시다.

scores = np.array([85, 92, 78, 95, 88, 76, 91, 89, 84, 93, 87, 90, 82])
student_positions = [3, 7, 12]  ## 관심 있는 학생들의 위치
selected_scores = scores[student_positions]  ## 결과: [95, 89, 82]

불리언 배열 인덱싱 (Boolean Array Indexing, 마스킹)

조건에 따라 요소를 선택합니다. True/False 값으로 "마스크"를 생성한 다음 이를 사용하여 배열을 필터링합니다.

실제 예시: 반에서 합격 점수 (80 점 이상) 를 필터링합니다.

scores = np.array([85, 92, 78, 95, 88, 76, 91, 89, 84, 93])
passing_mask = scores >= 80  ## 결과: [True, True, False, True, True, False, True, True, True, True]
passing_scores = scores[passing_mask]  ## 결과: [85, 92, 95, 88, 91, 89, 84, 93]

왜 이것이 중요한가

  • 정수 인덱싱: 특정 데이터 포인트를 샘플링하는 데 완벽합니다.
  • 불리언 인덱싱: 데이터 필터링 및 조건부 선택에 이상적입니다.
  • 둘 다 복사본을 생성하며 (뷰가 아님), 따라서 수정이 원본 배열에 영향을 미치지 않습니다.

둘 다 시도해 보겠습니다. indexing_practice.py 파일의 내용을 다음 코드로 바꾸세요.

import numpy as np

## --- 정수 배열 인덱싱 ---
x = np.arange(10, 0, -1)
print("Array for integer indexing:", x)

## 인덱스 3, 3, 1, 8 의 요소 선택
selected_elements = x[np.array([3, 3, 1, 8])]
print("Selected elements with integer array:", selected_elements)


## --- 불리언 배열 인덱싱 ---
y = np.array([1., -1., -2., 3.])
print("\nArray for boolean indexing:", y)

## 음수 요소에 대한 불리언 마스크 생성
mask = y < 0
print("Boolean mask (y < 0):", mask)

## 조건이 True 인 요소 선택
negative_elements = y[mask]
print("Elements where y < 0:", negative_elements)

파일을 저장하고 스크립트를 실행합니다.

python indexing_practice.py

출력은 정수 및 불리언 인덱싱이 배열에서 특정 데이터를 선택하는 데 어떻게 작동하는지 보여줍니다.

Array for integer indexing: [10  9  8  7  6  5  4  3  2  1]
Selected elements with integer array: [7 7 9 2]

Array for boolean indexing: [ 1. -1. -2.  3.]
Boolean mask (y < 0): [False  True  True False]
Elements where y < 0: [-1. -2.]

인덱싱된 배열에 값 할당

인덱싱은 데이터를 읽는 데만 사용되는 것이 아니라 데이터를 수정하는 데도 강력합니다. 할당 연산자 (=) 의 왼쪽에 어떤 인덱싱 방법이든 사용하여 특정 요소를 변경할 수 있습니다.

브로드캐스팅 (Broadcasting): 형태 (Shape) 호환성 맞추기

인덱싱된 배열에 값을 할당할 때, NumPy 는 형태를 호환시키기 위해 브로드캐스팅을 사용합니다. 이것은 NumPy 의 가장 강력한 기능 중 하나입니다!

브로드캐스팅 규칙

NumPy 는 할당 중에 다음 규칙에 따라 작은 배열을 자동으로 확장하여 큰 배열과 일치시킬 수 있습니다.

  1. 단일 값을 여러 요소에 할당: 하나의 값을 여러 위치에 할당할 수 있습니다.
  2. 작은 배열을 더 큰 선택 영역에 할당: 차원이 호환되는 한 가능합니다.

할당 시 브로드캐스팅 예시

## 슬라이스에 단일 값 할당
arr = np.array([1, 2, 3, 4, 5])
arr[1:4] = 99  ## 결과: [1, 99, 99, 99, 5]

## 일치하는 슬라이스에 배열 할당
arr = np.array([1, 2, 3, 4, 5])
arr[1:4] = [10, 20, 30]  ## 결과: [1, 10, 20, 30, 5]

## 브로드캐스팅을 사용한 불리언 인덱싱
arr = np.array([1, 2, 3, 4, 5])
arr[arr % 2 == 0] = -1  ## 모든 짝수를 -1 로 대체

중요 참고 사항

  • 브로드캐스팅은 형태가 호환될 때만 작동합니다.
  • 할당되는 값의 형태는 인덱싱된 선택 영역에 "맞아야" 합니다.
  • 이는 요소를 수동으로 반복하는 것보다 훨씬 효율적입니다.

이 기능을 실제로 확인하기 위해 indexing_practice.py 파일을 다음 코드로 업데이트하세요.

import numpy as np

## --- 슬라이스에 단일 값 할당 ---
x = np.arange(10)
print("Original array:", x)

## 인덱스 2 부터 4 까지의 요소에 값 99 할당
x[2:5] = 99
print("After assigning 99 to slice [2:5]:", x)


## --- 불리언 조건을 기반으로 값 할당 ---
y = np.arange(10)
print("\nOriginal array:", y)

## 모든 짝수에 값 -1 할당
y[y % 2 == 0] = -1
print("After assigning -1 to even numbers:", y)

파일을 저장하고 터미널에서 실행합니다.

python indexing_practice.py

출력은 수정 전후의 배열을 보여주며, 이 기능이 데이터 조작에 얼마나 강력한지 보여줍니다.

Original array: [0 1 2 3 4 5 6 7 8 9]
After assigning 99 to slice [2:5]: [ 0  1 99 99 99  5  6  7  8  9]

Original array: [0 1 2 3 4 5 6 7 8 9]
After assigning -1 to even numbers: [-1  1 -1  3 -1  5 -1  7 -1  9]

요약

이 실습에서는 NumPy 배열 인덱싱의 필수 기법을 배웠습니다. Python 리스트와 유사하게 1D 배열에서 기본적인 단일 요소 접근 및 슬라이싱으로 시작했습니다. 그런 다음 다차원 배열 인덱싱으로 진행하여 특정 요소와 하위 배열을 선택했습니다. 마지막으로 정수 및 불리언 배열을 사용한 고급 인덱싱을 탐색했으며, 이러한 강력한 선택 방법을 사용하여 배열 내의 데이터를 수정하는 방법을 배웠습니다. 이러한 기술은 NumPy 를 사용한 Python 에서의 효과적인 데이터 조작 및 분석에 필수적입니다.