인덱싱, 슬라이싱, 축, 브로드캐스팅과 파일 입출력
이번 강의가 끝나면 다음을 할 수 있어야 한다.
reshape()와 전치행렬을 사용할 수 있다.axis를 지정하여 행별·열별 계산을 수행할 수 있다.import numpy as np
array = np.array([3, 3, 4, 3, 3, 4, 5, 6])
Python의 인덱스는 0부터 시작한다.
print(array[0])
print(array[2])
print(array[-1])
array[0]: 첫 번째 원소 3array[2]: 세 번째 원소 4array[-1]: 마지막 원소 6슬라이싱은 array[start:stop:step] 형식을 사용한다. stop 위치의 원소는 포함하지 않는다.
print(array[2:6])
print(array[2:6:2])
print(array[::-1])
결과는 각각 다음과 같다.
[4 3 3 4]
[4 3]
[6 5 4 3 3 4 3 3]
matrix = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
])
2차원 배열에서는 쉼표 앞이 행 인덱스, 뒤가 열 인덱스이다.
print(matrix[0, 0])
print(matrix[1, :])
print(matrix[:, 1])
print(matrix[0:2, 1:3])
각 결과는 다음과 같다.
matrix[0, 0]: 첫 행 첫 열의 값 1matrix[1, :]: 두 번째 행 [4 5 6] matrix[:, 1]: 두 번째 열 [2 5 8] matrix[0:2, 1:3]: 첫 두 행과 마지막 두 열[[2 3]
[5 6]]
배열에 비교 연산을 적용하면 각 원소에 대한 Boolean 배열을 얻는다.
temperatures = np.array([300, 450, 700, 550])
is_high = temperatures >= 500
print(is_high)
print(temperatures[is_high])
500 K 이상인 값만 선택한 결과는 [700 550]이다. 조건식을 배열에 직접 넣을 수도 있다.
print(temperatures[temperatures >= 500])
NumPy의 기본 슬라이싱은 원본 데이터의 일부를 공유하는 view를 반환하는 경우가 많다.
original = np.array([10, 20, 30, 40])
part = original[1:3]
part[0] = 999
print(part)
print(original)
part를 바꾸면 original도 바뀐다. 원본과 독립된 배열이 필요하면 copy()를 사용한다.
original = np.array([10, 20, 30, 40])
part = original[1:3].copy()
part[0] = 999
print(part)
print(original)
values = np.arange(12)
matrix = values.reshape(3, 4)
print(matrix)
print(matrix.shape)
행과 열을 바꾸려면 전치(transpose)를 사용한다.
transposed = matrix.T
print(transposed)
print(transposed.shape)
matrix의 shape은 (3, 4)이고 matrix.T의 shape은 (4, 3)이다.
다음 배열은 두 시편에 대해 세 번씩 측정한 값이라고 하자.
measurements = np.array([
[10.0, 12.0, 11.0],
[20.0, 18.0, 22.0],
])
shape은 (2, 3)이다.
axis=0을 제거하면 각 열에 대한 결과 3개가 남는다.axis=1을 제거하면 각 행에 대한 결과 2개가 남는다.column_mean = measurements.mean(axis=0)
row_mean = measurements.mean(axis=1)
print(column_mean)
print(row_mean)
print(column_mean.shape)
print(row_mean.shape)
[15. 15. 16.5] [11. 20.] axis 번호를 외우기보다 입력 shape에서 어느 축이 사라지고 어떤 shape이 남는지 확인하면 이해하기 쉽다.
브로드캐스팅(broadcasting)은 shape이 다른 배열 사이의 연산을 가능한 형태로 확장하여 계산하는 규칙이다.
celsius = np.array([0.0, 25.0, 100.0])
kelvin = celsius + 273.15
print(kelvin)
스칼라 273.15가 모든 원소에 더해진다.
data = np.array([
[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0],
])
offset = np.array([10.0, 20.0, 30.0])
corrected = data + offset
print(corrected)
shape (3,)인 offset이 각 행에 반복 적용된다.
[[11. 22. 33.]
[14. 25. 36.]]
두 배열의 마지막 축부터 크기를 비교하여, 크기가 같거나 한쪽이 1이면 브로드캐스팅할 수 있다. 처음에는 연산 전후의 shape을 출력하면서 확인하는 것이 좋다.
링크에서 파일을 내려받아 Notebook과 같은 폴더에 저장한 뒤 실습한다.
공백으로 구분된 파일은 다음과 같이 읽는다.
matrix_txt = np.loadtxt("matrix_01.txt")
print(matrix_txt)
print(matrix_txt.shape)
print(matrix_txt.dtype)
쉼표로 구분된 CSV 파일은 delimiter=","를 지정한다.
matrix_csv = np.loadtxt(
"matrix_01.csv",
delimiter=",",
)
print(matrix_csv)
웹 링크의 경로와 Python이 사용하는 로컬 파일 경로는 다를 수 있다. FileNotFoundError가 발생하면 현재 작업 폴더와 내려받은 파일의 위치를 확인한다.
matrix = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
])
np.savetxt(
"saved_matrix.txt",
matrix,
fmt="%.2f",
)
np.savetxt(
"saved_matrix.csv",
matrix,
delimiter=",",
fmt="%d",
)
fmt="%.2f": 실수를 소수점 아래 둘째 자리까지 저장fmt="%d": 정수 형식으로 저장delimiter=",": 원소 사이를 쉼표로 구분저장한 뒤 다시 읽어 원래 shape과 값이 유지되는지 확인하는 것이 좋다.
세 시편의 힘을 세 번씩 측정한 데이터가 다음과 같다고 하자.
force_n = np.array([
[1000.0, 1020.0, 980.0],
[1500.0, 1530.0, 1470.0],
[2000.0, 1980.0, 2020.0],
])
area_mm2 = np.array([
[10.0],
[12.0],
[20.0],
])
force_n의 shape은 (3, 3)이고 area_mm2의 shape은 (3, 1)이다. 면적값 하나가 같은 시편의 세 측정값에 브로드캐스팅된다.
stress_mpa = force_n / area_mm2
mean_stress_mpa = stress_mpa.mean(axis=1)
print(stress_mpa)
print(mean_stress_mpa)
$1\ \mathrm{N/mm^2}=1\ \mathrm{MPa}$이므로 응력 단위는 MPa이다. 각 행의 평균을 구했으므로 시편별 평균응력 세 개가 나온다.
배열 범위를 벗어난 위치를 선택하면 발생한다. shape과 인덱스가 0부터 시작한다는 점을 확인한다.
원소 개수와 새 shape의 원소 개수가 다를 때 발생한다.
values = np.arange(12)
print(values.size)
12개 원소는 (3, 4)로 바꿀 수 있지만 (5, 3)으로는 바꿀 수 없다.
두 shape이 브로드캐스팅 규칙에 맞지 않으면 오류가 발생한다. 연산 전에 두 배열의 shape을 출력하여 마지막 축부터 비교한다.
copy()를 사용한다.axis=0은 첫 번째 축을, axis=1은 두 번째 축을 제거한다.delimiter=","를 지정한다.다음 코드의 출력값을 쓰시오.
a = np.array([10, 20, 30, 40])
print(a[1])
배열 a의 첫 번째부터 세 번째 원소까지 선택하는 표현을 쓰시오. 단, 세 번째 원소까지 포함한다.
2차원 배열 A의 두 번째 열 전체를 선택하는 표현을 쓰시오.
다음 배열에서 5보다 큰 원소만 선택하는 표현을 쓰시오.
a = np.array([2, 5, 7, 9])
shape이 (2, 3)인 배열의 행별 평균을 구할 때 사용할 axis를 쓰시오.
CSV 파일 data.csv를 np.loadtxt()로 읽는 표현을 쓰시오.
슬라이싱한 배열을 원본과 독립적으로 만들 때 사용하는 메서드는 무엇인가?