06wk-2: Numpy (2)

Author

최규빈

Published

April 12, 2023

강의영상

youtube: https://youtube.com/playlist?list=PLQqh36zP38-z-L_OmVbSF6lmFbS9IfOsI

import

import numpy as np

넘파이 공부 4단계: 축

np.concatenate

- 1차원: concat의 기본예제 (쓸모 없어보임)

a= np.array([1,2,3]) 
b= -a 
np.concatenate([a,b])
array([ 1,  2,  3, -1, -2, -3])
np.array(list(a)+list(b))
array([ 1,  2,  3, -1, -2, -3])

- 2차원: 이건 좀 의미가 있어보임

a = np.array([1,2,3,4]).reshape(2,2)
b = -a 
np.concatenate([a,b])
array([[ 1,  2],
       [ 3,  4],
       [-1, -2],
       [-3, -4]])

만약에 a,b를 좌우로 붙이고 싶다면? axis=1이라고 옵션을 주면 된다.

np.concatenate([a,b],axis=1) 
array([[ 1,  2, -1, -2],
       [ 3,  4, -3, -4]])
  • axis=1의 의미는 무엇일까?

- axis=1 의 의미를 파악하기 전에, axis=1만 가능한것인지 알아보자.

(시도1)

np.concatenate([a,b],axis=0)
# np.concatenate([a,b]) 와 같음 
# np.concatenate([a,b])은 np.concatenate([a,b],axis=0)의 생략버전이라 유추가능
array([[ 1,  2],
       [ 3,  4],
       [-1, -2],
       [-3, -4]])
  • axis=0 도 가능!!

(시도2)

np.concatenate([a,b],axis=2)
# 에러가 난다. 
AxisError: axis 2 is out of bounds for array of dimension 2
  • axis=1은 불가능!!

- axis의 의미를 알아보자.

a= np.array([1,2,3,4,5,6]).reshape(3,2)
b= -a 

(예시1)

a.shape,b.shape, np.concatenate([a,b],axis=0).shape
((3, 2), (3, 2), (6, 2))
  • 관찰: (3,2) concat (3,2) -> (6,2) // 첫번째 숫자가 바뀜 <== axis=0

(예시2)

a.shape,b.shape, np.concatenate([a,b],axis=1).shape
((3, 2), (3, 2), (3, 4))
  • 관찰: (3,2) concat (3,2) -> (3,4) // 두번째 숫자가 바뀜 <== axis=1

(예시3)

a= np.arange(24).reshape(2,3,4) 
b= -a 
a.shape,b.shape,np.concatenate([a,b],axis=0).shape
((2, 3, 4), (2, 3, 4), (4, 3, 4))
  • 유추: (2,3,4) concat (2,3,4) -> (4,3,4) // 첫번째 숫자가 바뀔 것 같았는데 실제로 그러함 <== axis=0

(예시4)

a.shape,b.shape,np.concatenate([a,b],axis=1).shape
((2, 3, 4), (2, 3, 4), (2, 6, 4))
  • (2,3,4) concat (2,3,4) -> (2,6,4) // 두번째 숫자가 바뀜 <== axis=1

(예시5)

a.shape,b.shape,np.concatenate([a,b],axis=2).shape
((2, 3, 4), (2, 3, 4), (2, 3, 8))
  • (2,3,4) concat (2,3,4) -> (2,3,8) // 세번째 숫자가 바뀜 <== axis=2

(예시5)

a.shape,b.shape,np.concatenate([a,b],axis=-1).shape
((2, 3, 4), (2, 3, 4), (2, 3, 8))
  • (2,3,4) concat (2,3,4) -> (2,3,8) // 마지막 숫자가 바뀜 <== axis=-1

(예시6)

a.shape,b.shape,np.concatenate([a,b],axis=-2).shape
((2, 3, 4), (2, 3, 4), (2, 6, 4))
  • (2,3,4) concat (2,3,4) -> (2,6,4) // 마지막에서 두번째 숫자가 바뀜 <== axis=-2

(예시7)

a.shape,b.shape,np.concatenate([a,b],axis=-3).shape
((2, 3, 4), (2, 3, 4), (4, 3, 4))
  • (2,3,4) concat (2,3,4) -> (4,3,4) // 마지막에서 세번째 숫자가 바뀜 <== axis=-3

(예시8)

