Post

[Python] Numpy (1)


[Python] Numpy

  • 본 포스팅은 Numpy 라이브러리의 Array 생성과 인덱싱 그리고 함수에 관하여 다룹니다.
  • 기본 Array 생성 및 인덱스
  • Numpy 함수
    • np.zeros() / np.ones() / np.full() / np.eye()
    • np.arange() / np.linspace()
    • np.random.random / np.random.rand / np.random.randint
  • Array 인덱싱
  • 다차원 배열 생성 및 인덱싱

Hello! Numpy

Numpy는 파이썬이 계산과학분야에 이용될 때 핵심 역할을 하는 라이브러리 중 하나이다.
그리고 고성능의 다차원 배열 객체와 이를 다룰 도구를 제공한다.

1
import numpy as np

Array(배열) 기본 생성 및 인덱스

  • Numpy배열은 동일한 자료형을 가지는 값들이 격자판 형태로 있는 것이다.
  • 각각의 값들은 튜플 형태로 색인된다.
  • rank는 배열이 몇 차원인지에 관하여 설명한다.
  • shape는 각 차원의 크기를 알려주는 정수들이 모인 튜플이다.

파이썬의 리스트를 중첩해 Numpy배열을 초기화 시킬 수 있으며, 대괄호를 통해 각 요소에 접근할 수 있다.
먼저 rank = 1인 배열 생성은 다음과 같다.

1

1
a = np.array([1, 2, 3])

아래와 같이 인덱스를 이용해 특정값을 배열의 특정값을 가져올 수 있으며,
자주사용하는 shape를 이용해 차원의 크기를 알 수 있다.
또한, dtype을 통해 배열의 일관된 자료형을 확인할 수 있다.

1
2
3
4
print(type(a))
print(a.dtype)
print(a.shape)
print(a[0], a[1], a[2])
1
2
3
4
<class 'numpy.ndarray'>
int32
(3,)
5 2 3

배열의 특정 요소를 변경하는 방법은 다음과 같다.

1
2
a[0] = 5
print(a) # 기존의 a[0] = 1이 5로 변경되었다.
1
[5 2 3]

또한, 다음과 같이 list를 이용하여 rank = 2의 배열을 생성할 수 있다.

2

1
2
b = np.array([[1, 2, 3], [4, 5, 6]])
print(b.shape)
1
(2, 3)

그리고 배열에서 각 특정 원소를 가져오고 싶을 때는 다음과 같이
배열명[m, n] / 배열명[m][n] 명령어를 이용하면된다.

1
2
3
4
# [row index, col index]
print(b[0])
print(b[0, 0], b[0, 1], b[1, 2])
print(b[0][0], b[0][1], b[1][2])
1
2
3
[1 2 3]
1 2 6
1 2 6

Numpy 함수

  • np.zeros()
    • 모든 값이 0인 배열을 생성하는 함수이다.
1
np.zeros((2,2))
1
2
array([[0., 0.],
       [0., 0.]])
  • np.ones()
    • 모든 값이 1인 배열을 생성하는 함수이다.
1
np.ones((2,3))
1
2
array([[1., 1., 1.],
       [1., 1., 1.]])
  • np.full()
    • 모든 값이 특정 상수로 이루어진 배열을 생성하는 함수이다.
1
np.full((3,4), 5)
1
2
3
array([[5, 5, 5, 5],
       [5, 5, 5, 5],
       [5, 5, 5, 5]])
  • np.eye()
    • 단위행렬생성 함수이다.
    • 다른 함수처럼 row와 col을 tuple형태로 제시하지 않는다.
1
np.eye(3)
1
2
3
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])
1
np.eye(4)
1
2
3
4
array([[1., 0., 0., 0.],
       [0., 1., 0., 0.],
       [0., 0., 1., 0.],
       [0., 0., 0., 1.]])
  • np.random.random()
    • 임의의 값으로 이루어진 배열을 생성하는 함수이다.
1
np.random.random((3,2))
1
2
3
array([[0.40011376, 0.3103186 ],
       [0.02167807, 0.81689155],
       [0.6690935 , 0.7824655 ]])
  • np.linspace( start, stop,[,개수])
    • 특정 구간에서 출력할 데이터의 개수를 설정하여, 동일한 간격으로 숫자를 출력할 때 사용하는 함수이다.
    • linspace는 stop 값을 반드시 선언 해주어야한다.
    • 또한, linspace의 개수 default 값은 50이다.
