STUDY/ML DL

numpy : ndarray, random, randn, rand, shape, dim, size, zeros, ones, arange, linspace

sed 2026. 5. 8. 18:20
SMALL

python 에 이어 numpy를 짚어보고자 한다.
파이썬과 넘파이는 굉장히 유사하기도 하고, 특정 부분에서 상호보완이 가능한 기특한 녀석이다.

특히 딥러닝을 할 때에는 numpy가 반드시 필요하다.

 

 

ndarray

아래와 같은 코드를 수행하면 어떻게 될까?

import numpy as np
a = np.array([1, 2, 3])
print(a)

 

당연히 `[1,2,3]` 이 되겠다.

 

`np.array()`는 파이썬 리스트를 numpy 배열로 변환하는 함수이다. 여기서 `[1, 2, 3]`은 원래 파이썬 리스트이고, `np.array([1, 2, 3])`을 사용하면 numpy의 배열 객체인 `ndarray`가 된다.

이는 가장 기본이 되는 배열 생성 방법으로, 수치 계산에 최적화 되어 있어서 여러 숫자에 대한 연산을 빠르고 간단하게 처리할 수 있다.

 

예를 들어 배열에 숫자를 곱하면 각 원소에 대해 연산이 수행된다.

lst = [1, 2, 3]
print(lst * 2)

위 코드를 수행하면, `[1, 2, 3, 1, 2, 3]` 이 출력이 된다.

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

그런데 위 코드를 수행하면, `[2, 4, 6]`이 출력 된다.

 

random

numpy의 random 모듈을 사용해서 정규분포 형태의 랜덤 행렬(데이터)을 출력할 수 있다.

print(np.random.randn(3, 3))

위 코드는 아래 결과를 나타낸다. 3행 3열 모양의 배열을 만든다는 것이다.

[[ 0.87443096 -0.42931884  0.19884613]
 [ 0.59439856  0.82724215 -1.89562362]
 [ 1.81534473 -0.99422861 -0.89380059]]
[[값 값 값]
 [값 값 값]
 [값 값 값]]

 

딥러닝에서 가중치 weight를 무작위로 초기화 할 때, 테스트용 데이터를 만들 때 사용할 수 있다.

 

`randn()`은 실행할 때마다 결과가 바뀌므로, 같은 결과를 얻고 싶다면 `seed`를 고정해야 한다.

np.random.seed(0)
print(np.random.randn(3, 3))

seed를 고정하면 같은 난수 결과를 재현할 수 있기 때문에 머신러닝 실험에서 자주 사용된다.

 

`randn()`과 `rand()`의 차이

`randn()`은 정규분포 형태의 랜덤 값이 필요할 때 사용한다.

예를 들어 머신러닝이나 딥러닝에서 가중치 초기화, 정규분포를 가정한 테스트 데이터 생성 등에 쓸 수 있다.

 

`rand()`는 0과 1 사이의 랜덤 값이 필요할 때 사용한다.

예를 들어 확률값처럼 보이는 데이터를 만들거나, 랜덤 샘플링, 시뮬레이션, 임의의 비율 값을 만들 때 자주 사용한다.

 
함수 분포 값의 범위 특징
randn() 표준정규분포 이론적으로 음수부터 양수까지 가능 평균 0 근처 값이 많이 나옴
rand() 균등분포 0 이상 1 미만 0과 1 사이 값이 고르게 나옴
# randn()
weights = np.random.randn(3, 3)

[[-0.5  1.2 -0.1]
 [ 0.3 -1.4  0.8]
 [ 2.0 -0.7  0.1]]
# rand()
probabilities = np.random.rand(5)

[[0.12 0.96 0.29]
 [0.20 0.14 0.18]
 [0.64 0.53 0.51]]

 

 

ndarray의 기본 정보 확인하기

이번에는 numpy 배열의 기본 속성을 확인해보자.

import numpy as np

a = np.array([1, 2, 3, 4])
print(a)
print(type(a))
print(a.dtype)
print(a.shape)

 

출력 결과는 다음과 같다.

[1 2 3 4]
<class 'numpy.ndarray'>
int64
(4,)

 

`type(a)`는 a가 어떤 자료형인지 확인한다.
여기서는 numpy 배열이므로 `<class 'numpy.ndarray'>`가 출력된다.

 

`dtype`은 배열 안에 들어있는 데이터의 타입을 의미한다.
위 예제에서는 정수로 이루어진 배열이므로 `int64`가 출력된다.

 

`shape`은 배열의 형태를 나타낸다.
`(4,)`는 원소가 4개인 1차원 배열이라는 뜻이다.

원소 값이 가장 첫번째 나오므로, 혼동하지 않는 것이 필요하다(나는 좀 헷갈렸음).

 

2차원 배열의 shape, ndim, size

이번에는 2차원 배열을 만들어보자.

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

print(A.shape)  # 배열의 형태
print(A.ndim)   # 배열의 차원
print(A.size)   # 전체 원소 개수

 

출력 결과는 다음과 같다.

(2, 2)
2
4

 

`A.shape`은 배열의 형태를 나타낸다. `(2, 2)`는 2행 2열의 배열이라는 의미이다.

 

`A.ndim`은 배열의 차원 수를 의미한다.
위 배열은 행과 열을 가진 2차원 배열이므로 2가 출력된다.

 

`A.size`는 배열 안에 들어있는 전체 원소의 개수이다.
즉, `A.shape[0] * A.shape[1]`과 같다.

