파이썬

파이썬 Tutorial

PGNV 2021. 4. 22. 11:29

 

 

 

 

 

 

 

함수

파이썬 함수는 ‘def’ 키워드를 통해 정의됩니다

def sign(x):
    if x > 0:
        return '양수'
    elif x < 0:
        return '음수'
    else:
        return 'zero'

for x in [-1, 0, 1]:
    print(sign(x))
# 출력 "음수", "zero", "양수", 한 줄에 하나씩 출력.

 

 

 

 

클래스

 

 

 

 

 

Numpy 라이브러리

대량의 데이터를 사용할때 빠르게 사용할수있음 (내부는 C언어로 이루어져 있음)

  • 각각의 값들은 튜플
  • rank는 배열이 몇 차원인지를 의미
  • shape는 는 각 차원의 크기를 알려주는 정수들이 모인 튜플
import numpy as np
arr = [1, 2, 3, 4, 5] #list
print(type(arr)) #출력 <class 'list'>
print(arr + 5) #이 줄은 에러처리된다.
print(arr - 5) #이것도 에러처리된다


npArr = np.array(arr) #convert from list to numpy
print(type(npArr)) #<class 'numpy.ndarray'>
print(npArr + 5) #출력 [ 6  7  8  9 10] 
print(npArr - 5) #출력 [-4 -3 -2 -1  0]
#numpy.Array는 Broadcasting 때문에 덧셈 혹은 뺄셈 등 사칙연산이 가능하다.
#이게 바로 array와 numpy.Array의 차이이다 
arr2D = [[1, 2, 3, 3.5], [4, 5, 6, 6.5], [7, 8, 9, 9.5]]
npArr2D = np.array(arr2D)
print(npArr2D)
print(npArr2D.shape) #npArray의 모양을 알고싶을때

'''
-print(npArr2D)출력-
[[1.  2.  3.  3.5]
 [4.  5.  6.  6.5]
 [7.  8.  9.  9.5]]
 
 -print(npArr2D.shape)의 출력-
 (3, 4)

 '''
import numpy as np

a = np.array([1, 2, 3])  # rank가 1인 배열 생성
print (type(a))            # 출력 "<type 'numpy.ndarray'>"
print (a.shape)            # 출력 "(3,)"
print (a[0], a[1], a[2])   # 출력 "1 2 3"
a[0] = 5                 # 요소를 변경
print (a)                  # 출력 "[5, 2, 3]"

b = np.array([[1,2,3],[4,5,6]])   # rank가 2인 배열 생성
print (b.shape )                    # 출력 "(2, 3)"
print (b[0, 0], b[0, 1], b[1, 0])   # 출력 "1 2 4"

Numpy Shape 기능

arr2D = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [14, 15, 16]]
npArr2D = np.array(arr2D)

N = npArr2D.shape[0]

for i in range(N):
  print(npArr2D[i][0])
  
  ''' 
  출력값
1
4
7
10
14
'''

Numpy각종 초기화 방법

 

 

arr = np.array([0, 1, 3, 4, 5])
print(arr) #출력 [0 1 3 4 5]

arr = np.array(range(10))
print(arr) #출력 [0 1 2 3 4 5 6 7 8 9]

arr = np.zeros((3, 3))
print(arr)
'''
출력
[[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]
 '''
 
arr = np.ones((3, 3))
print(arr)
'''
출력
[[1. 1. 1.]
 [1. 1. 1.]
 [1. 1. 1.]]
 '''
import numpy as np

a = np.zeros((2,2))  # 모든 값이 0인 배열 생성
print(a)              # 출력 "[[ 0.  0.]
                     #       [ 0.  0.]]"

b = np.ones((1,2))   # 모든 값이 1인 배열 생성
print(b)              # 출력 "[[ 1.  1.]]"

c = np.full((2,2), 7) # 모든 값이 특정 상수인 배열 생성
print(c)               # 출력 "[[ 7.  7.]
                      #       [ 7.  7.]]"

d = np.eye(2)        # 2x2 단위행렬 생성
print(d)              # 출력 "[[ 1.  0.]
                     #       [ 0.  1.]]"

e = np.random.random((2,2)) # 임의의 값으로 채워진 배열 생성
print(e)                     # 임의의 값 출력 "[[ 0.91940167  0.08143941]
                            #                  [ 0.68744134  0.87236687]]"

 

 

 

