[Python] 데이터 사이언스 스쿨 - 3.1 넘파이 배열

Updated:

데이터 사이언스 스쿨 자료를 토대로 공부한 내용입니다.

실습과정에서 필요에 따라 내용의 누락 및 추가, 수정사항이 있습니다.


3.1 넘파이 배열

1차원 배열 생성

import numpy as np
k1 = np.array([0,1,2,3,4,5,6,7,8,9])
print(k1)
type(k1)
[0 1 2 3 4 5 6 7 8 9]





numpy.ndarray
  • numpy 패키지는 파이썬에서 특히 데이터를 다룬다면 필수적인 패키지이다.

  • np.array()로 넘파이 배열을 생성할 수 있으며 type은 numpy.ndarray이다.

벡터화 연산

# 리스트
data = [0,1,2,3,4,5,6,7,8,9]

# 베열
x = np.array(data)

# 리스트와 달리 배열은 벡터화 연산이 가능
print(data * 2)
print(x * 2)

# 리스트로 같은 연산
lst = []
for i in data:
    lst.append(i*2)
    
print(lst)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[ 0  2  4  6  8 10 12 14 16 18]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
  • 넘파이 배열의 큰 특징 중 하나는 벡터화 연산이 가능하다는 점이다.

  • 위 예제에서 리스트와 넘파이 배열을 생성한 후 똑같이 2를 곱하였을 때 리스트는 같은 데이터가 2배로 늘어났다.

  • 반면에 넘파이 배열은 각 숫자에 2가 곱해진 값으로 나타난다.

  • 리스트로 같은 결과를 출력하려면 for문을 이용해서 출력하여는데 그에 비해 넘파이 배열은 훨씬 편하게 작업할 수 있다.

2차원 배열

# 2 x 3 행렬
m1 = np.array( [ [0,1,2],
                 [3,4,5] ])
print(m1)

# 행의 갯수
print("행의 갯수:", len(m1))

# 열의 갯수
print("열의 갯수:", len(m1[0]))
[[0 1 2]
 [3 4 5]]
행의 갯수: 2
열의 갯수: 3
  • 넘파이는 1차원 배열외에도 2차원, 3차원 등 다차원 배열 생성이 가능하다.

  • 바깥쪽 리스트의 길이가 행의 갯수가 되며, 안쪽 리스트의 길이는 열의 갯수가 된다.

연습문제 1

넘파이를 사용하여 다음과 같은 행렬을 만든다.

10 20 30 40
50 60 70 80
# 2 x 4 행렬
k2 = np.array( [[10,20,30,40],
                [50,60,70,80]])
print(k2)
[[10 20 30 40]
 [50 60 70 80]]

3차원 배열

# 2 x 3 x 4 행렬
k3 = np.array([[[1,2,3,4],
                [5,6,7,8],
                [10,11,12,13]],
               
               [[14,15,16,17],
                [18,19,20,21],
                [22,23,24,25]]])
print(k3)

print("-"*20)

# 차원, 행, 열의 갯수
print("차원:", len(k3))
print("행:", len(k3[0]))
print("열:", len(k3[0][0]))
[[[ 1  2  3  4]
  [ 5  6  7  8]
  [10 11 12 13]]

 [[14 15 16 17]
  [18 19 20 21]
  [22 23 24 25]]]
--------------------
차원: 2
행: 3
열: 4
  • 3 x 4로 이루어진 2개의 행렬을 묶어 2 x 3 x 4 행렬을 만들었다.

  • 3차원 배열은 (차원) x (행) x (열)로 구성된다.

  • 차원은 깊이라는 표현으로도 사용한다.

배열의 차원과 크기

# 1차원
a1 = np.array([1,2,3])

# 2차원
a2 = np.array([[0,1,2],
               [3,4,5]])

# 3차원
a3 = np.array([[[1,2,3,4],
                [5,6,7,8],
                [10,11,12,13]],
               
               [[14,15,16,17],
                [18,19,20,21],
                [22,23,24,25]]])

print("차원:", a1.ndim, "크기:", a1.shape)
print("차원:", a2.ndim, "크기:", a2.shape)
print("차원:", a3.ndim, "크기:", a3.shape)
차원: 1 크기: (3,)
차원: 2 크기: (2, 3)
차원: 3 크기: (2, 3, 4)
  • 앞서 len()으로 하나씩 차원, 행, 열의 갯수를 구하였다.

  • ndim 속성을 사용하면 배열의 차원을 알 수 있고, shape 속성을 사용하면 크기를 알 수 있다.

배열의 인덱싱

1차원 배열의 인덱싱

b1 = np.array([0,1,2,3,4])

print(b1[1])
print(b1[-1])
1
4
  • 1차원 배열의 인덱싱은 리스트와 동일하다.

2차원 배열의 인덱싱

b2 = np.array([[0,1,2],
               [3,4,5]])

print(b2[0,0])
print(b2[-1,-1])
0
5
  • 2차원 배열의 인덱싱은 콤마를 이용해서 앞에는 행, 뒤에는 열에 대해 인덱싱한다.

3차원 배열의 인덱싱

b3 = np.array([[[1,2,3,4],
                [5,6,7,8],
                [10,11,12,13]],
               
               [[14,15,16,17],
                [18,19,20,21],
                [22,23,24,25]]])

