본문 바로가기

Artificial Intelligence/Machine Learning

Ⅰ NumPy

1) IPython

데이터 집약적인 측면에서 파이썬만으로는 부족하기에, 사람들이 Ipython을 만들었다.

이는 대화형 파이썬 인터프리터로, 계산을 많이 하기 위해 만들었다.

 

Ipython을 사용하면 굉장히 강력하고 빠르고 효과적이다.

 

Ipython을 사용하기 위해서는 단순히 python을 설치하는 게 아니라,

가장 빠르고 쉬운 방법은 아나콘다를 설치하는 것이다.

- 표준 과학 계산용 파이썬 도구 모음에 포함된 컴포넌트
- 강력하고 생산적이고 향상된 인터랙티브(대화형) 파이썬 셸 제공
- 데이터 집약적인 컴퓨팅을 위해 파이썬을 효과적으로 사용하는 방

 

가장 좋은 특징은

매직 명령어(Magic commands)를 사용할 수 있다는 점이다.

magic commands
기능
%lsmagic
매직 명령어 리스트
%time 혹은 %timeit
실행시간 관련
%ls
현재 폴더의 파일 확인하기
%mkdir, %rmdir
새로운 폴더 생성(삭제)
%whos
Interactive namespace의 모든 객체(변수, 함수 등) 정보 보기
%xdel 객체명
특정 객체(와 관련된 모든 참조) 삭제
%reset
모든 객체 삭제
%hist
커맨드 히스토리 출력
%save
명령어 이력 중 일부 집합을 파일에 저장
%run 파일명
파이썬 파일 실행
%load 파일명
외부 파이썬 파일 보기
%%writefile 파일명
파이썬 파일로 쓰기

 

whos를 주로 많이 쓴다. 네임스페이스에 있는 모든 객체들의 리스트를 볼 수 있는 게 whos

이런 객체들 중에서 뭔가 특정한 걸 지우고 싶으면 xdel 사용

전부 지우기 위해선 reset을 사용한다.

 

 

2) Jupyter Notebook

주피터 노트북에서는 IPython 셸의 브라우저 기반 그래픽 인터페이스를 제공한다.

코드, 수식, 시각화를 포함하는 문서의 생성과 공유가 가능하다는 점에서 유용하게 쓰인다.

코딩, 서식이 있는 텍스트의 정적/동적 시각화 등을 포함한다.

Notebook Document : *.ipynb 파일 (JSON 형식)으로 저장된다.

주피터 셀(cell) : code cell / markdown cell

셀은 코드를 입력할 수 있는 하나의 조그마한 칸을 의미한다. 쉘과는 다르다.

또, 텍스트를 입력할 수 있는 마크다운 셀이 존재한다.

마크다운 셀에 필요한 커멘트나 제목을 작성할 수 있다.

 

마크다운에서 가장 많이 사용하게 될 기능은 '헤딩'이다.

헤딩 = #으로 시작, # 다음에는 빈칸, #의 개수가 늘어날수록 폰트 사이즈 작아지는 기능

이를 통해 제목의 크기를 달리하며 유용하게 사용할 수 있다.

 

 

3) Google Colab

구글 코랩은 구글의 클라우드 기반 주피터 노트북 개발 환경이다.

파이썬을 포함한 데이터 사이언스 패키지가 기본적으로 설치되어 있다. (아무것도 별도로 설치할 필요가 없다)

CPU뿐만 아니라 GPU까지도 무료로 사용 가능하다. (런타임 유형 변경)

 또, Github와 연동이 가능해서 포트폴리오를 쌓기도 쉽고 도움이 된다.

 

단축키
기능
Ctrl + Enter
현재 셀을 실행하고 커서를 해당 셀에 두기
Shift + Enter
현재 셀을 실행하고 커서를 다음 셀로 넘기기
Alt + Enter
현재 셀을 실행하고 셀을 삽입한 후 커서 넘기기
Ctrl + M Y
마크다운(텍스트) 셀을 코드 셀로 전환
Ctrl + M M
코드 셀을 마크다운 셀로 전환
Ctrl + M A
위에(above) 셀 추가
Ctrl + M B
아래에(below) 셀 추가
Ctrl + M D
셀 삭제
Ctrl + M Z
실행 취소

 

 

