[서초 AI 칼리지 데이터분석] - (1)

hi_rice·2025년 5월 12일

서초AI칼리지-심화

목록 보기
1/8
post-thumbnail

M01 - Numpy 표준 데이터타입 : Numpy 배열

NumPY

  • 넘파이는 대표적인 파이썬 수치 및 행렬 계산용 외부 라이브러리다.
  • 외부 라이브러리이기에 개발 중에 넘파이에서 제공하는 기능을 사용하고 싶으면 사용하기 전에 코드 상에서 import 해야 한다.
1 !pip install numpy # NumPy 라이브러리가 설치 되어 있지 않을때만.
2 import numpy as np # 개발자들 십중팔구 numpy는 np라는 별칭(alias)을 사용
  • 1995년 Numeric이라는 이름으로 출시한 후, 2006년 NumPy로 명칭을 바꾸고 꾸준히 개선됨.

  • 특히 복잡한 행렬 계산(선형대수)과 관련된 기능을 많이 제공하여 범용적으로 사용된다.

  • 파이썬 모듈(라이브러리, 패키지)에는 버전을 확인할 수 있는 __version__ 속성을 지니도록 권장하고 있으며 넘파이 역시 이를 갖고 있다.

1 print(np.__version__) # 넘파이 버전 확인
  • 넘파이에서는 다차원 행렬 계산을 위해 ndarray(그리고 matrix) 자료형을 자체적으로 가지고 있다.
1 my_first_array = np.array([0, 0.5, 1]) # 리스트로부터 ndarray 객체 생성(float와 int의 혼합)
2 print(my_first_array)
3 print(type(my_first_array))
4 print(type(my_first_array[0])) # float64로의 변환
5 print(my_first_array.dtype) # 전체 원소의 자료형
  • 넘파이에서는 자체적인 자료형을 가지고 있는데 float64, int64가 예시이다.
  • ndarray 객체 생성 시 원소들이 전부 숫자이지만 하나라도 float 값이 들어간다면 원소 전체가 float64 자료형으로 변환됨을 확인할 수 있다.

ndarray (넘파이 배열)

  • ndarray 객체는 배열로 간주하면 행렬과 유사하고, 관련 연산들을 지원한다.
    - 배열의 덧셈: 덧셈 연산자 +, 배열의 뺄셈: 뺄셈 연산자 -
    - 배열의 원소별(element-wise) 곱셈: 곱셈 연산자 *
    - 배열 원소별 나눗셈, 몫 연산, 나머지 연산: 나눗셈 연산자 /, 몫 연산자 //, 나머지 연산자 %