a.shape,b.shape,np.concatenate([a,b],axis=-4).shape
AxisError: axis -4 is out of bounds for array of dimension 3
  • (2,3,4) concat (2,3,4) -> ??? // 마지막에서 네번째 숫자는 없어서 에러남 <== axis=-4

(예시9)

a.shape,b.shape,np.concatenate([a,b],axis=3).shape
AxisError: axis 3 is out of bounds for array of dimension 3
  • (2,3,4) concat (2,3,4) -> ??? // 네번째 숫자는 없어서 에러남 <== axis=3

np.stack

- 아래의 자료를 관찰하자.

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

- 혹시 a,b를 위아래로 쌓아서 결과를 (2,3) 매트릭스로 만들 수 있을까?

np.concatenate([a,b]) # 실패1
array([ 1,  2,  3, -1, -2, -3])
np.concatenate([a,b],axis=1) # 실패2
AxisError: axis 1 is out of bounds for array of dimension 1

- 실패이유를 분석: (3,) concat (3,) 으로 (2,3) 를 만들려고 해서 불가능했음.

  • 전략: reshape을 이용하여 (3,), (3,) => (1,3), (1,3) 으로 변경후 concat을 하면 가능할듯
np.concatenate([a.reshape(1,3),b.reshape(1,3)],axis=0) # 성공
array([[ 1,  2,  3],
       [-1, -2, -3]])

또 다른 방법!

np.stack([a,b],axis=0)
array([[ 1,  2,  3],
       [-1, -2, -3]])

- 이번에는 a,b를 좌우로 쌓아서 결과를 (3,2) 매트릭스로를 만들어 보자.

np.concatenate([a.reshape(3,1),b.reshape(3,1)],axis=1)
array([[ 1, -1],
       [ 2, -2],
       [ 3, -3]])

또 다른 방법!

np.stack([a,b],axis=1)
array([[ 1, -1],
       [ 2, -2],
       [ 3, -3]])

- 요약: stack은 axis= 위치에 축을 추가하고 concat을 한 것 이라 이해할 수 있다.

강의에서는 하지 않은 예제

a=np.arange(3*4*5).reshape(3,4,5) 
b=-a
a.shape, b.shape
((3, 4, 5), (3, 4, 5))
np.stack([a,b],axis=0).shape # (3,4,5) => (1,3,4,5) // 첫 위치에 축이 추가되고 스택 
(2, 3, 4, 5)
np.stack([a,b],axis=1).shape # (3,4,5) => (3,1,4,5) // 두번째 위치에 축이 추가되고 스택 
(3, 2, 4, 5)
np.stack([a,b],axis=2).shape # (3,4,5) => (3,4,1,5) // 세번째 위치에 축이 추가되고 스택 
(3, 4, 2, 5)
np.stack([a,b],axis=3).shape # (3,4,5) => (3,4,5,1) // 네번째 위치에 축이 추가되고 스택 
(3, 4, 5, 2)
np.stack([a,b],axis=-1).shape # axis=-1 <=> axis=3 
(3, 4, 5, 2)
np.stack([a,b],axis=-2).shape # axis=-2 <=> axis=2
(3, 4, 2, 5)

np.concatenate 는 축의 총 갯수를 유지하면서 결합, np.stack은 축의 갯수를 하나 증가시키면서 결합

sum

- 1차원 array의 sum

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

- 2차원 array일 경우

a= np.arange(4*3).reshape(4,3)
a
array([[ 0,  1,  2],
       [ 3,  4,  5],
       [ 6,  7,  8],
       [ 9, 10, 11]])
a.sum(axis=-1)
array([ 3, 12, 21, 30])
  • 마지막 축이 삭제됨

- 그렇다면?

a.sum(axis=(0,1))
66
  • 첫번째 축과 두번째 축이 삭제됨

- 연습 (강의에서 하지 않은 예제)

a=np.array(range(10)).reshape(5,2) 
a
array([[0, 1],
       [2, 3],
       [4, 5],
       [6, 7],
       [8, 9]])

(문제1) 1열의 합, 2열의 합을 계산하고 싶다면?

(풀이) 차원이 (5,2) => (2,) 로 나와야 한다. (그럼 첫번째 축이 삭제되어야 하네?)

a.sum(axis=0)
array([20, 25])