1
np.linspace(1, 10, 10)
1
array([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10.])
1
np.linspace(1, 10, 20)
1
2
3
4
array([ 1.        ,  1.47368421,  1.94736842,  2.42105263,  2.89473684,
        3.36842105,  3.84210526,  4.31578947,  4.78947368,  5.26315789,
        5.73684211,  6.21052632,  6.68421053,  7.15789474,  7.63157895,
        8.10526316,  8.57894737,  9.05263158,  9.52631579, 10.        ])
1
2
3
print(np.linspace(1, 10))
print()
print('length :', len(np.linspace(1, 10)))
1
2
3
4
5
6
7
8
9
10
11
[ 1.          1.18367347  1.36734694  1.55102041  1.73469388  1.91836735
  2.10204082  2.28571429  2.46938776  2.65306122  2.83673469  3.02040816
  3.20408163  3.3877551   3.57142857  3.75510204  3.93877551  4.12244898
  4.30612245  4.48979592  4.67346939  4.85714286  5.04081633  5.2244898
  5.40816327  5.59183673  5.7755102   5.95918367  6.14285714  6.32653061
  6.51020408  6.69387755  6.87755102  7.06122449  7.24489796  7.42857143
  7.6122449   7.79591837  7.97959184  8.16326531  8.34693878  8.53061224
  8.71428571  8.89795918  9.08163265  9.26530612  9.44897959  9.63265306
  9.81632653 10.        ]

length : 50
  • np.random.rand()함수
    • random함수는 괄호안 숫자의 개수에 따라 적합한 numpy배열로 0 이상 1 미만의 임의의 값을 출력한다
1
2
# 1 rank
np.random.rand(5)
1
array([0.83509747, 0.45202962, 0.76035652, 0.80089514, 0.35270596])
1
2
# 2 rank
np.random.rand(5,6)
1
2
3
4
5
6
7
8
9
10
array([[0.09307308, 0.01340912, 0.89411922, 0.98070299, 0.08865148,
        0.38891428],
       [0.51862623, 0.73494605, 0.39790766, 0.29568049, 0.70303107,
        0.68930971],
       [0.30749667, 0.54478526, 0.92842788, 0.84283713, 0.27613517,
        0.01890928],
       [0.40991456, 0.08128661, 0.99417833, 0.28241801, 0.02359437,
        0.5860523 ],
       [0.41084456, 0.81534389, 0.93910881, 0.9400318 , 0.74743395,
        0.75802576]])
1
2
# 3 rank
np.random.rand(5,6,3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
array([[[0.70353089, 0.5015733 , 0.43467236],
        [0.14290471, 0.23652241, 0.10829044],
        [0.07901934, 0.1328511 , 0.21543321],
        [0.71749059, 0.27190494, 0.5087288 ],
        [0.1061441 , 0.50445   , 0.02263788],
        [0.79832255, 0.78655425, 0.00152723]],

       [[0.23214754, 0.60957154, 0.00683504],
        [0.3914287 , 0.81400845, 0.48528567],
        [0.61334068, 0.75641834, 0.47109568],
        [0.09229707, 0.96248413, 0.72330495],
        [0.70400407, 0.99381591, 0.968956  ],
        [0.06554547, 0.74257802, 0.5689088 ]],

       [[0.01197237, 0.79521737, 0.75573127],
        [0.52018312, 0.68750849, 0.87864685],
        [0.38971102, 0.33263129, 0.926711  ],
        [0.7082347 , 0.92576004, 0.12241113],
        [0.20109423, 0.86172776, 0.08501675],
        [0.71751167, 0.8864172 , 0.52937989]],

       [[0.96917761, 0.87516545, 0.76473274],
        [0.73326644, 0.27203604, 0.78502877],
        [0.58329292, 0.84605291, 0.68032686],
        [0.71879373, 0.81793146, 0.31961365],
        [0.12283249, 0.16944791, 0.86763295],
        [0.72352426, 0.26524936, 0.00220721]],

       [[0.92789659, 0.41765385, 0.56536246],
        [0.63139798, 0.06236128, 0.66015754],
        [0.31893659, 0.87215569, 0.14323517],
        [0.5204466 , 0.80858952, 0.56070511],
        [0.77047589, 0.89331092, 0.64084898],
        [0.27088515, 0.22454753, 0.59351674]]])
  • np.random.randint([start,] stop [,size=(m, n))
    • random.randint함수는 지정한 값 사이의 정수를 랜덤으로 호출한다.
      (start 값의 default값은 0이며, size 값의 default값은 1(1 row, 1 col)이다.)
      + stop값 미만의 정수만을 호출한다.
1
np.random.randint(1, 2, size = (3, 4)) # 1이상 2미만이므로 1만 출력된다.
1
2
3
array([[1, 1, 1, 1],
       [1, 1, 1, 1],
       [1, 1, 1, 1]])
1
np.random.randint(1, 2) # 1이상 2미만이므로 1만 출력된다.
1
1
1
np.random.randint(2, size = (7, 3)) # 2미만 값인 0과 1이 랜덤으로 배치된다
1
2
3
4
5
6
7
array([[1, 0, 0],
       [0, 1, 0],
       [1, 1, 0],
       [0, 0, 0],
       [1, 1, 1],
       [1, 1, 1],
       [1, 0, 0]])

배열 인덱싱

  • 아래와 같은 요소를 가지는 rank가 2이고 크기가 (3,4)인 배열을 만들자

3

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

c
1
2
3
array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])