1 my_second_array = np.array((1, 1, 1)) # 튜플로부터 ndarray 객체 생성 (int만으로 구성)
2 print(my_second_array)
3 print(type(my_second_array))
4 print(type(my_second_array[0]))
5 print(my_first_array + my_second_array) # 배열 덧셈
6 print(my_first_array - my_second_array) # 배열 뺄셈
7 print(my_first_array * my_second_array) # 배열 원소별 곱셈
8 print(my_first_array / my_second_array) # 배열 원소별 나눗셈
9 print(my_first_array // my_second_array) # 배열 원소별 몫 연산
10 print(my_first_array % my_second_array) # 배열 원소별 나머지 연산
  • ndarray 객체는 배열로 간주하고 관련 연산들을 지원한다.
    - 배열의 곱셈(내적) : @ 또는 dot 메소드
1 A = np.array([[1, 2], [3, 4]]) # (2,2) shape의 배열
2 B = np.array([[1, 1], [2, 2]])
3 print(A, "A.shape:", A.shape, "A.ndim:", A.ndim)
4 print("A.size:",A.size, "len(A):", len(A), "\n")
5 print(B, "\n")
6 print(A*B, "\n") # 배열 원소별 곱셈
7 print(A@B) # 배열의 곱 (1)
8 print(A.dot(B)) # 배열의 곱(2)
9 print(np.dot(A,B)) # 배열의 곱 (3)

shape은 구체적인 배열의 모양을 알려주고 ndim은 총 자원 수를 알려준다. (len(A.shape) == A.ndim) size는 배열 내의 모든 원소 개수를 알려주고 배열에서 사용하는 len 함수는 가장 바깥 (혹은 첫) 차원에서의 값을 나타낸다.
(len(A) == A.shape[0])

NumPy의 메소드

  • 넘파이에서 제공하는 여러 메소드(=클래스 함수) 중 몇개를 소개한다.
  • arange : range 내장 함수와 거의 동일한 기능을 제공한다. 지정된 범위에 따라 ndarray 객체를 생성한다.
1 print(np.arange(5)) # 0부터(디폴트) 5이전까지 1 간격(디폴트)
2 print(np.arange(1, 5)) # 1부터 5이전까지 1간격(디폴트)
3 print(np.arange(1, 5, 2)) # 1부터 5이전까지 2간격
  • linspace : 특정 범위의 수를 균등하게 나누고자 할 때 사용한다.
    np.linspace(start, stop, count) 이처럼 세 개의 파라미터를 받으며 'start부터 stop까지 count개 구간으로 나눈다'를 의미한다.
1 print(np.linspace(1, 50), len(np.linspace(1, 50))) # 1부터 50까지 총 50개 구간(디폴트)
2 print(np.linspace(1, 10, 5) # 1부터 10까지 총 5개 구간
  • zeros : shape에 맞춰서 float64 타입의 0으로 채워진 ndarray 객체 생성
  • zeros_like : 주어진 시퀀스 객체와 동일한 shape으로 int64 타입의 0으로 채워진 ndarray 객체 생성
1 print(np.zeros(5)) # float64 자료형으로 0을 채움
2 print(np.zeros(5).dtype)
3 C = np.array([[1,2],[3,4],[5,6]])
4 print(np.zeros_like(C)) # 특정 시퀀스 객체와 같은 shape을 가지되 0으로 채우기
5 print(np.zeros_like(C).dtype) # zeros와는 다르게 int64 자요형으로 0을 채움
6 d = [1,2]
7 print(np.zeros_like(d))
8 e = (1, 2, 3)
9 print(np.zeros_like(e))
  • full : 주어진 shape와 값에 맞춰서 채워진 ndarray 객체 생성(zeros_like, ones_like의 일반화된 버전)
1 print(np.full((2,3),3))
2 print(np.full((2,3),3).dtype)
3 print(np.full(shape=(2,3),fill_value=3.))
4 print(np.full((2,3), 3.)dtype)
  • eye : 주어진 shape에 맞춰서 Identical matrix(단위행렬) 객체 생성(Identical의 'I' 발음에 본따서 명칭)
1 print(np.eye(3)) # (3,3)으로 단위행렬 객체 생성
2 print(np.eye(3)*3) # (3,3)으로 값이 3인 대각행렬 생성
  • random.randn : 표준정규분포로부터 주어진 shape에 맞춰 난수를 채운 ndarray 객체 생성
1 print(np.random.randn(3))
2 print(np.random.randn(3,3))
3 print(np.random.randn(2,2,2))

표준정규분포란, 평균이 0이고 표준 편차가 1인 정규분포를 의미한다.

  • ndarray 객체는 reshape 속성 혹은 reshape 메소드를 통해 shape을 변경할 수 있다.
1 my_array = np.arange(10)
2 my_new_array = my_array.reshape(2,5) # reshape 속성
3 my_new_array2 = np.reshape(my_array, (2,-1))
	# reshape 메소드 -1은 인터프리터가 자동으로 연산
4 print(my_new_array)
5 print(my_new_array2)
  • 성립될 수 없는 shape으로 모양을 변형하려고 하면 에러가 발생한다.
1 my_array = np.arange(10)
2 my_new_array2 = my_array.reshape(3,-1)
  • ndarray 객체는 T 속성 혹은 transpose 메소드를 통해 치환(transpose)할 수 있다
1 print(my_new_array) # (2,5) shape
2 my_new_array = my_new_array.T
3 print(my_new_array) # (5,2) shape
4 my_new_array = np.transpose(my_new_array)
5 print(my_new_array) # (2,5) shape
6 my_3d _array = np.arange(8).reshape(2,2,2)
7 print(my_3d _array)
8 my_3d_array= my_3d_array.T # 2D가 아닐 경우에는?
-> 항상 처음과 마지막 axis간의 치환이 이뤄진다
9 print(my_3d_array)
  • swapaxes 메소드는 특정 축들간의 변경도 가능하다 (transpose의 일반화된 버전)
1 my_3d_array = np.arange(8).reshape(2,2,2)
2 print(my_3d_array)
3 my_3d_array = np.swapaxes(my_3d_array, 0, 1)
	# 0번째와 1번째 축간의 교환
4 print(my_3d_array)
  • ndarray의 결합과 분리와 관련된 메소드들 몇 가지에 대해서 알아보자
  • 결합 : hstack, vstack, stack, concatenate
  • 분리: split
  • hstack: horizontal stack; 넘파이 배열을 수평으로 쌓는다
1 count_to_ten = np.arange(1,11)
2 count_to_twenty = np.hstack[count_to_ten,count_to_ten+10])
3 print(count_to_twenty)
  • vstack: vertical stack; 넘파이 배열을 수직으로 쌓는다
1 count_to_twenty = np.vstack([count_to_ten, count_to_ten+10))
2 print(count_to_twenty)
  • stack: hstack과 vstack의 일반화 버전; 새로운 축을 생성하여 그 방향 으로 넘파이 배열을 결합한다
1 a = np.arange(1,5).reshape(2,2)
2 print(a, "ndim:", a.ndim, "shape:", a.shape)
3 print(np.stack([a, a+4, a+8]), np.stack([a, a+4, a+8]).shape) # axis = 0
4 print(np.stack([a, a+4, a+8], axis=1), np.stack([a, a+4, a+8], axis=1).shape)
5 print(np.stack([a, a+4, a+8], axis=2), np.stack([a, a+4, a+8], axis=2).shape)
  • concatenate: stack과는 다르게 기존에 있던 축을 활용하여 배열을 연장하는 방식
1 a = np.arange(1,5).reshape(2,2)
2 print(a, "ndim:", a.ndim, "shape:", a.shape)
3 print(np.concatenate([a, a+4, a+8]), np.concatenate([a, a+4, a+8]).shape)
4 print(np.concatenate([a, a+4, a+8], axis=1), np.concatenate([a, a+4, a+8], axis=1).shape)
5 print(np.concatenate(a, 314, a18), axis=2) 축오류 발생
  • split: split은 넘파이 배열을 분리하는 메소드로 np.split(ary, indices_or_sections, axis) 방식을 취한다.
  • 첫번째 인자인 ary는 원본 넘파이 배열이고 세번째 인자인 axis는 분리하는 축 방향을 의미한다. (0이 디폴트)
  • indices_or_sections에 해당하는 인수가 정수형 N이라면 분리되는 배열이 N개의 동일한 값을 가진다 (나눌 수 없다면 오류 발생) 혹은 정렬된(sorted) 1D 꼴이라면 배열의 요소값을 기준으로 값을 나눈다
1 x = np.arange(6)
2 print(np.split(x,2)) # 2등분
3 print(np.split(x,3)) # 3등분
4 print(np splik 4) # 6개 원소를 4등분할 수 없음 (오류)
1 x = np.arange(6)
2 print(np.split(x,(2,3))) # 인덱스 2와 3을 기준으로 분리
3 print(np.split(x,[2,4,5,91)) # 인덱스 2, 4, 5, 그리고 9를 기준으로 분리
1 x = np.arange(6).reshape(2,3)
2 print(x)
3 print(np.split(x, 2)) # axis=0
4 print(np.split(x, 3, axis=1))
5 print(np.spligx, 2.axis=1) # 3개 원소를 2등분 불가능 (오류)

0개의 댓글