레이블이 numpy인 게시물을 표시합니다. 모든 게시물 표시
레이블이 numpy인 게시물을 표시합니다. 모든 게시물 표시

2022년 8월 28일 일요일

python Numpy basic 기본 사용법 정리

 

Numpy

1. 특징

  • 다차원 행렬 및 배열 처리 및 연산

출처 : 기본 내용은 아래 링크로부터 가져왔습니다.
https://numpy.org/doc/stable/user/quickstart.html

2. NumPy 설치

Python이 있는 경우 다음을 사용하여 NumPy를 설치할 수 있습니다.

conda install numpy

또는

pip install numpy


3. NumPy를 가져오는 방법

NumPy 및 해당 기능에 액세스하려면 다음과 같이 Python 코드에서 가져옵니다.
import numpy as np

np를 사용하여 코드의 더 나은 가독성을 위해 가져온 이름을 줄여서 사용합니다.



4. 완전 기본


NumPy의 다차원 배열을 표현하고 사용하기 위해서 사용합니다. 이것은 양수의 튜플에 의해 인덱싱된 같은 유형의 요소(보통 숫자)의 테이블입니다. 

(튜플이란 python에서 () 로 이루어진 데이터의 연속이나 수정이 안되는 배열로 생각 하면 됩니다. list의 수정 안되는 형태라고 이해하시면 됩니다. )

아래와 같이 표현된다면 2차원 배열이라고 생각 하면 됩니다.

[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]]


위 리스트를 numpy로 생성시키면 아래와 같은 2차원으로 배열로 표현이 됩니다. 


이걸 코드로 만들어 보면 아래와 같습니다.

import numpy as np
a = np.array([[ 0,  1,  2,  3,  4],[ 5,  6,  7,  8,  9],[10, 11, 12, 13, 14]])
print(f"array {a}")


array [[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]]


여기에서 np.array() 함수는 list나 tuple 형태를 np 로 변환하게 됩니다.


ndarray.ndim

배열의 축(차원) 수입니다.

ndarray.shape

배열의 차원. 이것은 각 차원에서 배열의 크기를 나타내는 정수의 튜플입니다. n개의 행과 m 개의 열 shape이 있는 행렬의 경우 (n,m)입니다. shape따라서 튜플의 길이는 축의 수입니다. 많이 사용하게 되므로 꼭 기억해 둘 필요가 있습니다.

ndarray.size

배열의 총 요소 수입니다. 

ndarray.dtype

배열의 요소 유형을 설명하는 개체입니다. 표준 Python 유형을 사용하여 dtype을 만들거나 지정할 수 있습니다. 또한 NumPy는 자체 유형을 제공합니다. numpy.int32, numpy.int16 및 numpy.float64가 몇 가지 예입니다.

ndarray.itemsize

배열의 각 요소의 크기(바이트)입니다.

ndarray.data

배열의 실제 요소를 포함하는 버퍼. 일반적으로 인덱싱 기능을 사용하여 배열의 요소에 액세스하기 때문에 이 속성을 사용할 필요가 없습니다.


import numpy as np
a = np.array([[ 0,  1,  2,  3,  4],[ 5,  6,  7,  8,  9],[10, 11, 12, 13, 14]])
print(f"array {a}")
print(f"np.ndim {a.ndim}")
print(f"np.shape {a.shape}")
print(f"np.size {a.size}")
print(f"np.dtype {a.dtype}")
print(f"np.itemsize {a.itemsize}")
print(f"np.data {a.data}")

array [[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]]
np.ndim 2
np.shape (3, 5)
np.size 15
np.dtype int32
np.itemsize 4
np.data <memory at 0x000001F07A34AEE0>


2차원까지는 그럭저럭 그려보는데... 3차원 이상의 경우 그림으로 그려보기 힘듭니다. 따라서 차원이 복잡한 경우 shape으로 디버깅을 해서 구조를 파악해 둘 필요가 있습니다.


5. 생성


5.1 array 이용

앞선 예제에도 사용했지만 기본으로는 array 함수를 사용합니다.
array 결과 배열의 유형은 시퀀스의 요소 유형에서 추론됩니다.

import numpy as np
>>> a = np.array([2, 3, 4])
>>> a
array([2, 3, 4])
>>> a.dtype
dtype('int64')
>>> b = np.array([1.2, 3.5, 5.1])
>>> b.dtype
dtype('float64')

위 결과를 보면 실제 부동 소수점이냐 아니면 정수 형태냐는 입력값을 가지고 판단을 하게 됩니다. 인자로 형태를 고정 할 수도 있습니다. ( dtype 사용함 )