배열 인덱싱

 

import numpy as np

# Create the following rank 2 array with shape (3, 4)
# [[ 1  2  3  4]
#  [ 5  6  7  8]
#  [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])

# 슬라이싱을 이용하여 첫 두 행과 1열, 2열로 이루어진 부분배열을 만들어 봅시다;
# b는 shape가 (2,2)인 배열이 됩니다:
# [[2 3]
#  [6 7]]
b = a[:2, 1:3]

# 슬라이싱된 배열은 원본 배열과 같은 데이터를 참조합니다, 즉 슬라이싱된 배열을 수정하면
# 원본 배열 역시 수정됩니다.
print (a[0, 1])   # 출력 "2"
b[0, 0] = 77    # b[0, 0]은 a[0, 1]과 같은 데이터입니다
print (a[0, 1])   # 출력 "77"

Numpy배열 슬라이싱

 

import numpy as np

# 아래와 같은 요소를 가지는 rank가 2이고 shape가 (3, 4)인 배열 생성
# [[ 1  2  3  4]
#  [ 5  6  7  8]
#  [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])

# 배열의 중간 행에 접근하는 두 가지 방법이 있습니다.
# 정수 인덱싱과 슬라이싱을 혼합해서 사용하면 낮은 rank의 배열이 생성되지만,
# 슬라이싱만 사용하면 원본 배열과 동일한 rank의 배열이 생성됩니다.
row_r1 = a[1, :]    # 배열a의 두 번째 행을 rank가 1인 배열로
row_r2 = a[1:2, :]  # 배열a의 두 번째 행을 rank가 2인 배열로
print (row_r1, row_r1.shape)  # 출력 "[5 6 7 8] (4,)"
print (row_r2, row_r2.shape)  # 출력 "[[5 6 7 8]] (1, 4)"

# 행이 아닌 열의 경우에도 마찬가지입니다:
col_r1 = a[:, 1]
col_r2 = a[:, 1:2]
print (col_r1, col_r1.shape)  # 출력 "[ 2  6 10] (3,)"
print (col_r2, col_r2.shape)  # 출력 "[[ 2]
                              #       [ 6]
                              #       [10]] (3, 1)"

정수 배열 인덱싱

 Numpy 배열을 슬라이싱하면, 결과로 얻어지는 배열은 언제나 원본 배열의 부분 배열입니다. 그러나 정수 배열 인덱싱을 한다면, 원본과 다른 배열을 만들 수 있습니다

 

import numpy as np

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

# 정수 배열 인덱싱의 예.
# 반환되는 배열의 shape는 (3,)
print (a[[0, 1, 2], [0, 1, 0]])  # 출력 "[1 4 5]"

# 위에서 본 정수 배열 인덱싱 예제는 다음과 동일합니다:
print (np.array([a[0, 0], a[1, 1], a[2, 0]]))  # 출력 "[1 4 5]"

# 정수 배열 인덱싱을 사용할 때,
# 원본 배열의 같은 요소를 재사용할 수 있습니다:
print (a[[0, 0], [1, 1]])  # 출력 "[2 2]"

# 위 예제는 다음과 동일합니다
print (np.array([a[0, 1], a[0, 1]]))  # 출력 "[2 2]"

 

 

불리언 배열 인덱싱

불리언 배열 인덱싱은 특정 조건을 만족하게 하는 요소만 선택하고자 할 때 자주 사용됩니다.

 

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

bool_idx = (a > 2)  # 2보다 큰 a의 요소를 찾습니다;
                    # 이 코드는 a와 shape가 같고 불리언 자료형을 요소로 하는 numpy 배열을 반환합니다,
                    # bool_idx의 각 요소는 동일한 위치에 있는 a의
                    # 요소가 2보다 큰지를 말해줍니다.

print (bool_idx)      # 출력 "[[False False]
                    #       [ True  True]
                    #       [ True  True]]"

# 불리언 배열 인덱싱을 통해 bool_idx에서
# 참 값을 가지는 요소로 구성되는
# rank 1인 배열을 구성할 수 있습니다.
print (a[bool_idx])  # 출력 "[3 4 5 6]"

# 위에서 한 모든것을 한 문장으로 할 수 있습니다:
print (a[a > 2])     # 출력 "[3 4 5 6]"

 

 

 

