Lesson 06: numpy II

Author

최규빈

Published

July 24, 2023

Imports

import numpy as np

Numpy: axis의 이해

- 목표: 넘파이의 axis를 이해하여 보자.

np.concatenate

- 기본예제

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

- 응용

a=np.array([1,2])
b=-a 
c=np.array([3,4,5])
np.concatenate([a,b,c])
array([ 1,  2, -1, -2,  3,  4,  5])
  • 여기까진 딱히 칸캐터네이트의 메리트가 없어보임
  • 리스트였다면 a+b+c 하면 되는 기능이니까?

- 2d array에 적용해보자.

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

- 옆으로 붙일려면?

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

- 위의 코드에서 axis=1 이 뭐지? axis=0,2 등을 치면 결과가 어떻게 될까?

np.concatenate([a,b],axis=0)
array([[ 0,  1],
       [ 2,  3],
       [ 0, -1],
       [-2, -3]])
  • 이건 그냥 np.concatenate([a,b])와 같다.
  • np.concatenate([a,b])는 np.concatenate([a,b],axis=0)의 생략버전이군?
np.concatenate([a,b],axis=2)
AxisError: axis 2 is out of bounds for array of dimension 2
  • 이런건 없다.

- axis의 의미가 뭔지 궁금함. 좀 더 예제를 살펴보자.

a=np.array(range(2*3*4)).reshape(2,3,4)
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]]])
b=-a
b
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]]])
np.concatenate([a,b],axis=0) 
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]],

       [[  0,  -1,  -2,  -3],
        [ -4,  -5,  -6,  -7],
        [ -8,  -9, -10, -11]],

       [[-12, -13, -14, -15],
        [-16, -17, -18, -19],
        [-20, -21, -22, -23]]])
np.concatenate([a,b],axis=1) 
array([[[  0,   1,   2,   3],
        [  4,   5,   6,   7],
        [  8,   9,  10,  11],
        [  0,  -1,  -2,  -3],
        [ -4,  -5,  -6,  -7],
        [ -8,  -9, -10, -11]],

       [[ 12,  13,  14,  15],
        [ 16,  17,  18,  19],
        [ 20,  21,  22,  23],
        [-12, -13, -14, -15],
        [-16, -17, -18, -19],
        [-20, -21, -22, -23]]])
np.concatenate([a,b],axis=2) 
array([[[  0,   1,   2,   3,   0,  -1,  -2,  -3],
        [  4,   5,   6,   7,  -4,  -5,  -6,  -7],
        [  8,   9,  10,  11,  -8,  -9, -10, -11]],

       [[ 12,  13,  14,  15, -12, -13, -14, -15],
        [ 16,  17,  18,  19, -16, -17, -18, -19],
        [ 20,  21,  22,  23, -20, -21, -22, -23]]])
  • 이번에는 axis=2까지 된다?
np.concatenate([a,b],axis=3) 
AxisError: axis 3 is out of bounds for array of dimension 3
  • axis=3까지는 안된다?

- 뭔가 나름의 방식으로 합쳐지는데 원리가 뭘까?

(분석1) np.concatenate([a,b],axis=0)

a=np.array(range(2*3*4)).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))
  • 첫번째차원이 바뀌었다 => 첫번째 축이 바뀌었다 => axis=0 (파이썬은 0부터 시작하니까!)

(분석2) np.concatenate([a,b],axis=1)

a=np.array(range(2*3*4)).reshape(2,3,4) 
b=-a 
a.shape, b.shape, np.concatenate([a,b],axis=1).shape
((2, 3, 4), (2, 3, 4), (2, 6, 4))
  • 두번째차원이 바뀌었다 => 두번째 축이 바뀌었다 => axis=1

(분석3) np.concatenate([a,b],axis=2)

a=np.array(range(2*3*4)).reshape(2,3,4) 
b=-a 
a.shape, b.shape, np.concatenate([a,b],axis=2).shape
((2, 3, 4), (2, 3, 4), (2, 3, 8))
  • 세번째차원이 바뀌었다 => 세번째 축이 바뀌었다 => axis=2

(분석4) np.concatenate([a,b],axis=3)

a=np.array(range(2*3*4)).reshape(2,3,4) 
b=-a 
a.shape, b.shape, np.concatenate([a,b],axis=3).shape
AxisError: axis 3 is out of bounds for array of dimension 3
  • 네번째차원이 없다 => 네번째 축이 없다 => axis=3으로 하면 에러가 난다.

(보너스1)

a=np.array(range(2*3*4)).reshape(2,3,4) 
b=-a 
np.concatenate([a,b],axis=-1)
array([[[  0,   1,   2,   3,   0,  -1,  -2,  -3],
        [  4,   5,   6,   7,  -4,  -5,  -6,  -7],
        [  8,   9,  10,  11,  -8,  -9, -10, -11]],

       [[ 12,  13,  14,  15, -12, -13, -14, -15],
        [ 16,  17,  18,  19, -16, -17, -18, -19],
        [ 20,  21,  22,  23, -20, -21, -22, -23]]])
a.shape, b.shape, np.concatenate([a,b],axis=-1).shape
((2, 3, 4), (2, 3, 4), (2, 3, 8))
  • 마지막 차원이 바뀌었다 => 마지막 축이 바뀌었다 => axis = -1

(보너스2)

a=np.array(range(2*3*4)).reshape(2,3,4) 
b=-a 
np.concatenate([a,b],axis=-2)
array([[[  0,   1,   2,   3],
        [  4,   5,   6,   7],
        [  8,   9,  10,  11],
        [  0,  -1,  -2,  -3],
        [ -4,  -5,  -6,  -7],
        [ -8,  -9, -10, -11]],

       [[ 12,  13,  14,  15],
        [ 16,  17,  18,  19],
        [ 20,  21,  22,  23],
        [-12, -13, -14, -15],
        [-16, -17, -18, -19],
        [-20, -21, -22, -23]]])