c = np.array([[1, 2], [3, 4]], dtype=complex)
>>> c
array([[1.+0.j, 2.+0.j],
       [3.+0.j, 4.+0.j]])


5.2 zeros, ones, empty 함수 사용


함수 zeros는 0으로 가득 찬 배열을 만들고,
함수 ones는 1로 가득 찬 배열,
함수 empty는 초기 내용이 무작위이고 메모리 상태에 따라 달라지는 배열을 만듭니다. 
기본적으로 생성된 배열의 dtype은 float64이지만 키워드 인수를 통해 지정할 수 있습니다.

np.zeros((3, 4))
array([[0., 0., 0., 0.],
       [0., 0., 0., 0.],
       [0., 0., 0., 0.]])
>>> np.ones((2, 3, 4), dtype=np.int16)
array([[[1, 1, 1, 1],
        [1, 1, 1, 1],
        [1, 1, 1, 1]],

       [[1, 1, 1, 1],
        [1, 1, 1, 1],
        [1, 1, 1, 1]]], dtype=int16)
>>> np.empty((2, 3)) 
array([[3.73603959e-262, 6.02658058e-154, 6.55490914e-260],  # may vary
       [5.30498948e-313, 3.14673309e-307, 1.00000000e+000]])


5.3 arange 함수 사용


숫자 시퀀스(순서대로 증감하는 배열)를 생성하기 위해 NumPy는 arange 를 이용(Python 내장과 유사한 함수를 range 제공 ) 배열을 반환합니다.

np.arange(10, 30, 5)
array([10, 15, 20, 25])
>>> np.arange(0, 2, 0.3)  # it accepts float arguments
array([0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8])


6. 차원의 변환

많은 경우 차원의 변환이 필요한 경우가 많습니다.
reshape을 이용하게 되는데 아래 예제를 봅시다.

c = np.arange(24)
print(f"array {c}")
print(f"array {c.reshape(2,3,4)}")
print(f"array {c.reshape(-1,3,4)}")

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

reshape의 특성상 제일 하위 차원부터 구성을 하기 때문에 제일 상위 차원의 형태의 경우 -1을 입력하더라도 남은 구조를 알아서 계산 하기 때문에 같은 형태의 결과를 얻을 수 있습니다. 즉 위의 예제에서 24개의 배열이니 2*3*4 = 24개의 크기가 맞기 때문에 형태를 변환하는것은 문제 없었습니다.

만약 위의 예제에서 c = np.arange(24) -> c = np.arange(23) 으로 변환 했다면 크기가 맞지 않아서 아래와 같은 에러가 발생하게 됩니다.
Traceback (most recent call last):
  File "np.py", line 14, in <module>
    print(f"array {c.reshape(2,3,4)}")
ValueError: cannot reshape array of size 23 into shape (2,3,4)


7. 기본 연산

연산이야 말로 numpy를 사용하는 목적이 됩니다. 연산 자체를 배열 통째로 할 수 있기 때문입니다.
배열의 산술 연산자는 요소별로 적용 됩니다 . 새 배열이 생성되고 결과로 채워집니다.

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

b**2 는 제곱을 의미합니다.

사칙 연산뿐만 아니라 함수 연산도 기본적으로 배열 통째로 이루어집니다.

배열의 곱셈은 두가지가 있습니다. *은 + - 처럼 원소별로 이루어 지고 행렬 곱은 @연산자(python >=3.5) 또는 dot함수 또는 메서드를 사용하여 수행할 수 있습니다.

A = np.array([[1, 1],
...               [0, 1]])
>>> B = np.array([[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]])

+=및 와 같은 일부 작업 *=은 새 배열을 생성하는 대신 기존 배열을 수정하는 역할을 합니다. ( 이건 당연한 겁니다. )


8. 합, 최대 최소 값 그리고 축이야기

배열에 있는 모든 요소의 합을 계산하는 것과 같은 많은 단항 연산은 ndarray 클래스의 메서드로 구현됩니다.

a = rg.random((2, 3))
>>> a
array([[0.82770259, 0.40919914, 0.54959369],
       [0.02755911, 0.75351311, 0.53814331]])
>>> a.sum()
3.1057109529998157
>>> a.min()
0.027559113243068367
>>> a.max()
0.8277025938204418

기본적으로 이러한 작업은 배열의 모양에 관계없이 마치 숫자 목록인 것처럼 배열에 적용됩니다. 그러나 axis 매개변수를 지정하면 배열의 지정된 축을 따라 작업을 적용할 수 있습니다.

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=1)  # cumulative sum along each row
array([[ 0,  1,  3,  6],
       [ 4,  9, 15, 22],
       [ 8, 17, 27, 38]])