슬라이싱을 이용하여 1,2행과 1,2열로 이루어진 부분배열을 만들면 다음과 같다.

  • 전자의 :2는 row 인덱스 0부터 1를 의미하며,
  • 후자의 1:3은 col 인덱스 1부터 2를 의미한다.

4

1
2
d = c[:2, 1:3]
d
1
2
array([[2, 3],
       [6, 7]])

이제는 다음과 같이 arange함수를 이용하여 크기가 큰 행렬을 만들고 인덱싱해보자
( 다음의 경우는 위에서 설명하지 않은 배열 생성법이다. )

5

  • 설명하기전에 arange 함수란?
    • 기본형식 : numpy.arrange([start,]stop,[step,]dtype = None)
    • arange함수는 반 열린 구간인 [strat,stop)에서 step의 크기만큼 일정하게 떨어져 있는 숫자들을 array형태로 반환해주는 함수이다.
    • stop 인자의 값은 반드시 전달되어야 하지만, start와 step은 반드시 전달될 필요가 없다.
      (start값이 없으면 0을 기본값으로 가짐, > step값이 없으면 1을 기본값으로 가짐)
    • dtype값이 주어지지 않는 경우 전달된 다른 매개변수로 부터 자료형을 추정하여 사용한다.
1
2
3
4
5
6
7
8
9
10
11
# [STEP 1]
# 배열에 들어갈 숫자를 numpy의 arange함수를 이용하여 value들을 선언한다. 
# 0부터 100까지 공차가 2인 숫자들을 배열로가지게 된다.
arr_test = np.arange(0, 100, 2)

# [STEP 2]
# 배열의 크기를 지정해준다.
arr_test.shape = (10, 5)

# 출력
print(arr_test)
1
2
3
4
5
6
7
8
9
10
[[ 0  2  4  6  8]
 [10 12 14 16 18]
 [20 22 24 26 28]
 [30 32 34 36 38]
 [40 42 44 46 48]
 [50 52 54 56 58]
 [60 62 64 66 68]
 [70 72 74 76 78]
 [80 82 84 86 88]
 [90 92 94 96 98]]

다음과 같이 :을 이용하여 가지각색의 행을 추출하여 출력할 수있다.

다음의 경우는 (인덱스기준)0행과 1행을 출력한다.

6

1
arr_test[:2]
1
2
array([[ 0,  2,  4,  6,  8],
       [10, 12, 14, 16, 18]])

다음과 같이 :연속으로 2번 사용되었을 때이다.
이 경우 (인덱스기준)0행부터 2씩 건너뛰면서 해당하는 행을 모두 출력한다.

7

1
arr_test[::2]
1
2
3
4
5
array([[ 0,  2,  4,  6,  8],
       [20, 22, 24, 26, 28],
       [40, 42, 44, 46, 48],
       [60, 62, 64, 66, 68],
       [80, 82, 84, 86, 88]])

하지만, 여기서 ::사이에 ,를 추가해주면 또 말이 다르다.
아래의 경우 전자의 `:`은 전체 row를 가져온다는 의미이고, 동시에 후자의 `:`은 (인덱스기준)0, 1 col을 가져온다는 의미이다.
개인적으로 배열을 처음접했을 때 이런 부분때문에 머리가 지끈거렸다.

8

