본문 바로가기

프로젝트/게임 AI

딥러닝 선수지식 2 : 파이썬 기초

파이썬 준비

프로그램 설치

아나콘다 : 다양한 수치계산, 머신러닝용 외부 패키지가 내장된 파이썬 모듈

 -> https://www.anaconda.com/download#Windows

주피터 노트북 : 머신러닝 IDE. 아나콘다에 내장되어있으며 웹페이지 형식으로 작업함

 -> Anaconda3 > Anaconda Navigator > Jupyter Notebook Launch

 

주피터 노트북 파일생성 : 대시보드의 New > Python 3 을 선택하면 .jpynb확장자 파일을 생성할 수 있다.

 

명령 실행 단축키 : Shift + Enter 
노트북 쉘은 파이썬 쉘과 같이 한번 모듈을 import해두면 명령 실행 후에도 사용할 수 있고, 변수도 마찬가지로 계속 사용할 수 있다.

 

주피터 노트북 종료 : 노트북 서버에서 하나의 프로세스로 실행되기 때문에 브라우저를 닫는다 해도 프로세스는 종료되지 않는다.  File > Close and Halt  버튼을 클릭하거나 대시보드의 러닝탭에서 shutdown하여 주피터를 종료해줘야 한다.

 

파이썬 문법

자료형 확인

a = 1313

print(type(a)) 

-> <class 'int'>

 

 

한행에 여러 명령어

a = True; b = False; print(a+b)

 

 

연산자

+ - * /

// : 나눗셈 후 몫만 가져오기

% : 나눗셈 후 나머지만 가져오기

** : 거듭제곱

<, >, <=, >=, ==, !=

and, or, not

in : 포함여부

   ex) y=['a', 'b', 'x', 'c']

       'x' in y; -> true

 

 

리스트 []

>>> a = [1, 2, 3] + [4, 5, 6]
>>> print(a) 
[1, 2, 3, 4, 5, 6]


>>> L = [i*i for i in range(10)]  # for문의 반환값으로 i*i를 계산해서 리스트의 데이터로 넣어준다.
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]


# [원소에대한처리 for 원소 in 리스트 if 조건문]
>>> a = [1, 2, 3, 4, 5, 6, 7]
>>> b = [c*2 for c in a if c < 5]  # a의 원소들 중 c에 대해 5 미만인 경우 c*2해서 b의 원소로 넣는다
>>> print(b)
[2, 4, 6, 8]


>>> c = [1, 2, 3]
>>> c1, c2, c3 = c
>>> print(c1, c2, c3)
10 11 12


>>> c.append(5)
>>> print(c)
[1, 2, 3, 5]

 

튜플 ()

리스트와 마찬가지로 여러개의 값을 다룰때 사용하는데, 튜플은 원소 추가, 삭제, 변경이 불가능하다.

>>> a = (1, 2, 3, 4, 5) ; b = a[2]
>>> print(a + (6, 7, 8, 9))  # +연산자로 새로운 튜플을 만들어 낼 수 있다
(1, 2, 3, 4, 5, 6, 7, 8, 9)


>>> c = (10, 11, 12)
>>> c1, c2, c3 = c
>>> print(c1, c2, c3)
10 11 12

 

딕셔너리 {}

키와 값 쌍을 데이터로 갖는 자료형

 

>>> a = {"Apple" : 3, "Pineapple" : 4}
>>> a["Pineapple"] = 6  # 딕셔너리 값 변경
>>> print(a["Pineapple"])
6


>>> a["Melon"] = 99  # 딕셔너리에 값 추가
>>> print(a)
{'Apple': 3, 'Pineapple': 4, 'Melon': 99}

 

조건문

if a <12 : 

 

 

반복문

for a in [4, 7, 10]:

for a in range(3):

 

while a < 3:

 

 

함수

>>> def add(a, b=5):   # 기본값을 설정한 함수
	return a+b
>>> print(add(3))


>>> def add(a, b, c):
	print(a+b+c)
>>> e = (1, 2, 3)
>>> add(*e)  # 튜플에 *를 붙여 함수안의 인자로 전달할 수 있다.


>>> a = 123
>>> def setGlobal():
	global a   # 함수 내에서 글로벌변수 a를 선언
	a = 456
>>> setGlobal()
>>> print(a)
456

 

클래스

파이썬도 객체지향 프로그래밍이 가능하다. 

클래스 : 설계도, 틀 / 인스턴스 : 실체 