Numpy자료형

Numpy에선 배열을 구성하는 데 사용할 수 있는 다양한 숫자 자료형을 제공합니다. Numpy는 배열이 생성될 때 자료형을 스스로 추측합니다, 그러나 배열을 생성할 때 명시적으로 특정 자료형을 지정할 수도 있습니다

import numpy as np

x = np.array([1, 2])  # Numpy가 자료형을 추측해서 선택
print (x.dtype)         # 출력 "int64"

x = np.array([1.0, 2.0])  # Numpy가 자료형을 추측해서 선택
print (x.dtype)             # 출력 "float64"

x = np.array([1, 2], dtype=np.int64)  # 특정 자료형을 명시적으로 지정
print (x.dtype)                         # 출력 "int64"

 

 

 

 

배열 연산

기본적인 수학함수는 배열의 각 요소별로 동작하며 연산자를 통해 동작하거나 numpy 함수모듈을 통해 동작합니다

x = np.array([[1,2],[3,4]], dtype=np.float64)
y = np.array([[5,6],[7,8]], dtype=np.float64)

print(x)
#[[1. 2.]
#[3. 4.]]
print(y)
#[[5. 6.]
#[7. 8.]]

# 요소별 합; 둘 다 다음의 배열을 만듭니다
# [[ 6.0  8.0]
#  [10.0 12.0]]
print (x + y)
print (np.add(x, y))

# 요소별 차; 둘 다 다음의 배열을 만듭니다
# [[-4.0 -4.0]
#  [-4.0 -4.0]]
print (x - y)
print (np.subtract(x, y))

# 요소별 곱; 둘 다 다음의 배열을 만듭니다
# [[ 5.0 12.0]
#  [21.0 32.0]]
print (x * y)
print (np.multiply(x, y))

# 요소별 나눗셈; 둘 다 다음의 배열을 만듭니다
# [[ 0.2         0.33333333]
#  [ 0.42857143  0.5       ]]
print (x / y)
print (np.divide(x, y))

# 요소별 제곱근; 다음의 배열을 만듭니다
# [[ 1.          1.41421356]
#  [ 1.73205081  2.        ]]
print (np.sqrt(x))

 

 

dot함수

x = np.array([[1,2],[3,4]])
y = np.array([[5,6],[7,8]])

v = np.array([9,10])
w = np.array([11, 12])

print(x)
#[[1 2]
#[3 4]]

print(y)
#[[5 6]
#[7 8]]
print(v)
#[ 9 10]
print(w)
#[11 12]

# 벡터의 내적; 둘 다 결과는 219
print (v.dot(w))
print (np.dot(v, w))

# 행렬과 벡터의 곱; 둘 다 결과는 rank 1인 배열 [29 67]
print (x.dot(v))
print (np.dot(x, v))

# 행렬곱; 둘 다 결과는 rank 2인 배열
# [[19 22]
#  [43 50]]
print (x.dot(y))
print (np.dot(x, y))

 

 

 

Numpy sum

import numpy as np

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

print (np.sum(x))  # 모든 요소를 합한 값을 연산; 출력 "10"
print (np.sum(x, axis=0))  # 각 열에 대한 합을 연산; 출력 "[4 6]"
print (np.sum(x, axis=1))  # 각 행에 대한 합을 연산; 출력 "[3 7]"

 

 

 

 

np.transpose 트렌스포즈

import numpy as np

x = np.array([[1,2], [3,4]])
print (x)    # 출력 "[[1 2]
           #          [3 4]]"
print (x.T)  # 출력 "[[1 3]
           #          [2 4]]"


# rank 1인 배열을 전치할 경우 아무 일도 일어나지 않습니다:
v = np.array([1,2,3])
print (v)    # 출력 "[1 2 3]"
print (v.T)  # 출력 "[1 2 3]"

 

브로드 캐스팅

브로트캐스팅은 Numpy에서 shape가 다른 배열 간에도 산술 연산이 가능하게 하는 메커니즘

 

 

 

 

 

 작은 배열과 큰 배열이 있을 때, 큰 배열을 대상으로 작은 배열을 여러 번 연산하고자 할 때가 있습니다. 예를 들어, 행렬의 각 행에 상수 벡터를 더하는 걸 생각해보세요. 이는 다음과 같은 방식으로 처리될 수 있습니다