print(b3[1,1,1])
print(b3[1,2,3])
19
25
  • 3차원 배열의 인덱싱은 2차원 배열의 인덱싱에서 콤마를 추가해 각각 차원, 행, 열에 대해 인덱싱한다.

배열 슬라이싱

k = np.array([[0,1,2,3],
              [4,5,6,7]])

# 두번째 행 전체
print(k[1, :])

# 첫번째 열 전체
print(k[:,0])

# 첫번째 행의 두번째 열부터 끝까지
print(k[0,1:])

# 처음 2개의 행과 열
print(k[:2, :2])
[4 5 6 7]
[0 4]
[1 2 3]
[[0 1]
 [4 5]]
  • 배열의 슬라이싱은 2차원 배열 기준으로 [행 슬라이싱, 열 슬라이싱] 방식으로 수행한다.

연습문제 2

다음 행렬과 같은 행렬이 있다.

m = np.array([[ 0,  1,  2,  3,  4],
            [ 5,  6,  7,  8,  9],
            [10, 11, 12, 13, 14]])
  1. 이 행렬에서 값 7 을 인덱싱한다.

  2. 이 행렬에서 값 14 을 인덱싱한다.

  3. 이 행렬에서 배열 [6, 7] 을 슬라이싱한다.

  4. 이 행렬에서 배열 [7, 12] 을 슬라이싱한다.

  5. 이 행렬에서 배열 [[3, 4], [8, 9]] 을 슬라이싱한다.

m = np.array([[ 0,  1,  2,  3,  4],
            [ 5,  6,  7,  8,  9],
            [10, 11, 12, 13, 14]])

print(m[1,2])
print(m[-1,-1])
print(m[1,1:3])
print(m[1:,2])
print(m[:2,-2:])
7
14
[6 7]
[ 7 12]
[[3 4]
 [8 9]]

배열 인덱싱 (fancy indexing)

넘파이 배열의 강력한 기능 중 하나는 팬시 인덱싱(fancy indexing)이라고도 부르는 배열 인덱싱(array indexing) 방법이다.

단순하게 생각하면 배열에 다른 배열을 위치 정보로 사용하는 방법이다.

배열 인덱싱은 Boolean 배열과 정수 배열을 위치 정보로 사용 가능하다.

  • Boolean 배열을 위치 정보로 사용할 경우 Boolean 배열과 원래 배열의 크기가 같아야한다.

  • 정수 배열을 위치 정보로 사용할 경우 원래 배열과 크기가 달라도 상관없다.

불린 배열 인덱싱

a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
idx = np.array([True, False, True, False, True, False, True, False, True, False])

a[idx]
array([0, 2, 4, 6, 8])
# 위 과정을 단순하게
a[a % 2 == 0]
array([0, 2, 4, 6, 8])
  • 위 예시와 같이 True, False로 나타나는 Boolean 배열을 이용하여 원래 배열에서 True인 배열만 추출할 수 있다.

정수 배열 인덱싱

a = np.array([11, 22, 33, 44, 55, 66, 77, 88, 99])
idx = np.array([0, 2, 4, 6, 8]) # 홀수 원소

a[idx]
array([11, 33, 55, 77, 99])
  • 정수 배열 인덱싱은 원하는 위치 정보(인덱스 정보) 배열을 입력하여 원래 배열에서 추출할 수 있다.
a = np.array([11, 22, 33, 44, 55, 66, 77, 88, 99])
idx = np.array([0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2])

a[idx]
array([11, 11, 11, 11, 11, 11, 22, 22, 22, 22, 22, 33, 33, 33, 33, 33])
  • 다음과 같이 정수 배열의 크기가 원래 배열의 크기보다 커도 상관없으며 해당 인덱스를 중복해서 추출한다.

다차원 배열

# 2차원 배열
k = np.array([[1, 2, 3, 4],
              [5, 6, 7, 8],
              [9, 10, 11, 12]])

# 모든 행과 2,3열
print(k[:, [False, True, True, False]])

# 열 순서 바꿔 출력
print(k[:,[3,1,2,0]])
[[ 2  3]
 [ 6  7]
 [10 11]]
[[ 4  2  3  1]
 [ 8  6  7  5]
 [12 10 11  9]]
  • 배열 인덱싱은 1차원 배열뿐 아니라 다차원 배열에서도 똑같이 적용 가능하다.

연습문제 3

다음 행렬과 같은 배열이 있다.

x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
             11, 12, 13, 14, 15, 16, 17, 18, 19, 20])
  1. 이 배열에서 3의 배수를 찾아라.

  2. 이 배열에서 4로 나누면 1이 남는 수를 찾아라.

  3. 이 배열에서 3으로 나누면 나누어지고 4로 나누면 1이 남는 수를 찾아라.

x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20])

# 3의 배수
print(x[x % 3 == 0])

# 4의 배수 + 1
print(x[x % 4 == 1])

# 3의 배수 & 4의 배수 + 1
print( x[ (x % 3 == 0) & (x % 4 == 1) ] )
[ 3  6  9 12 15 18]
[ 1  5  9 13 17]
[9]
  • 한 가지 자주하던 실수가 여러 조건을 and, or로 결합해서 줄 떄 각 조건은 반드시 소괄호( )로 묶어야 한다.

Leave a comment