본문 바로가기
파이썬/Numpy(넘파이)

[NumPy] 2. 넘파이 연산, 축, 배열 출력

by 쿠킷리스트 2021. 10. 12.

학습내용


#1 : 배열 출력하기(Printing Arrays)

 배열을 출력할 때, NumPy는 중첩된 배열과 비슷한 방법으로, 다음의 레이아웃을 따라 출력된다. 1차원은 배열처럼 출력되고, 2차원은 매트릭스처럼, 3차원은 매트릭스의 리스트처럼 출력된다.

  • 마지막 축은 왼쪽에서 오른쪽으로 출력.
  • 두번째에서 마지막은 위에서 아래로 출력.
  • 나머지는 위에서 아래로 출력되며, 각기의 슬라이스는 비어있는 라인에 의해 다음 슬라이스와 구분.
#1차원
a = np.arange(6)
print(a)
#[0 1 2 3 4 5]

#2차원
b = np.arange(12).reshape(2,6)
print(b)
# [[ 0  1  2  3  4  5]
#  [ 6  7  8  9 10 11]]

#3차원
c = np.arange(24).reshape(2,3,4)
print(c)
# [[[ 0  1  2  3]
#   [ 4  5  6  7]
#   [ 8  9 10 11]]

#  [[12 13 14 15]
#   [16 17 18 19]
#   [20 21 22 23]]]

 

 만약 배열이 프린트하기에 너무 크다면 NumPy는 자동적으로 중간 부분을 생략하고 처음과 끝부분 일부분만 출력한다. np.ndarray.reshpae()을 이용하면 데이터는 그대로 유지한 채 차원을 쉽게 변경할 수 있다.

print(np.arange(10000))
#[   0    1    2 ... 9997 9998 9999]

print(np.arange(10000).reshape(100,100))
# [[   0    1    2 ...   97   98   99]
#  [ 100  101  102 ...  197  198  199]
#  [ 200  201  202 ...  297  298  299]
#  ...
#  [9700 9701 9702 ... 9797 9798 9799]
#  [9800 9801 9802 ... 9897 9898 9899]
#  [9900 9901 9902 ... 9997 9998 9999]]

#2 : 기본 연산(Basic Operations)

 NumPy에서 배열의 산술 연산자는 요소별(elementwise)로 적용된다. 

a = np.array([20,30,40,50])
b = np.arange(4)
c = a - b
c
#array([20, 29, 38, 47])
b**2
# array([0, 1, 4, 9])
a < 35
# array([ True,  True, False, False])
10 * np.sin(a)
# array([ 9.12945251, -9.88031624,  7.4511316 , -2.62374854])

1) 곱하기 연산

다른 matrix 언어와는 다르게 product 연산자 *는 NumPy에서 elementwise로 계산한다. Matrix product는 @ 연산자를 사용하여 수행하거나 dot 함수나 method를 사용하여 수행할 수 있다.

  • * : 각각의 원소끼리 곱셈(Elementwise product, Hadamard product)
  • @, .dot() : 행렬 곱셈(Matrix product)
A = np.array([[1,1],[0,1]])
B = np.array([[2,0],[3,4]])
print(A) 
# [[1 1]
#  [0 1]]
print(B)
# [[2 0]
#  [3 4]]

A*B # elementwise product
# array([[2, 0],
#        [0, 4]])

A@B # matrix product
# array([[5, 4],
#        [3, 4]])

A.dot(B) # another matrix product
# array([[5, 4],
#        [3, 4]])

2) *=, += 연산

*=, +=과 같은 몇몇 연산자는 배열을 새로 생성하지 않고 이미 있는 배열을 수정

rg = np.random.default_rng(1) # 0~1사이의 랜덤값

a = np.ones((2,3), dtype=int)
a *= 3
a
# array([[3, 3, 3],
#        [3, 3, 3]])

b = rg.random((2,3))
b
# array([[0.51182162, 0.9504637 , 0.14415961],
#        [0.94864945, 0.31183145, 0.42332645]])

b += a # b = b+a
b
# array([[3.51182162, 3.9504637 , 3.14415961],
#        [3.94864945, 3.31183145, 3.42332645]])