(문제2) 1행의 합, 2행의 합, … , 5행의 합을 계산하고 싶다면?

(풀이) 차원이 (5,2) => (5,)로 나와야 한다. (그럼 두번째 축이 삭제되어야 하네?)

a.sum(axis=1)
array([ 1,  5,  9, 13, 17])

(문제3) a의 모든원소의 합을 계산하고 싶다면?

(풀이) 차원이 (5,2) => () 로 나와야 한다. (첫번째축, 두번째축이 모두 삭제되어야 하네?)

a.sum(axis=(0,1))
45
a.sum() # 즉 a.sum(axis=(0,1))이 디폴트값임 
45

mean, std, max, min, prod

- mean, std, max, min, prod 모두 sum과 유사한 논리임

- 평균

a = np.arange(3*5*5).reshape(3,5,5)
a
array([[[ 0,  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],
        [35, 36, 37, 38, 39],
        [40, 41, 42, 43, 44],
        [45, 46, 47, 48, 49]],

       [[50, 51, 52, 53, 54],
        [55, 56, 57, 58, 59],
        [60, 61, 62, 63, 64],
        [65, 66, 67, 68, 69],
        [70, 71, 72, 73, 74]]])
a.mean(axis=0)
array([[25., 26., 27., 28., 29.],
       [30., 31., 32., 33., 34.],
       [35., 36., 37., 38., 39.],
       [40., 41., 42., 43., 44.],
       [45., 46., 47., 48., 49.]])
  • (3,5,5) => (5,5)
a.mean(axis=(1,2))
array([12., 37., 62.])
  • (3,5,5) => (3,)

- std

a = np.array([1,2,3,4,5,6]).reshape(3,2)
a
array([[1, 2],
       [3, 4],
       [5, 6]])
a.std(axis=1)
array([0.5, 0.5, 0.5])

참고: 분모를 \(n\)이 아니라 \(n-1\)로 나누고 싶다면 아래와 같이 사용하라.

a.std(axis=1,ddof=1)
array([0.70710678, 0.70710678, 0.70710678])

- max,min,prod

a = np.array([1,2,3,4,5,6]).reshape(3,2)
a
array([[1, 2],
       [3, 4],
       [5, 6]])
a.max(axis=1)
array([2, 4, 6])
a.min(axis=1)
array([1, 3, 5])
a.prod(axis=1)
array([ 2, 12, 30])

argmax, argmin

- 아래와 같은 행렬 a를 고려하자.

a = np.random.rand(15).reshape(5,3)
a = np.stack([np.array(l)/l.sum() for l in a]) # 리스트는 5개의 원소가 있으며 각 원소는 차원이 (3,) => stack을 이용해 첫 위치에 축을 추가하여 (5,3) 매트릭스를 만듬 
a
array([[0.58989212, 0.30450216, 0.10560572],
       [0.05347106, 0.83664056, 0.10988837],
       [0.50986898, 0.27325369, 0.21687733],
       [0.06361946, 0.33376979, 0.60261074],
       [0.0593742 , 0.70953607, 0.23108973]])
  • 편의상 이 행렬의 each-row 는 어떠한 이미지가 ‘개,고양이,사과’ 일 확률을 의미한다고 상상하자.

- 위의 a에서 최대값을 가지는 index를 리턴하는 함수 (=np.argmax)를 행별로 적용하려면?

np.argmax(a,axis=1)
array([0, 1, 0, 2, 1])

HW

16. a,b가 아래와 같이 주어졌다고 하자.

a=np.array([1]*10)
b=np.array([2]*10)

1. a,b와 np.concatenate를 이용하여 아래와 같은 배열을 만들어라. // 2022-중간고사-1-(25)

array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])

(풀이)

np.concatenate([a,b])
array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])

2. a,b와 np.concatenate를 이용하여 아래와 같은 배열을 만들어라. // 2022-중간고사-1-(26)

a=np.array([1]*10)
b=np.array([2]*10)
array([[1],
       [1],
       [1],
       [1],
       [1],
       [1],
       [1],
       [1],
       [1],
       [1],
       [2],
       [2],
       [2],
       [2],
       [2],
       [2],
       [2],
       [2],
       [2],
       [2]])

(풀이)