>>> class Calc:
        def __init__(self, a):  # 생성자. 인스턴스의 초기값 설정
	    self.a = a  # 인스턴스별로 할당된 인스턴스 변수 a에 인자로받은 a를 넣는다. 
            
        def add(self, b):
	    print(self.a + b)  # a는 인스턴스화 되어 같은 인스턴스의 메소드인 add에서도 사용할 수 있다.
            
        def multiply(self, b):
	    print(self.a * b)

>>> calc = Calc(3)  # Calc 클래스의 인스턴스 생성 (a=3 calc인스턴스에서만 유지됨)
>>> calc.add(4)  # add 메소드 실행(3+4)
>>> calc.multiply(5)  # multiply 메소드 실행 (3*5)


>>> class CalcPlus(Calc):  # Calc 클래스를 상속받음
        def substract(self, b):
            print(self.a - b)
        def devide(self, b):
            print(self.a / b)

>>> calc_plus = CalcPlus(5)  # CalcPlus 클래스 인스턴스 생성 
>>> calc_plus.add(4)  # 상속받아서 Calc의 메소드를 사용할 수 있음. (5+4)
>>> calc_plus.devide(10)  # CalcPlus의 메소드 (5/10)

 

넘파이 모듈

수학함수 라이브러리를 내장하는 파이썬모듈. 다차원 배열을 지원하면서 내부는 C로 작성되어 실행속도가 빠르다. 

import numpy as np  # 넘파이 모듈에 별명을 지정해줘서 np라는 이름으로 다룰 수 있게 된다.

 

배열 생성

>>> a = np.array([0, 1, 2, 3, 4, 5])  # 1차원
>>> print(a)
[0 1 2 3 4 5]

>>> b = np.array([[0,1,2], [3,4,5]])  # 2차원
>>> print(b)
[[0 1 2]
 [3 4 5]]
 
>>> c = np.array([[[0,1,2], [3,4,5]], [[6,7,8], [9,0,1]]])  # 3차원
>>> print(c)
[[[0 1 2]
  [3 4 5]]
 [[6 7 8]
  [9 0 1]]]


>>> print(np.zeros(10)) # 0으로 이뤄진 길이 10의 배열 생성 후 출력
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]  # 0. 인 이유는 부동소수점 실수임을 표현
>>> g = np.ones(10); g  # 1로 이뤄진 길이 10의 배열 생성 후 변수 g에 저장
array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])  
>>> g[2]
1.0
>>> print(np.random.rand(4)) # 0~1 사이의 랜덤한 값으로 이뤄진 배열 생성
[0.07750046 0.91623676 0.54525929 0.22444675]

>>> print(np.zeros((2,3)))  # 길이를 튜플로 전달해서 다차원 배열을 생성할 수 있다.
[[0. 0. 0. ]
 [0. 0. 0. ]]

>>> print(np.arange(0, 1, 0.1))  # 0~1 사이에서 0.1 간격으로 배열 원소 생성
[0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]
# 시작하는 수의 default는 0, 간격의 defualt는 1이다

>>> print(np.linspace(0, 1, 4))  # 0~1 범위의 총 4개의 원소를 갖는 배열 생성
[0.  0.33 0.66 1. ]
# 원소 수의 default는 50

 

배열 형태 변환

>>> c = np.array([[[0,1,2], [3,4,5]], [[6,7,8], [9,0,1]]])
>>> print(np.shape(c)) # 배열의 모양
(2, 2, 3)  # (뒤에서부터 읽음)가로3 세로2 높이2 인 3차원배열
>>> print(np.size(c)) # 배열의 총 원소 수 
12

>>> d = [[1,2], [3,4], [5,6]]  # (3,2) 형태
>>> print(len(d))  # 배열의 원소 개수를 가져온다 (= 가장높은 차원의 원소개수)
3
>>> print(np.array(d))
[[1 2]
 [3 4]
 [5 6]]
>>> print(len(np.array(d)))  # d를 np array형태로 변경 후 길이를 센다.
3


>>> a = np.array([0, 1, 2, 3, 4, 5, 6, 7])  # 원소 8개의 배열 생성
>>> b = a.reshape(2, 4)  # 배열 a를 (2, 4) 형태로 변경. 당연히 다차원 -> 다차원도 가능하다.
>>> print(b)
[[0 1 2 3]
 [4 5 6 7]]
 
>>> b = np.reshape(a, (2, 4))  # 위와 동일