4) NumPy

넘파이 = 숫자 배열을 효과적으로 저장하고 가공하는 전문 도구

   - 이미지, 사운드 클립, 가공된 텍스트 데이터 모두 숫자 배열로 표현한다.

   - 행렬을 기가막히게 가장 잘 다루는 도구가 이 넘파이로, 머신러닝에서는 '행렬'이 매우 중요하다. 

   - 왜냐하면, 행렬을 사용할 때 계산이 굉장히 빨라지기 때문이다. (루프 없이 데이터를 신속히 처리 가능)

 

 

NumPy의 기능

넘파이는 기본적으로 데이터를 배열에 담는다.

빠르고 효율적인 다차원 배열 객체 ndarray를 사용한다.

  - 데이터 컨테이너 역할

배열 원소를 다루거나 배열 간의 수학 연산을 수행하는 함수

 

 

넘파이 기초 실습

1) 넘파이 임포트

2) 매직 커멘드 - 네임스페이스 안에 있는 모든 객체를 보여주는 who 사용

3) 텍스트 셀 만들어보기 

4) #개수가 늘어날수록 크기가 작아지는 것 확인

 

 

dtype 이라는 속성을 사용하게 되면, 데이터 타입을 지정해줄 수 있다.

위의 예시의 경우, 실수형 32비트로 지정한 것에 해당한다.

dtype(a)를 통해 데이터형을 알 수 있다.

 

 

1차원이므로, 뒤에 아무것도 안 나온 것을 확인할 수 있다.

4행만 명시해주면 된다.

더보기

열 벡터로 이해를 하면 된다.

1열 4행

4x1이 된다.

1D같은 경우, 콤마를 써주고 공백을 통해 1차원 ndarray 객체임을 나타낸다.

더보기

1 2 3

3 4 5

과 같은 2차원 벡터에 대해서는 (2, 3)으로 표기된다.

이와 같은 2차원과 1차원을 확실히 구분하기 위한 용도로도 ,공백의 형태로 사용한다. 

 

 


 

24.09.09.MON

 

1) ndim

a.ndim

1

차원을 알아보는 방법은 shape을 사용하지 않고도 위와 같은 방식으로도 알 수 있다.

(파란색 = 실행결과)

 

 

2) range 객체

이터레이터를 만들어주는 generator = range() 객체

시작은 무조건 0번 부터.

step은 명시해주지 않으면 디폴트 1

 

np.arange(1, 7, 2)

array([1, 3, 5])

끝값은 포함하지 않는다.

 

 

3) linspace

linspace(0, 1, 5)

array([0.   , 0.25, 0.5, 0.75, 1.   ])

 

+) np.linspace?

?를 붙이면 도움말 확인 가능 (모두 영문)

 

 

 

4) 난수 생성

(0, 1)에서 무작위로 선택한 수가 결과값으로 나온다.

 

시드값을 사용하여 어디서 실행하든 동일한 수로 맞춰줄 수 있다.

 

2행 3열 ndarray 객체 생성

 

정규분포를 이용하면 다음과 같이 평균에 가까운 값으로 출력된다.

평균이 0이고 표준편차가 1인 난수 6개를 2x3의 형상으로 만들어주는 것

 

주사위를 100번 던졌을 때 나오는 결과를 가정하여 위와 같이 출력해서 확인해볼 수 있다.

 

 

 

5) 배열 원소에 접근하기

리스트와 마찬가지로 넘파이 배열 또한 인덱스를 사용하여 배열 원소에 접근한다.

 

 

네거티브 인덱싱도 중요하다

 