위 배열은 2행 2열이므로 전체 원소 개수는 4이다.

 

zeros, ones, arange, linspace

numpy에서는 특정 값으로 채워진 배열을 쉽게 만들 수 있다.

특히 `zeros`, `ones`, `arange`, `linspace`는 배열을 초기화하거나 일정한 규칙을 가진 값을 만들 때 자주 사용된다.

print(np.zeros(5))
print(np.zeros_like(A))
print(np.ones(5))
print(np.ones_like(A))
print(np.zeros((3, 3)))
print(np.arange(3, 10, 2))
print(np.linspace(0, 1, 10, endpoint=True))

 

출력 결과는 다음과 같다.

[0. 0. 0. 0. 0.]
[[0 0]
 [0 0]]
[1. 1. 1. 1. 1.]
[[1 1]
 [1 1]]
[[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]
[3 5 7 9]
[0.         0.11111111 0.22222222 0.33333333 0.44444444 0.55555556
 0.66666667 0.77777778 0.88888889 1.        ]

 

 
 
 

np.zeros(5)는 0으로 채워진 길이 5의 배열을 만든다.

[0. 0. 0. 0. 0.]
 

여기서 값이 0이 아니라 0.으로 출력되는 이유는 기본적으로 실수형 배열이 만들어지기 때문이다.
즉, 정수 0이 아니라 실수 0.0으로 채워진 배열이다.

 

반대로 정수형으로 만들고 싶다면 dtype을 지정할 수 있다.

np.zeros(5, dtype=int)
 

그러면 다음과 같이 출력된다.

[0 0 0 0 0]
 

 

 

np.zeros_like(A)배열 A와 같은 shape을 가지는 0 배열을 만든다.

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

print(np.zeros_like(A))
 

출력 결과는 다음과 같다.

[[0 0]
 [0 0]]
 

즉, A가 2행 2열 배열이기 때문에 zeros_like(A)도 2행 2열로 만들어진다.
차이점은 값만 모두 0으로 바뀐다는 것이다.

이런 함수는 기존 배열과 같은 크기의 결과 저장 공간을 만들 때 자주 사용된다.

 

 

np.ones(5)는 1로 채워진 길이 5의 배열을 만든다.

[1. 1. 1. 1. 1.]
 

zeros()와 마찬가지로 기본값은 실수형이다.
그래서 1이 아니라 1.로 출력된다.

 

정수형으로 만들고 싶다면 다음처럼 쓸 수 있다.

np.ones(5, dtype=int)
 

출력 결과는 다음과 같다.

[1 1 1 1 1]
 
 

 

np.ones_like(A)배열 A와 같은 shape을 가지는 1 배열을 만든다.

print(np.ones_like(A))
 

출력 결과는 다음과 같다.

[[1 1]
 [1 1]]
 

즉, zeros_like()와 구조는 같고, 채워지는 값만 0이 아니라 1이다.

 

 

np.zeros((3, 3))은 0으로 채워진 3행 3열 배열을 만든다.

[[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]
 

여기서 (3, 3)은 배열의 shape을 의미한다.
첫 번째 3은 행의 개수, 두 번째 3은 열의 개수이다.

즉, 아래와 같은 구조를 만든다고 보면 된다.

[[값 값 값]
 [값 값 값]
 [값 값 값]]
 

딥러닝이나 데이터 처리에서는 이렇게 특정 크기의 배열을 먼저 만들어두고, 이후 계산 결과를 채워 넣는 방식으로 사용할 수 있다.

 

 

np.arange(3, 10, 2)는 3부터 시작해서 10 전까지 2씩 증가하는 배열을 만든다.

[3 5 7 9]
 

구조는 다음과 같다.

np.arange(start, stop, step)
 

따라서 np.arange(3, 10, 2)는 다음 의미가 된다.

3부터 시작
10 전까지
2씩 증가
 

그래서 생성되는 값은 3, 5, 7, 9이다.
10은 포함되지 않는다.

range()와 비슷하지만, numpy 배열을 바로 만들어준다는 점이 다르다.

 

 

np.linspace(0, 1, 10, endpoint=True)0부터 1까지를 10개의 값으로 균등하게 나눈 배열을 만든다.

[0.         0.11111111 0.22222222 0.33333333 0.44444444 0.55555556
 0.66666667 0.77777778 0.88888889 1.        ]
 

구조는 다음과 같다.

np.linspace(start, stop, num)
 

따라서 위 코드는 다음 의미이다.

0부터 시작
1까지
총 10개의 값 생성
 

endpoint=True이면 마지막 값인 1을 포함한다.
그래서 0과 1을 포함한 상태에서 그 사이를 균등하게 나누게 된다.

반대로 endpoint=False로 설정하면 마지막 값인 1은 포함하지 않는다.

np.linspace(0, 1, 10, endpoint=False)
 

이 경우에는 0부터 시작하지만 1 직전까지만 10개의 값으로 나눈다.

 

 

 

arange()와 linspace()는 비슷해 보이지만 기준이 다르다.

arange()는 간격을 기준으로 값을 만든다.

np.arange(3, 10, 2)
 

즉, “3부터 10 전까지 2씩 증가해라”라는 의미이다.

 

반면 linspace()는 개수를 기준으로 값을 만든다.

np.linspace(0, 1, 10)
 

즉, “0부터 1까지를 총 10개의 값으로 나누어라”라는 의미이다.

정리하면, 간격이 중요할 때는 arange(), 생성할 개수가 중요할 때는 linspace()를 사용하면 된다.

LIST