>>> c = b.reshape(-1)  # -1을 인자로 전달하는경우 자동으로 계산해달라는 의미이다. 
>>> print(c)
[0, 1, 2, 3, 4, 5, 6, 7]
>>> c = b.reshape(2, -1)  # 세로 2만 맞추고 나머지는 원소 개수에 따라 자동으로 맞춘다.

 

배열 연산

파이썬 자체적으로는 에러가 발생한다. 

>>> a = np.array([0, 1, 2, 3, 4, 5]).reshape(2, 3)
>>> print(a * 3)  # 각 원소에 3을 곱함
[[ 0  3  6] 
 [ 9 12 15]]
 
>>> b = np.array([2, 3, 4, 5, 4, 3])
>>> c = np.array([2, 4, 5])  # (3,)
>>> print(a * b)
# 에러발생

>>> print(a * c)
[[ 0  4 10]		# 0*2 1*4 2*5
 [ 6 16 25]]	# 3*2 4*4 5*5
>>> c = np.array([[2], [3]])  # (2, 1)
[[ 0  2  4]		# 0*2 1*2 2*2 
 [ 9 12 15]]	# 3*3 4*3 5*3
# 서로 같은 차원의 원소 수가 같으면서 원소 수가 대응이 되어야 한다 (브로드캐스트 규칙)

 

배열 원소에 접근

>>> a = np.array([[0, 1, 2], [3, 4, 5]])
>>> print(a[1, 2])  # 2차원, 1차원 순서. a[1][2]와 같다.
5
>>> print(a[1])  # 인덱스를 하나만 지정하는 경우 가장 높은차원을 지정하는것이다.
[3, 4, 5]

>>> b = np.array([1,2,3,4,5,6,7,8,9]).reshape(3,3)
>>> b[1] = np.array([10, 11, 12])  # 배열 인덱스 위치에 배열을 삽입
>>> print(b)
[[ 0  1  2]
 [10 11 12]
 [ 7  8  9]]

>>> c = np.array([1,2,3,4,5,6,7,8,9])
>>> print(c[c%2 == 0])  # 배열의 인덱스가 조건에 맞는 경우에만 가져옴
[1 3 5 7 9]  # 0, 2, 4, 6, 8 인덱스의 값을 가져옴

>>> e = np.zeros((3, 3))  # 원소값이 0인 3*3 배열
>>> f = np.array([8, 9])  # 저장될 값
>>> e[np.array([0,2]), np.array([0,1])] = f  # [8의x축 9의x축, 8의y축 9의y축] 
>>> print(e)
[[8. 0. 0.]
 [0. 0. 0.]
 [0. 9. 0.]]
# 원래는 [x, y]에 형식인데 배열로 되어있기 때문에 [[x1 x2], [y1 y2]] 순서로 위치를 잡는다.
# 정확히 따지면 [2차, 1차]

 

배열 슬라이싱

>>> a = np.array([0,1,2,3,4,5,6,7,8,9])
>>> print(a[3:5])
[3 4]
>>> print(a[2:8:2])  # [시작:끝:간격] 파이썬은 끝 -1 까지만 한다
[2 4 6]
>>> print(a[:])  # 모든 원소
[0 1 2 3 4 5 6 7 8 9]

>>> b = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
>>> b[0:2, 0:2] = np.array([9,9], [0,0])  # 각 차원의 범위를 지정하고 값을 변경
>>> print(b)
[[9, 9, 2],
 [0, 0, 5],
 [6, 7, 8]]
 
>>> c = np.zeros(18).reshape(2, 3, 3)   
>>> c[0, 1:3, 1:3] = np.ones(4).reshape(2,2)  # 3차원 배열도 가능하다
[[[0. 0. 0.]
  [0. 1. 1.]
  [0. 1. 1.]]
  
 [[0. 0. 0.]
  [0. 0. 0.]
  [0. 0. 0.]]]

 

배열 축

배열을 선언할 때의 순서와 같다. 가장 고차원을 왼쪽부터 적듯 고차원이 0번 인덱스를 가지고 있다.

쉽게 생각하면 np.shape(a) 함수 반환값(2, 3) 인덱스의 차원(0: 2차원, 1: 1차원)으로 보면 된다.

 

축변경 함수 transpose