arange 자체로는 행렬을 지정해줄 수 없고, reshape을 통해서 4행 5열의 ndarray객체 생성이 가능하다.

 

 

하나의 원소에 접근하지 않고 여러 범위에 접근하고 싶다면, 다음의 넘파이 슬라이싱을 이용해야 한다.

 

 

 

6) 넘파이 슬라이싱

 

 

 

중요 주의사항

** (넘파이) 배열 슬라이스는 원래 배열의 사본(copy)이 아니라 뷰(view)를 반환하므로 슬라이스를 수정하면 원래 배열이 변경된다. 데이터를 명시적으로 복사하고 싶다면 다음과 같이 copy() 메서드를 사용해야 한다. 

 

 

 

7) 형상 변경 메서드

ravel, flatten 모두 같은 기능이므로 둘 중 하나 쓰면 된다.

하지만 다음의 결과들은 모두 원본값이 변경된 것은 아니다.

다른 변수에 대입연산자를 활용해서 변경한 값으로 별도로 저장해줄 수 있다.

 

 

8) 1차원을 2차원 배열로 만들기2

reshape 말고도 newaxis를 사용한 방법이 있다.

 

 

9) 전치

transpose를 사용하여 전치 가능

 

<배열 결합(연결) 및 분할>

concatenate

vstack, hstack 함수

np.r_, np.c_

10) 두 ndarray객체 연결하기

주의) 넘파이에서는 파이썬과 달리,

+가 더 이상 연결연산자가 아닌, 각각 덧셈을 수행하는 기능으로 작동한다.

따라서 concatenate를 사용해서 두 객체를 연결해줄 수 있다.

+) np.concatenate(x, y)와 같이 대괄호 없이 사용할 경우, 에러가 난다.

 

 


 

24.09.11.WED

 

1) np.vstack & np.hstack 함수

array 리스트를 인수로 한다.

v는 세로

h는 괄호

 

2) np.r_ & np.c_

각각 v스택, h스택과 동일하다.

 

+

• 배열 분할은 다음에 필요하면 하고 넘어가기로 한다.

~ np.split, np.hsplit, np.vsplit 함수로 구현 ✓ N개의 분할점 => +1개의 하위 배열 생성

X = [1,2,3,99,99,3,2,1]  
x1, x2, x3 = np.split(x, [3,5])  
grid = np.arange(16).reshape((4, 4))  
upper, lower = np.vsplit(grid, [2])  
left, right = np.hsplit(grid, [2])

 

 

NumPy 배열 연산 : 유니버셜 함수 & 브로드캐스팅

1) 벡터화 연산

 

 

2) 넘파이 UFuncs

 

 

3) 브로드캐스팅

차원이 다른 두 배열의 연산을 확장하는 방식

  - 차원이 더 큰 배열에 맞춰 더 작은 차원의 배열의 shape을 확장한다.

 

4) Ones

np.ones((3, 3)) + np.arange(3)

크기 3x3을 1로 채우는 것을 의미한다.

 

 

NumPy 배열 집계

1) 내장 함수 vs NumPy 함수

- 배열 합: sum() vs np.sum()

x = np.random.random(10)

sum(x)

np.sum(x)

 

- NumPy 함수가 더 빠르다.

 

- 배열 객체 자체의 메소드로도 사용 가능하다.

x.sum() <- np.sum(x)와 동일하다.

 

 

%timeit를 통해 실행시간을 재면 다음과 같이 넘파이 내장함수가 훨씬 빠른 것을 확인할 수 있다.

+ %time은 여러 번 재서 평균을 낸다. 반면에 timeit는 한 번만 돌린다.

 

 

+ 오류가 생기는 이유는?

 

sum함수에 소괄호를 썼다는 것은 sum이 함수여야 함을 의미한다.

기존에 멀쩡히 돌아가던 sum이 갑자기 먹통이 된 이유는, 기존

 

기존에 sum = 0으로 변수 선언을 했으므로,

sum이 함수가 아닌, 변수로 바뀐 것으로 인식한다.

