배열의 내용을 처음부터 알고 있다면 직접 만들 수 있지만, 대부분의 경우 크기만 알고 내용은 나중에 채우거나, 특정 패턴으로 초기화합니다.

방법1: 직접생성

# Python 리스트에서 변환
arr = np.array([1, 2, 3, 4, 5])
print(arr)

# 2D 배열 (리스트의 리스트)
matrix = np.array([[1, 2, 3], [4, 5, 6]])
print(matrix)

# dtype 지정
complex_arr = np.array([1, 2], dtype=np.complex128)
print(complex_arr)

배열에 들어갈 값과 크기를 알고 있다면 어려울건 없죠. 위의 코드처럼 미리 리스트에 자료들을 넣거나 자료들의 데이터 타입을 지정하여 넣는것도 가능합니다.

방법2: 특정 값으로 채우기

# zeros - 0으로 채워진 배열
zeros_arr = np.zeros((3, 4))
print("Zeros:\\n", zeros_arr)

# ones - 1로 채워진 배열
ones_arr = np.ones((2, 3))
print("\\nOnes:\\n", ones_arr)

# full - 특정 값으로 채우기
sevens = np.full((3, 3), 7)
print("\\nFull of 7s:\\n", sevens)

# empty - 초기화하지 않음 (메모리의 쓰레기 값)
empty_arr = np.empty((2, 2))
print("\\nEmpty (random garbage):\\n", empty_arr)

대부분 값은 미리 알 수 없지만 배열의 크기는 주어집니다.

그래서 NumPy는 초기값이 지정된 배열을 만드는 다양한 함수를 제공합니다.

이들은 배열을 확장하는 비효율적인 연산을 줄이며, 기본 데이터 타입은 float64로 생성됩니다.

zeros_int = np.zeros((2, 3), dtype=np.int32)
print(zeros_int.dtype)  # int32)

데이터 타입을 변경하고 싶으면 dtype 키워드 인수로 타입을 지정할 수 있습니다.

import time

size = (500000, 500000)

start = time.time()
z = np.zeros(size)
print(f"zeros: {time.time() - start:.4f}초")

start = time.time()
e = np.empty(size)
print(f"empty: {time.time() - start:.4f}초")

image.png

기본적으로 초기화 과정이 없는 zeros나 ones보다 empty가 빠릅니다. 다만 값을 나중에 반드시 채워 넣어야 합니다.

방법3: 범위 생성

# arange - Python range와 유사
arr = np.arange(10)  # 0부터 9까지
print("0~9:", arr)

arr = np.arange(2, 10, 2)  # 2부터 10 미만까지 2씩 증가
print("2,4,6,8:", arr)

# linspace - 구간을 균등하게 나누기
arr = np.linspace(0, 1, 5)  # 0부터 1까지 5개의 점
print("0 to 1 (5 points):", arr)  # [0.   0.25 0.5  0.75 1.  ]

# 왜 arange 대신 linspace를 쓸까?
# arange는 부동소수점에서 예측 불가능한 개수가 나올 수 있음
arr1 = np.arange(0, 1, 0.1)  # 10개? 11개?
arr2 = np.linspace(0, 1, 11)  # 정확히 11개!
print(f"arange: {len(arr1)}개, linspace: {len(arr2)}개")