a += b # Error
  • a는 정수 값 만을 담고 있고, 틀을 유지한 채로 수정해야하기에 소수값을 넣어줄 수 없다.
  • 새로운 메모리에 할당하는 경우 수정이 가능하다.
c = a+b
c
# array([[3.51182162, 3.9504637 , 3.14415961],
#        [3.94864945, 3.31183145, 3.42332645]])

3) .dtype의 변경

수치연산을 할 때 각각의 .dtype이 다르면 타입이 큰쪽(int < float < complex)으로 자동으로 변경.

#정수(int)와 소수(float)
a = np.ones(5, dtype=np.int32) #정수형
b = np.linspace(0, np.pi, 5) #pi가 들어가면서 소수형
print(b.dtype.name)
#float64

c = a+b
print(c)
# [1.         1.78539816 2.57079633 3.35619449 4.14159265]
print(c.dtype.name)
# float64

#복소수(complex)
d = np.exp(c*3j) #exp는 자연상수의 n제곱하라, j는 복소수
print(d)
# [-0.9899925 +0.14112001j  0.60024349-0.79981732j  0.14112001+0.9899925j
#  -0.79981732-0.60024349j  0.9899925 -0.14112001j]
print(d.dtype.name)
# complex128

4) 단항 연산자

배열에 있는 요소들의 합을 계산하는 것과 같이 많은 단항연산자들은 ndarray class 메소드로 구현되어 있다.

대표적인 단항 연산자
.sum() 모든 요소의 합
.min() 모든 요소 중 최소값
.max() 모든 요소 중 최대값
.argmax() 모든 요소 중 최대값의 인덱스
.argmin() 모든 요소 중 최소값의 인덱스
.cumsum() 모든 요소의 누적합

그림으로 표현한 단항 연산자

rg = np.random.default_rng(1) # 0~1사이의 랜덤값

a = rg.random((2, 3))
a
# array([[0.51182162, 0.9504637 , 0.14415961],
#        [0.94864945, 0.31183145, 0.42332645]])

#아래의 연산들은 차원 구분 없이 연산된다.
a.sum()
# 3.290252281866131
a.min()
# 0.14415961271963373
a.max()
# 0.9504636963259353
a.argmax()
#1
a.argmin()
#2
a.cumsum() #누적합
# array([0.51182162, 1.46228532, 1.60644493, 2.55509438, 2.86692583,
#        3.29025228])

- .cumsum()은 누적합을 계산하기에 수치의 증감을 파악하기에 유리하다.


4-1) 단항 연산자 + 축

기본적으로 단항 연산자들은 모양에 관계없이 배열에 숫자 리스트처럼 적용된다. 그러나 축을 parameter로 사용하면 연산자를 배열의 특정 축을 기준으로 적용할 수 있다. axis = 0은 shape에서 첫번째부터 순서대로 할당.

b = np.arange(12).reshape(3,4)
b
# array([[ 0,  1,  2,  3],
#        [ 4,  5,  6,  7],
#        [ 8,  9, 10, 11]])
b.sum(axis=0) # sum of each column(열방향)
#array([12, 15, 18, 21])

b.min(axis=1) # min of each row(행방향)
# array([0, 4, 8])

b.cumsum(axis=0) #열방향으로 누적합
# array([[ 0,  1,  2,  3],
#        [ 4,  6,  8, 10],
#        [12, 15, 18, 21]])

b.cumsum(axis=1) #행방향으로 누적합
# array([[ 0,  1,  3,  6],
#        [ 4,  9, 15, 22],
#        [ 8, 17, 27, 38]])

5) 범용 함수(Universal Functions)

NumPy는 sin, co, exp와 같은 수학적 함수들을 제공한다. NumPy에서 이러한 함수들을 ufunc(universal function)으로 부른다. NumPy에서는 이러한 함수들은 배열에서 elementwise로 작동하며 새로운 배열 결과를 만든다.

B = np.arange(3)
B #array([0, 1, 2])

np.exp(B) # y=e^x, 자연상수에 배열을 제곱
# array([1.        , 2.71828183, 7.3890561 ])

np.sqrt(B) # y=sqrt(x), 배열에 루트를 씌우는것
# array([0.        , 1.        , 1.41421356])

댓글