a.shape, b.shape, np.concatenate([a,b],axis=-2).shape
((2, 3, 4), (2, 3, 4), (2, 6, 4))
  • 마지막에서 2번째 차원이 바뀌었다 => 마지막에서 2번째 축이 바뀌었다 => axis = -2

(보너스3)

a=np.array(range(2*3*4)).reshape(2,3,4) 
b=-a 
np.concatenate([a,b],axis=-3)
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]],

       [[  0,  -1,  -2,  -3],
        [ -4,  -5,  -6,  -7],
        [ -8,  -9, -10, -11]],

       [[-12, -13, -14, -15],
        [-16, -17, -18, -19],
        [-20, -21, -22, -23]]])
a.shape, b.shape, np.concatenate([a,b],axis=-3).shape
((2, 3, 4), (2, 3, 4), (4, 3, 4))
  • 마지막에서 3번째 차원이 바뀌었다 => 마지막에서 3번째 축이 바뀌었다 => axis = -3

(보너스3)

a=np.array(range(2*3*4)).reshape(2,3,4) 
b=-a 
np.concatenate([a,b],axis=-4)
AxisError: axis -4 is out of bounds for array of dimension 3
  • 마지막에서 4번째 차원은 없다 => 마지막에서 4번째 축이 없다 => axis = -4는 에러가 난다.

- 0차원은 축이 없으므로 concatenate를 쓸 수 없다.

a= np.array(1)
b= np.array(-1) 
a.shape, b.shape
((), ())
np.concatenate([a,b])
ValueError: zero-dimensional arrays cannot be concatenated

- 꼭 a,b가 같은 차원일 필요는 없다.

a=np.array(range(4)).reshape(2,2) 
b=np.array(range(2)).reshape(2,1)  
np.concatenate([a,b.T],axis=0)
array([[0, 1],
       [2, 3],
       [0, 1]])
np.concatenate([a,b],axis=1)
array([[0, 1, 0],
       [2, 3, 1]])
a.shape, b.shape, np.concatenate([a,b],axis=1).shape
((2, 2), (2, 1), (2, 3))

np.stack

- 혹시 아래가 가능할까?

  • (3,) 결합 (3,) => (3,2)
a=np.array([1,2,3])
b=-a
a,b
(array([1, 2, 3]), array([-1, -2, -3]))
np.concatenate([a,b],axis=1)
AxisError: axis 1 is out of bounds for array of dimension 1
  • 불가능

- 아래와 같이 하면 해결가능

a=np.array([1,2,3]).reshape(3,1) 
b=-a
a,b
(array([[1],
        [2],
        [3]]),
 array([[-1],
        [-2],
        [-3]]))
np.concatenate([a,b],axis=1)
array([[ 1, -1],
       [ 2, -2],
       [ 3, -3]])
  • 분석: (3) (3) => (3,1) (3,1) => (3,1) concat (3,1)

- 위의 과정을 줄여서 아래와 같이 할 수 있다.

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

- 아래도 가능

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

- 분석해보고 외우자

(분석1)

a=np.array([1,2,3])
b=-a
a.shape, b.shape, np.stack([a,b],axis=0).shape
((3,), (3,), (2, 3))
      1. => 첫 위치에 축을 추가 (axis=0) => (1,3) (1,3) => (2,3)

(분석2)

a=np.array([1,2,3])
b=-a
a.shape, b.shape, np.stack([a,b],axis=1).shape
((3,), (3,), (3, 2))
      1. => 두 위치에 축을 추가 (axis=1) => (3,1) (3,1) => (3,2)

- 고차원예제

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차원

a = np.array([1,2,3]) 
a
array([1, 2, 3])
a.sum()
6
a.sum(axis=0)
6

- 2차원

a=np.array(range(6)).reshape(2,3)
a
array([[0, 1, 2],
       [3, 4, 5]])
a.sum() # 전체합
15
a.sum(axis=0) 
array([3, 5, 7])
a.sum(axis=1) 
array([ 3, 12])

- 2차원 결과 분석

a.shape, a.sum(axis=0).shape
((2, 3), (3,))
  • 첫번째 축이 삭제됨 => axis=0
a.shape, a.sum(axis=1).shape
((2, 3), (2,))
  • 두번째 축이 삭제됨 => axis=1

- 연습

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, max, min

- 모두 sum이랑 유사한 논리

a=np.array(range(10)).reshape(5,2)
a
array([[0, 1],
       [2, 3],
       [4, 5],
       [6, 7],
       [8, 9]])
a.mean(axis=0), a.max(axis=0), a.min(axis=0)
(array([4., 5.]), array([8, 9]), array([0, 1]))
a.mean(axis=1), a.max(axis=1), a.min(axis=1)
(array([0.5, 2.5, 4.5, 6.5, 8.5]),
 array([1, 3, 5, 7, 9]),
 array([0, 2, 4, 6, 8]))

Quiz

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

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

1. a,b와 np.concatenate를 이용하여 아래와 같은 배열을 만들어라.

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를 이용하여 아래와 같은 배열을 만들어라.

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]])

3. a,b와 np.concatenate를 이용하여 아래와 같은 배열을 만들어라.

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를 이용하여 아래와 같은 배열을 만들어라.

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을 이용하여 아래와 같은 배열을 만들어라.

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을 이용하여 아래와 같은 배열을 만들어라.

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

78

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

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행의 합을 계산하라.

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

8. 각 열의 평균을 구하라. 즉 1열의 평균, 2열의 평균, … , 100열의 평균을 계산하라.