9. sin, cos, exp 함수 범용 기능


NumPy는 sin, cos, exp와 같은 친숙한 수학 함수를 제공합니다. NumPy에서는 이것을 "범용 함수"라고 합니다. NumPy 내에서 이러한 함수는 배열에서 요소별로 작동하여 배열을 출력으로 생성합니다.

B = np.arange(3)
>>> B
array([0, 1, 2])
>>> np.exp(B)
array([1.        , 2.71828183, 7.3890561 ])
>>> np.sqrt(B)
array([0.        , 1.        , 1.41421356])
>>> C = np.array([2., -1., 4.])
>>> np.add(B, C)
array([2., 0., 6.])


10. 인덱싱, 슬라이싱

이건 리스트와 동일하다고 생각하면 됩니다.
다차원 배열은 축당 하나의 인덱스를 가질 수 있습니다. 이러한 인덱스는 쉼표로 구분된 튜플에 제공됩니다.

def f(x, y):
...     return 10 * x + y
...
>>> b = np.fromfunction(f, (5, 4), dtype=int)
>>> b
array([[ 0,  1,  2,  3],
       [10, 11, 12, 13],
       [20, 21, 22, 23],
       [30, 31, 32, 33],
       [40, 41, 42, 43]])
>>> b[2, 3]
23
>>> b[0:5, 1]  # each row in the second column of b
array([ 1, 11, 21, 31, 41])
>>> b[:, 1]    # equivalent to the previous example
array([ 1, 11, 21, 31, 41])
>>> b[1:3, :]  # each column in the second and third row of b
array([[10, 11, 12, 13],
       [20, 21, 22, 23]])

축 수보다 적은 인덱스가 제공되면 누락된 인덱스는 완전한 슬라이스로 간주됩니다.:

b[-1]   # the last row. Equivalent to b[-1, :]
array([40, 41, 42, 43])


11. 배열에 다른 배열을 쌓기


내용이 복잡하기 때문에 다른 링크를 참고하세요























2022년 7월 19일 화요일

python numpy 배열/행렬을 붙이기 np.r_, np.c_, np.hstack, np.vstack, np.concatenate

 numpy 를 사용하다보면 배열과 행렬을 여기저기에 붙이는 작업을 자주 합니다. 해당 내용을 정리해보겠습니다.

여기에선 행렬을 붙이는 예제를 들고자 합니다.

들어가기에 앞서 여기에서는 특별한 설명 없이 배열이라고하면 1차원 배열을 의미하고 행렬은 2차원 배열로 설명하겠습니다.

기본 동작

(3,2) 크기의 행렬 2개를 붙인다고 할 때 사용하는 함수는 아래와 같습니다. 



실제 동작 결과입니다.

>>> import numpy as np
>>> a = np.array([[1, 2], [3, 4], [5, 6]])
>>> a.shape
(3, 2)
>>> a
array([[1, 2],
       [3, 4],
       [5, 6]])
>>> b = np.array([[11, 12], [13, 14], [15, 16]])
>>> b
array([[11, 12],
       [13, 14],
       [15, 16]])

# 아래쪽으로 붙이기
>>> np.r_[a,b]
array([[ 1,  2],
       [ 3,  4],
       [ 5,  6],
       [11, 12],
       [13, 14],
       [15, 16]])

>>> np.vstack([a,b])
array([[ 1,  2],
       [ 3,  4],
       [ 5,  6],
       [11, 12],
       [13, 14],
       [15, 16]])
	   
>>> np.concatenate((a,b),axis=0)
array([[ 1,  2],
       [ 3,  4],
       [ 5,  6],
       [11, 12],
       [13, 14],
       [15, 16]])

# 오른쪽으로 붙이기
>>> np.c_[a,b]
array([[ 1,  2, 11, 12],
       [ 3,  4, 13, 14],
       [ 5,  6, 15, 16]])
	   
>>> np.hstack([a,b])
array([[ 1,  2, 11, 12],
       [ 3,  4, 13, 14],
       [ 5,  6, 15, 16]])
	   
>>> np.concatenate((a,b),axis=1)
array([[ 1,  2, 11, 12],
       [ 3,  4, 13, 14],
       [ 5,  6, 15, 16]])


여러가지 방식으로 붙여보기

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> import numpy as np
>>> a = np.array([[1, 2], [3, 4], [5, 6]])
>>> a.shape
(3, 2)
>>> b = np.array([21, 22, 23])
>>> b.shape()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object is not callable
>>> b.shape
(3,)
>>> b
array([21, 22, 23])
>>> np.r_[a,b]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/work/myenv38/lib/python3.8/site-packages/numpy/lib/index_tricks.py", line 412, in __getitem__
    res = self.concatenate(tuple(objs), axis=axis)
  File "<__array_function__ internals>", line 180, in concatenate