1
arr_test[:,:2]
1
2
3
4
5
6
7
8
9
10
array([[ 0,  2],
       [10, 12],
       [20, 22],
       [30, 32],
       [40, 42],
       [50, 52],
       [60, 62],
       [70, 72],
       [80, 82],
       [90, 92]])

: :는 다음과 같이 선행제한을 걸어서 사용할 수도 있다.
첫번째 경우는 1행부터 2단위씩 끊은 행들(즉 1, 3, 5, 7, 9)을 가져온 것이며,
두번쨰 경우는 (인덱스기준)1행부터 끝까지 가져오며, 동시에 (인덱스기준)0과 1열까지만 가져온다.

10

1
arr_test[1::2]
1
2
3
4
5
array([[10, 12, 14, 16, 18],
       [30, 32, 34, 36, 38],
       [50, 52, 54, 56, 58],
       [70, 72, 74, 76, 78],
       [90, 92, 94, 96, 98]])
1
arr_test[1:, :2]
1
2
3
4
5
6
7
8
9
array([[10, 12],
       [20, 22],
       [30, 32],
       [40, 42],
       [50, 52],
       [60, 62],
       [70, 72],
       [80, 82],
       [90, 92]])

좀 더 살펴보자
:쓰던 안쓰던 같은 경우가 존재한다. 그 경우는 다음과같다.
두 표현 모두 2행의 모든 열을 출력한다.

9

하지만,`[ :, 2]`는 되지만 `[ , 2]`의 경우는 오류가 발생한다.
다시 살펴보니, 같이 참조한 블로그의 설명에 따르면 주피터가 멍청해서 그렇다한다. 이에 대해 나는 공감하였다. https://m.blog.naver.com/jjys9047/221566766122

1
arr_test[2, :]
1
array([20, 22, 24, 26, 28])
1
arr_test[2, ]
1
array([20, 22, 24, 26, 28])

이처럼 배열의 인덱싱에서 :,의 역할은 매우 중요하다는 것을 알 수 있다.
하지만, 나는 나중에 차원이 높아지는 배열을 만나고 :,가 하나의 리스트안에서 난무하는 것을 보게되면 정말 머리가 띵해짐을 느꼈었다.


다차원 배열 생성 및 인덱싱

  • 다차원 배열 중 3차원 배열에 관하여 생성하고 인덱싱해보자
  • 생성은 다음과 같은 형태로 진행한다.

11

1
2
3
# 0~17까지의 value를 생성하고, 이를 순차적으로 3차원 배열에 대입
arr_test = np.arange(18).reshape(3, 2, 3)
arr_test
1
2
3
4
5
6
7
8
array([[[ 0,  1,  2],
        [ 3,  4,  5]],

       [[ 6,  7,  8],
        [ 9, 10, 11]],

       [[12, 13, 14],
        [15, 16, 17]]])

3차원 배열의 인덱싱은 기본적으로 2차원 배열과 동일하다.

  • 기본적으로 3차원 배열은 [m, n, k]로 적용되고, m은 말보다 위의 그림으로 설명하는 것이 더 이해하기 좋을 것이다.
    나머지, n,k는 이전 2차원 배열과 동일하다.
1
arr_test[0, 1, 2] # m=0이므로, 위의 그림에서 m1 리스트를 가져온 것을 알 수 있다.
1
5
1
arr_test[1, :, :] # m=1이므로, 위의 그림에서 m2 리스트를 가져온 것을 알 수 있다.
1
2
array([[ 6,  7,  8],
       [ 9, 10, 11]])

특정 위치의 배열을 출력하고 할 때는 2차원 배열과 같이, 원하는 m,n,k만을 입력하고,
나머지 부분에는 :: 혹은 ...을 이용하여 모든 값을 불러오겠다는 의미로 사용할 수 있다.

1
arr_test[1, ...]
1
2
array([[ 6,  7,  8],
       [ 9, 10, 11]])
1
arr_test[1, ]  # [1, ,] 이렇게 선언하면 오류가 발생한다.
1
2
array([[ 6,  7,  8],
       [ 9, 10, 11]])
1
arr_test[1, ::]
1
2
array([[ 6,  7,  8],
       [ 9, 10, 11]])

References

  • http://aikorea.org/cs231n/python-numpy-tutorial/#numpy-arrays
  • https://m.blog.naver.com/jjys9047/221566766122
  • https://numpy.org/doc/stable/reference/generated/numpy.arange.html
This post is licensed under CC BY 4.0 by the author.