>>> a = np.array([[0, 1, 2], [3, 4, 5]])
>>> print(a.transpose(1, 0)  # print(a.T)와 같다. 
[[0 3]
 [1 4]
 [2 5]]

>>> a = np.arange(0, 18).reshape(2,3,3)
>>> print(a)
[[[ 0,  1,  2],
  [ 3,  4,  5],
  [ 6,  7,  8]],

[[ 9, 10, 11],
  [12, 13, 14],
  [15, 16, 17]]]

>>> print(a.T)  # a.transpose(2,1,0) 과 같다.
[[[ 0,  9],
  [ 3, 12],
  [ 6, 15]],

 [[ 1, 10],
  [ 4, 13],
  [ 7, 16]],

 [[ 2, 11],
  [ 5, 14],
  [ 8, 17]]]

a.transpose(2,1,0)

transpose 함수를 사용하게 되면 기본 축(0,1,2)으로 정렬되어 있던 배열이 함수로 전달한 인자(2,1,0)에 맞춰 기존 축 axis=2(1차원)가 0(3차원)의 위치로, 1->1, 0->2의 축으로 변경된다.

축이 변경됨에 따라 데이터가 쌓이는 순서가 변경되었다고 보면 된다.

변경되기 전에는 1차원이 [ [[1 2 3], ...] ...] 이렇게 쌓였지만 축이 1->3차원축으로 변경됨에 따라 [ [[1..], ..], [[2..], ..] ..] 이렇게 쌓인다. 

 

함수

>>> a = np.array([[0, 1], [2, 3]])
>>> print(np.sum(a))
6
# 모든 원소의 합을 계산해준다.

>>> print(np.sum(a, axis=0))
[2 4]
# 1차원축을 모양대로(세로방향) 더해준다. 

>>> print(np.sum(a, axis=1, keepdims=True))
[[1]
 [5]]
# 2차원축 모양대로 (가로방향) 더해주고 차원을 유지한다.(keepdims)


>>> print(np.max(a))  # 원소중 가장큰값 출력
3 
>>> print(np.argmax(a, axis=0))  # 세로방향(axis=0)에서 가장 큰값의 인덱스
[1 1]


# np.where(조건, 조건을 만족하는값, 조건을 만족하지않는값) 
>>> print(np.where(a<2, 9, a))  # a의 인자중 2보다 작은값은 9로 변경하고 아니면 a 그대로 둔다.
[[9 9]
 [2 3]]

 

 

맷플롯립

넘파이같은 파이썬 외부 모듈로 그래프나 이미지 표시, 간단한 애니메이션 생성등이 가능하다.

%matplotlib inline  # 맷플롯립의 그래프를 인라인으로 표시하기 위해 선언

import numpy as np
import matplotlib.pyplot as plt

그래프 생성

0~2파이까지 sin함수 그래프를 생성

>>> x = np.linspace(0, 2*np.pi)  # 0~2파이까지 x축
>>> y_sin = np.sin(x)  # sin(x) 그래프의 결과값을 y에 담기
>>> y_cos = np.cos(x)  # cos(x) 그래프의 결과값을 y에 담기

>>> plt.xlabel("x value")  # 축이름 지정
>>> plt.ylabel("y value")
>>> plt.title("sin/cos")  # 그래프 이름 지정

>>> plt.plot(x, y_sin, label="sin")  # sin으로 라벨 지정
>>> plt.plot(x, y_cos, label="cos", linestyle="dashed")  # cos로 라벨 지정, 선 스타일 대쉬형태
>>> plt.legend()  # 범례를 label과 자동으로 연결. 파라미터로 따로 지정 가능
>>> plt.show()

 *** 나중에 그림첨부하기

 

 

산포도 표시

>>> x_1 = np.random.rand(100) - 1.0
>>> x_2 = np.random.rand(100)
>>> y_1 = np.random.rand(100)
>>> y_2 = np.random.rand(100)

>>> plt.scatter(x_1, y_1, marker="+")  # 위에서 x_1 에서 1을 뺐기 때문에 왼쪽으로 1만큼 이동한다.
>>> plt.scatter(x_2, y_2, marker="*")
>>> plt.show()

 *** 나중에 그림첨부하기

 

 

이미지 표시

>>> img = np.arange(16).reshape(4,4)   # 4*4 배열 생성 숫자는 0~15까지
>>> plt.imshow(img, "gray")  # 그레이스케일로 표시
>>> plt.colorbar()  # 컬러막대 표시 
>>> plt.show()
# 배열을 이미지로 표시

>>> img = plt.imread("flower.png")
>>> plt.imshow(img)
>>> plt.show()
# 이미지를 불러올 수 있다.

 *** 나중에 그림첨부하기