ValueError: all the input arrays must have same number of dimensions, but the array at index 0 has 2 dimension(s) and the array at index 1 has 1 dimension(s)
>>> np.vstack([a,b])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<__array_function__ internals>", line 180, in vstack
  File "/work/myenv38/lib/python3.8/site-packages/numpy/core/shape_base.py", line 282, in vstack
    return _nx.concatenate(arrs, 0)
  File "<__array_function__ internals>", line 180, in concatenate
ValueError: all the input array dimensions for the concatenation axis must match exactly, but along dimension 1, the array at index 0 has size 2 and the array at index 1 has size 3
>>> np.concatenate((a,b),axis=0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<__array_function__ internals>", line 180, in concatenate
ValueError: all the input arrays must have same number of dimensions, but the array at index 0 has 2 dimension(s) and the array at index 1 has 1 dimension(s)
>>> np.c_[a,b]
array([[ 1,  2, 21],
       [ 3,  4, 22],
       [ 5,  6, 23]])
>>> np.hstack([a,b])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<__array_function__ internals>", line 180, in hstack
  File "/work/myenv38/lib/python3.8/site-packages/numpy/core/shape_base.py", line 345, in hstack
    return _nx.concatenate(arrs, 1)
  File "<__array_function__ internals>", line 180, in concatenate
ValueError: all the input arrays must have same number of dimensions, but the array at index 0 has 2 dimension(s) and the array at index 1 has 1 dimension(s)
>>> np.concatenate((a,b),axis=1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<__array_function__ internals>", line 180, in concatenate
ValueError: all the input arrays must have same number of dimensions, but the array at index 0 has 2 dimension(s) and the array at index 1 has 1 dimension(s)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> b = np.array([[21], [22], [23]])
>>> b
array([[21],
       [22],
       [23]])
>>> b.shape
(3, 1)
>>> np.r_[a,b]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/work/myenv38/lib/python3.8/site-packages/numpy/lib/index_tricks.py", line 412, in __getitem__
    res = self.concatenate(tuple(objs), axis=axis)
  File "<__array_function__ internals>", line 180, in concatenate
ValueError: all the input array dimensions for the concatenation axis must match exactly, but along dimension 1, the array at index 0 has size 2 and the array at index 1 has size 1
>>> np.vstack([a,b])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<__array_function__ internals>", line 180, in vstack
  File "/work/myenv38/lib/python3.8/site-packages/numpy/core/shape_base.py", line 282, in vstack
    return _nx.concatenate(arrs, 0)
  File "<__array_function__ internals>", line 180, in concatenate
ValueError: all the input array dimensions for the concatenation axis must match exactly, but along dimension 1, the array at index 0 has size 2 and the array at index 1 has size 1
>>> np.concatenate((a,b),axis=0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<__array_function__ internals>", line 180, in concatenate
ValueError: all the input array dimensions for the concatenation axis must match exactly, but along dimension 1, the array at index 0 has size 2 and the array at index 1 has size 1
>>> np.c_[a,b]
array([[ 1,  2, 21],
       [ 3,  4, 22],
       [ 5,  6, 23]])
>>> np.hstack([a,b])
array([[ 1,  2, 21],
       [ 3,  4, 22],
       [ 5,  6, 23]])
>>> np.concatenate((a,b),axis=1)
array([[ 1,  2, 21],
       [ 3,  4, 22],
       [ 5,  6, 23]])
>>>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> b = np.array([21, 22])
>>> b.shape
(2,)
>>> b
array([21, 22])
>>> np.r_[a,b]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/work/myenv38/lib/python3.8/site-packages/numpy/lib/index_tricks.py", line 412, in __getitem__
    res = self.concatenate(tuple(objs), axis=axis)
  File "<__array_function__ internals>", line 180, in concatenate
ValueError: all the input arrays must have same number of dimensions, but the array at index 0 has 2 dimension(s) and the array at index 1 has 1 dimension(s)
>>> np.vstack([a,b])
array([[ 1,  2],
       [ 3,  4],
       [ 5,  6],
       [21, 22]])
>>> np.concatenate((a,b),axis=0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<__array_function__ internals>", line 180, in concatenate
ValueError: all the input arrays must have same number of dimensions, but the array at index 0 has 2 dimension(s) and the array at index 1 has 1 dimension(s)
>>> np.c_[a,b]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/work/myenv38/lib/python3.8/site-packages/numpy/lib/index_tricks.py", line 412, in __getitem__
    res = self.concatenate(tuple(objs), axis=axis)
  File "<__array_function__ internals>", line 180, in concatenate
ValueError: all the input array dimensions for the concatenation axis must match exactly, but along dimension 0, the array at index 0 has size 3 and the array at index 1 has size 2
>>> np.hstack([a,b])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<__array_function__ internals>", line 180, in hstack
  File "/work/myenv38/lib/python3.8/site-packages/numpy/core/shape_base.py", line 345, in hstack
    return _nx.concatenate(arrs, 1)
  File "<__array_function__ internals>", line 180, in concatenate
ValueError: all the input arrays must have same number of dimensions, but the array at index 0 has 2 dimension(s) and the array at index 1 has 1 dimension(s)
>>> np.concatenate((a,b),axis=1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<__array_function__ internals>", line 180, in concatenate
ValueError: all the input arrays must have same number of dimensions, but the array at index 0 has 2 dimension(s) and the array at index 1 has 1 dimension(s)
>>>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> b = np.array([[21, 22]])
>>> b.shape
(1, 2)
>>> b
array([[21, 22]])
>>> np.r_[a,b]
array([[ 1,  2],
       [ 3,  4],
       [ 5,  6],
       [21, 22]])
>>> np.vstack([a,b])
array([[ 1,  2],
       [ 3,  4],
       [ 5,  6],
       [21, 22]])
>>> np.concatenate((a,b),axis=0)
array([[ 1,  2],
       [ 3,  4],
       [ 5,  6],
       [21, 22]])
>>> np.c_[a,b]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/work/myenv38/lib/python3.8/site-packages/numpy/lib/index_tricks.py", line 412, in __getitem__
    res = self.concatenate(tuple(objs), axis=axis)
  File "<__array_function__ internals>", line 180, in concatenate
ValueError: all the input array dimensions for the concatenation axis must match exactly, but along dimension 0, the array at index 0 has size 3 and the array at index 1 has size 1
>>> np.hstack([a,b])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<__array_function__ internals>", line 180, in hstack
  File "/work/myenv38/lib/python3.8/site-packages/numpy/core/shape_base.py", line 345, in hstack
    return _nx.concatenate(arrs, 1)
  File "<__array_function__ internals>", line 180, in concatenate
ValueError: all the input array dimensions for the concatenation axis must match exactly, but along dimension 0, the array at index 0 has size 3 and the array at index 1 has size 1
>>> np.concatenate((a,b),axis=1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<__array_function__ internals>", line 180, in concatenate
ValueError: all the input array dimensions for the concatenation axis must match exactly, but along dimension 0, the array at index 0 has size 3 and the array at index 1 has size 1
>>>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


1차원 배열과 2차원 배열의 표현법 다름을 이해

위의 결과를 보면 2차원 배열에 붙일때는 2차원 배열로 크기를 맞춰서 붙이는것이 제일 제대로 동작합니다. 1차원 배열로 붙이더라도 붙는 함수가 있긴 하지만 1차원형태로 만들어 주는것이 좋습니다. 

아래는 비슷하게 생겼지만 아래 표현법을 익히는 것이 중요합니다. 

1차원 배열 : [21, 22]
2차원 배열 가로 : [[21, 22]]
2차원 배열 세로 : [[21], [22], [23]]

또한 가로 세로 변경은 .T 를 붙여서 전환이 가능합니다. (전치행렬:대각선을 기준으로 뒤집음)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1차원 배열
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> b = np.array([21, 22])
>>> b.shape
(2,)
>>> b
array([21, 22])
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2차원 배열 가로
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> b = np.array([[21, 22]])
>>> b.shape
(1, 2)
>>> b
array([[21, 22]])
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2차원 배열 세로
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> b = np.array([[21], [22], [23]])
>>> b
array([[21],
       [22],
       [23]])
>>> b.shape
(3, 1)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
전치 행렬
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> b = np.array([[21], [22], [23]])
>>> b
array([[21],
       [22],
       [23]])
>>> b.T
array([[21, 22, 23]])
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1차원 배열->2차원 배열 전환
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> b = np.array([21, 22, 23])
>>> b
array([21, 22, 23])
>>> np.array([b])
array([[21, 22, 23]])


정리

1. 2차원 배열에 붙일때는 2차원 배열로 변환해서 붙인다.

2. 붙일려고 하는 크기가 다를때는 오류 발생

3. 가로 세로 전환시에는 np.T 전치 행렬 이용

4. 하나만 제대로 외우자 np.hstack([]), np.vstack([])