따라서 에러가 발생한다.

 

그래서 sum = 0 없애버리면 정상작동하게 된다. 

 

결과적으로, 내장함수와 동일한 명칭을 사용하는 것은 좋지 않다.

그래서 %who를 통해 내가 지금 쓰고 있는 객체의 타입이 어떻게 설정되어 있는지, 네임스페이스에 대한 상황을 잘 이해하고 있어야 한다.

 

 

 

2) 다차원 집계 (배열의 합)

y = np.array([[1,2], [3,41])  
np.sum(y) #결과 10 전체 합  
np.sum(y, axis = 0) #결과 array(4, 61) 각 열의 합 <=> y.sum(0)  
np.sum(y, axis = 1) #결과 array([3, 7] 각 행의 합 <=> y.sum(1)

 

 

3) 배열의 집계 함수 목록

- np.max, np.min, np.prod, np.mean, np.std, np.var, np.argmin,

np.argmax, np.median, np.percentile, np.any, np.all

 

- NaN 안전 모드 (결측값은 무시) : np.nansum, np.nanmax, ...

x[0] = np.NaN

np.sum(x). | #결과 nan

np.nansum (x)

 

4) 브로드캐스팅 & 집계 예제

데이터 표준화(standardization)

- 데이터 센터링(centering) : 각 열의 평균을 빼기
- 데이터 스케일링(scaling) : 각 열의 표준편차로 나누기

 

t 이건 살짝 어려운 거니까 실습을 한 번 해볼게요.

X = np.random.randint(0, 100, (10,2))

avgs = np.mean(X, 0) #X.mean(0)

sds = np.std(X, 0)

Z = (X - avgs) / sds

Z.mean(0)

Z.std (0)

 

 

[6 6]을 다섯 개 만들어서 각각 빼주는 연산이 자동적으로 수행된 것이다. (브로드캐스팅)

 

 

 

NumPy 비교, 마스크, 부울 로직

1) UFunc로서의 비교 연산자

- 비교 연산자도 NumPy의 ufunc로 구현 ex) x < 3 ⇔ np.less(x, 3)

- 비교 연산자 : ==, !=, <, <=, >, >=

- 연산 결과는 부울 타입의 배열

x = np.array([1,2,3,4,5]) x<3

각각 [True True False - - ] 연산

(2 * x) == (x ** 2)

[2 3 6 8 10] == [1 4 9 16 25] 분명 값이 다르지만 원소별로 비교한다. 2와 1을 비교, 2과 4를 비교 이런 식이다.

-> [False Fasle Fasle - -]

 

- 조건식 : np.where(조건, x, y).  t: where는 알아두면 좋을 것 같아요.

a = np.arange(10)

np.where(a < 5, a, 10*a)

 

 

2) 부울 마스킹 (masking)

특정 기준에 따라 배열을 값을 추출하거나, 수정, 계산, 조작할 때 사용

마스킹 연산 : 부울 배열을 인덱스로 사용하여 배열에서 조건에 맞는 값을 선택

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

x[x%2==0]

-> 결과는 [2 4]가 나오게 된다.

 

 

3) 팬시 인덱싱 (fancy indexing)

단순 인덱싱 : 인덱스(a[0]), 슬라이싱(a[:3]), 부울마스크(a[a>0])

팬시 인덱싱 : 단일 스칼라 대신 인덱스 배열을 전달
✓ 원래 배열을 복사해 처리하므로 값을 변경해도 원래 배열의 값은 변경되지 않음

rand = np.random.RandomState(1)

x = rand.randint(10, size = 10)  # array([5, 8, 9, 5, 0, 0, 1, 7, 6, 9])

ind = [3, 7, 4]

x[ind]   # array([5, 7, 0])

M = np.arange(12).reshape((3, 4))

row = np.array([0, 1, 2])

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

M[row, col]

 

기초 선형대수는 필요할 때 추가하고

넘파이는 여기서 마칠 것