np.concatenate([a.reshape(10,1),b.reshape(10,1)],axis=0)
array([[1],
       [1],
       [1],
       [1],
       [1],
       [1],
       [1],
       [1],
       [1],
       [1],
       [2],
       [2],
       [2],
       [2],
       [2],
       [2],
       [2],
       [2],
       [2],
       [2]])

3. a,b와 np.concatenate를 이용하여 아래와 같은 배열을 만들어라. // 2022-중간고사-1-(27)

array([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [2, 2, 2, 2, 2, 2, 2, 2, 2, 2]]

(풀이)

np.concatenate([a.reshape(1,10),b.reshape(1,10)],axis=0)
array([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [2, 2, 2, 2, 2, 2, 2, 2, 2, 2]])

4. a,b와 np.concatenate를 이용하여 아래와 같은 배열을 만들어라. // 2022-중간고사-1-(28)

array([[1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2]])

(풀이)

np.concatenate([a.reshape(10,1),b.reshape(10,1)],axis=1)
array([[1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2]])

5. a,b와 np.stack을 이용하여 아래와 같은 배열을 만들어라. // 2022-중간고사-1-(29)

array([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [2, 2, 2, 2, 2, 2, 2, 2, 2, 2]]

(풀이)

np.stack([a,b],axis=0)
array([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
       [2, 2, 2, 2, 2, 2, 2, 2, 2, 2]])

6. a,b와 np.stack을 이용하여 아래와 같은 배열을 만들어라. // 2022-중간고사-1-(30)

array([[1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2]])

(풀이)

np.stack([a,b],axis=1)
array([[1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2],
       [1, 2]])

710

아래와 같은 매트릭스를 생성하라.

np.random.seed(43052)
a=np.random.randn(10000).reshape(100,100)
a
array([[ 0.38342049,  1.0841745 ,  1.14277825, ..., -0.18506968,
         1.05538764,  1.18701443],
       [-0.25027283, -1.58045215,  0.1124153 , ...,  1.0321894 ,
         0.40438012, -0.13491595],
       [-0.76763724, -0.64294232, -0.24782396, ..., -0.01530161,
         0.89125897, -0.82683395],
       ...,
       [-1.41379028,  0.79611333, -0.71011837, ..., -0.9860352 ,
         1.30755244,  2.18677233],
       [ 1.33968105, -0.78457449, -0.10405858, ..., -0.71110186,
         0.99841286,  2.34371635],
       [-0.66422032, -0.07550233,  0.7405869 , ...,  1.03232398,
        -0.18988252, -0.03578389]])

7. 각 행의 합을 구하라. 즉 1행의 합, 2행의 합, … 100행의 합을 계산하라. // 2022-중간고사-2-(11)

  • 1행의합 = 0.38342049 + 1.0841745 + … + 1.18701443

(풀이)

a.sum(axis=1)
array([-8.13607922e+00,  9.87120533e+00, -1.41434956e+01, -2.21705363e+00,
       -1.45535236e+01, -9.15821678e+00, -2.59866360e+00, -1.54562385e+01,
       -1.42005088e+00, -3.51523111e+00,  9.70487578e+00, -1.26229105e+01,
        1.66837113e+00,  2.43015457e+00,  2.72990184e+00, -7.99486429e+00,
       -8.38305954e-01, -8.45002020e+00, -1.03610098e+00,  2.07251861e+01,
        1.11461478e+01,  7.62144075e+00, -7.93734585e+00,  1.82844319e+01,
       -2.63562392e+00, -8.97916930e+00, -1.88986183e+00, -9.32477049e+00,
       -6.69074565e+00, -1.42463143e+01,  6.45540510e-01,  1.80911488e+00,
        2.40997157e+00,  1.63367254e+01,  7.63990677e+00,  8.13524813e+00,
        3.97159000e+00, -1.10542949e+00,  4.37564512e-01,  2.87299971e+00,
       -4.01016768e+00,  5.71115215e+00, -4.64132698e+00, -9.13987753e+00,
       -6.78326000e+00,  3.36308150e+00, -5.13704342e+00, -5.09782466e+00,
        6.54192465e-03,  7.19722660e+00, -4.64674820e+00, -9.24124039e+00,
        6.73530841e+00,  1.12168921e+00,  1.61615988e+00,  1.37602200e+01,
        6.67289840e-01, -2.09578108e+00, -2.81826564e-01, -8.52416541e+00,
       -7.21970047e+00,  2.27146777e+01, -1.40341974e+01,  1.69263136e+01,
       -1.80568372e+01,  6.52142336e+00, -1.73092812e+01, -1.34999285e+01,
       -7.85539317e+00, -4.74940393e-01, -2.75765037e+01,  8.74991555e+00,
       -9.77324158e+00,  1.42854121e+01, -1.10130356e+00, -1.39206483e-01,
       -1.54638921e+01,  1.36814794e+00,  8.41394160e+00, -2.42153833e+00,
       -2.57155344e+01, -6.72423820e+00, -9.49366257e-01,  3.79493472e+00,
       -6.23508582e+00,  7.75657189e+00,  9.69403620e+00,  1.46847519e+01,
        7.36500792e+00, -2.54755192e+01,  1.22792449e+01, -1.02497847e+01,
        1.30452028e+01,  3.92943038e+00, -3.27227585e+00, -1.06633071e+01,
       -1.56942302e+01,  8.01451222e+00,  2.81546938e+00,  5.56774384e+00])

8. 7의 결과로 나온 배열의 표준편차를 구하라. // 2022-중간고사-1-(12)

(풀이)

a.sum(axis=1).std(ddof=1)
10.030404622647882

a.sum(axis=1).std() 역시 정답으로 인정

9. 각 열의 평균을 구하라. 즉 1열의 평균, 2열의 평균, … , 100열의 평균을 계산하라. // 2022-중간고사-1-(13)

(풀이)

a.sum(axis=0)
array([ 5.05543481e-01, -8.11250975e-01, -7.27142023e-01,  9.64876493e+00,
        5.64186324e+00, -2.22728206e+00,  1.32808256e-02, -9.60905067e+00,
        9.42144096e+00, -1.21946518e+01, -2.21878576e+00, -3.77018716e+00,
        2.35739166e-01, -1.13202128e+01, -9.00374437e+00, -3.09372275e+00,
       -2.18029121e+00,  7.04210003e+00, -4.12563112e+00,  2.58233488e+00,
        1.16578817e+01, -1.59430241e+01, -1.53668953e+00,  9.21879710e+00,
       -1.11346500e+01, -1.20131585e+01,  5.94139652e+00, -3.27022797e+00,
       -1.46466366e+00, -1.78386785e+00, -1.06650333e+01, -9.04542721e+00,
       -8.52586244e+00,  5.52166280e+00,  1.94115122e+01,  4.64389603e+00,
        5.13636914e+00,  1.11424801e+01, -4.18629084e+00,  9.23822150e+00,
       -2.00433998e+00, -5.73784795e+00, -8.79928414e+00, -3.01766235e+00,
        6.47256326e+00,  3.14419234e+00, -1.16146865e+01, -1.04800787e+01,
        3.17924308e+00,  5.51687322e+00,  1.04913214e+01, -2.79741703e-01,
        2.56767141e+01, -1.35620430e+01, -9.59492302e+00,  1.23241275e+01,
       -5.26436946e-01, -3.14823093e+00, -4.00286104e+00, -1.48618576e+01,
        4.85988487e+00, -1.37972086e+01, -1.04715966e+01, -7.13893940e+00,
        4.35483376e+00, -2.10610822e+01, -1.03231108e+01, -1.62132451e+01,
        2.85187037e+01, -8.25697744e+00,  4.33723229e+00,  1.32763889e+00,
       -1.61919484e+01, -5.07924036e+00,  6.62243327e+00, -9.72863991e+00,
        2.71962223e+01, -5.97710822e+00,  1.54580795e+01, -5.46739064e+00,
       -1.08611574e+01, -1.56520706e+01, -1.40476317e+01,  1.06067589e+01,
       -3.46141736e+00, -6.07673046e+00,  5.33471760e-01,  8.10276105e+00,
       -1.31994569e+01, -1.00936968e+00,  6.13944222e+00, -9.72765699e+00,
        1.61342793e+01,  1.02634369e+01, -5.03038014e+00, -7.50604837e+00,
        2.63992605e+00,  6.98470602e+00, -1.89567885e+01,  7.91910813e+00])

10. 9의 결과로 나온 배열의 표준편차를 구하라. // 2022-중간고사-1-(14)

(풀이)

a.sum(axis=0).std(ddof=1)
9.995093032516454

a.sum(axis=0).std() 역시 정답으로 인정