import numpy as np

# 행렬 x의 각 행에 벡터 v를 더한 뒤,
# 그 결과를 행렬 y에 저장하고자 합니다
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
y = np.empty_like(x)   # x와 동일한 shape를 가지며 비어있는 행렬 생성

# 명시적 반복문을 통해 행렬 x의 각 행에 벡터 v를 더하는 방법
for i in range(4):
    y[i, :] = x[i, :] + v

# 이제 y는 다음과 같습니다
# [[ 2  2  4]
#  [ 5  5  7]
#  [ 8  8 10]
#  [11 11 13]]

print (y)

위의 방식대로 하면 됩니다; 그러나 ‘x’가 매우 큰 행렬이라면, 파이썬의 명시적 반복문을 이용한 위 코드는 매우 느려질 수 있습니다. 벡터 ‘v’를 행렬 ‘x’의 각 행에 더하는 것은 ‘v’를 여러 개 복사해 수직으로 쌓은 행렬 ‘vv’를 만들고 이 ‘vv’를 ‘x’에 더하는것과 동일합니다. 이 과정을 아래의 코드로 구현할 수 있습니다

import numpy as np

# 벡터 v를 행렬 x의 각 행에 더한 뒤,
# 그 결과를 행렬 y에 저장하고자 합니다
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
vv = np.tile(v, (4, 1))  # v의 복사본 4개를 위로 차곡차곡 쌓은 것이 vv
print (vv)                 # 출력 "[[1 0 1]
                         #       [1 0 1]
                         #       [1 0 1]
                         #       [1 0 1]]"
y = x + vv  # x와 vv의 요소별 합
print (y)  # 출력 "[[ 2  2  4
           #       [ 5  5  7]
           #       [ 8  8 10]
           #       [11 11 13]]"

Numpy 브로드캐스팅을 이용한다면 이렇게 v의 복사본을 여러 개 만들지 않아도 동일한 연산을 할 수 있습니다. 아래는 브로드캐스팅을 이용한 예시 코드

import numpy as np

# 벡터 v를 행렬 x의 각 행에 더한 뒤,
# 그 결과를 행렬 y에 저장하고자 합니다
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
y = x + v  # 브로드캐스팅을 이용하여 v를 x의 각 행에 더하기
print (y)  # 출력 "[[ 2  2  4]
         #       [ 5  5  7]
         #       [ 8  8 10]
         #       [11 11 13]]"

두 배열의 브로드캐스팅은 아래의 규칙을 따릅니다:

  1. 두 배열이 동일한 rank를 가지고 있지 않다면, 낮은 rank의 1차원 배열이 높은 rank 배열의 shape로 간주합니다.
  2. 특정 차원에서 두 배열이 동일한 크기를 갖거나, 두 배열 중 하나의 크기가 1이라면 그 두 배열은 특정 차원에서 compatible하다고 여겨집니다.
  3. 두 행렬이 모든 차원에서 compatible하다면, 브로드캐스팅이 가능합니다.
  4. 브로드캐스팅이 이뤄지면, 각 배열 shape의 요소별 최소공배수로 이루어진 shape가 두 배열의 shape로 간주합니다.
  5. 차원에 상관없이 크기가 1인 배열과 1보다 큰 배열이 있을 때, 크기가 1인 배열은 자신의 차원 수만큼 복사되어 쌓인 것처럼 간주합니다.

 

import numpy as np

# 벡터의 외적을 계산
v = np.array([1,2,3])  # v의 shape는 (3,)
w = np.array([4,5])    # w의 shape는 (2,)
# 외적을 계산하기 위해, 먼저 v를 shape가 (3,1)인 행벡터로 바꿔야 합니다;
# 그다음 이것을 w에 맞춰 브로드캐스팅한뒤 결과물로 shape가 (3,2)인 행렬을 얻습니다,
# 이 행렬은 v와 w 외적의 결과입니다:
# [[ 4  5]
#  [ 8 10]
#  [12 15]]
print (np.reshape(v, (3, 1)) * w)

# 벡터를 행렬의 각 행에 더하기
x = np.array([[1,2,3], [4,5,6]])
# x는 shape가 (2, 3)이고 v는 shape가 (3,)이므로 이 둘을 브로드캐스팅하면 shape가 (2, 3)인
# 아래와 같은 행렬이 나옵니다:
# [[2 4 6]
#  [5 7 9]]
print (x + v)

# 벡터를 행렬의 각 행에 더하기
# x는 shape가 (2, 3)이고 w는 shape가 (2,)입니다.
# x의 전치행렬은 shape가 (3,2)이며 이는 w와 브로드캐스팅이 가능하고 결과로 shape가 (3,2)인 행렬이 생깁니다;
# 이 행렬을 전치하면 shape가 (2,3)인 행렬이 나오며
# 이는 행렬 x의 각 열에 벡터 w을 더한 결과와 동일합니다.
# 아래의 행렬입니다:
# [[ 5  6  7]
#  [ 9 10 11]]
print ((x.T + w).T)
# 다른 방법은 w를 shape가 (2,1)인 열벡터로 변환하는 것입니다;
# 그런 다음 이를 바로 x에 브로드캐스팅해 더하면
# 동일한 결과가 나옵니다.
print (x + np.reshape(w, (2, 1)))

# 행렬의 스칼라배:
# x 의 shape는 (2, 3)입니다. Numpy는 스칼라를 shape가 ()인 배열로 취급합니다;
# 그렇기에 스칼라 값은 (2,3) shape로 브로드캐스트 될 수 있고,
# 아래와 같은 결과를 만들어 냅니다:
# [[ 2  4  6]
#  [ 8 10 12]]
print (x * 2)

 

 

 

 

Matplotlib

 

우리가 가지고 있는 데이터를 시각화 시켜주는 라이브러리

import matplotlib.pyplot as plt
import tensorflow as tf
n = 20
y = tf.random.normal([n], 0, 1)
x = range(n)
plt.plot(x, y, 'k-') #k-는 실선 ko는 점/파란실선b- 파란점bo/빨간실선r- 빨간점ro
plt.show()

 

Plotting

matplotlib에서 가장 중요한 함수는 2차원 데이터를 그릴 수 있게 해주는 plot 입니다.

import numpy as np
import matplotlib.pyplot as plt

# 사인과 코사인 곡선의 x,y 좌표를 계산
x = np.arange(0, 3 * np.pi, 0.1)
y = np.sin(x)

# matplotlib를 이용해 점들을 그리기
plt.plot(x, y)
plt.show()  # 그래프를 나타나게 하기 위해선 plt.show()함수를 호출해야만 합니다.

 

 

약간의 몇 가지 추가적인 작업을 통해 여러 개의 그래프와 제목, 범주, 축 이름을 한 번에 쉽게 나타낼 수 있습니다

import numpy as np
import matplotlib.pyplot as plt

# 사인과 코사인 곡선의 x,y 좌표를 계산
x = np.arange(0, 3 * np.pi, 0.1)
y_sin = np.sin(x)
y_cos = np.cos(x)

# matplotlib를 이용해 점들을 그리기
plt.plot(x, y_sin)
plt.plot(x, y_cos)
plt.xlabel('x axis label')
plt.ylabel('y axis label')
plt.title('Sine and Cosine')
plt.legend(['Sine', 'Cosine'])
plt.show()

 

 

 

Subplots

‘subplot’함수를 통해 다른 내용도 동일한 그림 위에 나타낼 수 있습니다

import numpy as np
import matplotlib.pyplot as plt

# 사인과 코사인 곡선의 x,y 좌표를 계산
x = np.arange(0, 3 * np.pi, 0.1)
y_sin = np.sin(x)
y_cos = np.cos(x)

# 높이가 2이고 너비가 1인 subplot 구획을 설정하고,
# 첫 번째 구획을 활성화.
plt.subplot(2, 1, 1)

# 첫 번째 그리기
plt.plot(x, y_sin)
plt.title('Sine')

# 두 번째 subplot 구획을 활성화 하고 그리기
plt.subplot(2, 1, 2)
plt.plot(x, y_cos)
plt.title('Cosine')

# 그림 보이기.
plt.show()

 

 

 

 

 

 

 

 

(계속 수정중)

'파이썬' 카테고리의 다른 글

불리언(Boolean) : 참과 거짓  (0) 2021.05.07
양식문자(형식 제어 문자)  (0) 2021.05.07
숫자(Numeric) : 정수와 실수  (0) 2021.05.07
복합대입연산자  (0) 2021.05.07
파이썬 함수  (0) 2021.04.27