※ tokenization이란?

토큰화(tokenization)문장을 토큰으로 나누는 과정으로 수행대상에 따라 다음 세 방법이 있다.
- 문자
- 단어
- 서브워드
§ 문자 단위 토큰화
-  한글 위주로 표현된 데이터로 언어 모델을 만든다 하자.
한글 음절 수는 1만1172개이므로 알파벳, 숫자 등을 고려 해도 어휘 집합 크기는 최대 1만5000개를 넘기 어렵다.
게다가 해당 언어의 모든 문자를 어휘 집합에 포함하므로 미등록 토큰(unknown token) 문제로부터 자유롭다.
미등록 토큰이란 어휘 집합에 없는 토큰이다. (주로 신조어 등에서 발생)

하지만 문자 단위로 토큰화를 수행할 경우 단점도 있는데, 각 문자 토큰은 의미 있는 단위가 되기 어려운데,  예를 들어 어제와 어미간의  어의 구분이 모호해지는 것처럼 단점이 존재한다.
어제 카페 갔었어          > 어 / 제 / 카 / 페 / 갔 / 었 / 어
어제 카페 갔었는데요   > 어 / 제 / 카 / 페 / 갔 / 었 / 는 / 데 / 요

뿐만 아니라 문자 단위 토큰화는 앞의 단어 단위와 비교할 때 분석 결과인 토큰 시퀀스의 길이가 상대적으로 길어졌음을 확인할 수 있다. 언어 모델에 입력할 토큰 시퀀스가 길면 모델이 해당 문장을 학습하기가 어려워지고 결과적으로 성능이 떨어지게 된다.
§ 단어(어절) 단위 토큰화
- 가장 쉽게 생각해보면 공백으로 분리할 수 있다. 
어제 카페 갔었어          > 어제 / 카페 / 갔었어
어제 카페 갔었는데요   > 어제 / 카페 / 갔었는데요

공백으로 분리하면 별도의 토크나이저를 쓰지 않아도 된다는 장점이 있다.
다만, 어휘 집합의 크기가 매우 커질 수 있는데,  갔었어, 갔었는데요 처럼 표현이 살짝만 바뀌어도 모든 경우의 수가 어휘 집합에 포함돼야 하기 때문이다.

만약 학습된 토크나이저를 사용하면 어휘 집합의 크기가 커지는 것을 조금 완화할 수는 있다.
예를 들어 같은 문장을 은전한닢으로 토큰화하면 다음과 같다.
예시가 적어서 효과가 도드라져 보이지는 않지만, 의미 있는 단위로, (예를 들면 갔었) 토큰화해 어휘 집합이 급격하게 커지는 것을 다소 막을 수 있다.
어제 카페 갔었어 > 어제 / 카페 / 갔었 / 어
어제 카페 갔었는데요 > 어제 / 카페 / 갔었 / 는데요

그렇지만 위 같은 토크나이저를 사용하더라도 어휘 집합 크기가 지나치게 커지는 것은 막기 어려운데,  보통 언어 하나로 모델을 구축할 때 어휘 집합 크기는 10만 개를 훌쩍 넘는 경우가 다반사이기에 어휘 집합 크기가 커지면 그만큼 모델 학습이 어려워질 수 있다.
§ 서브워드 단위 토큰화
- 단위 토큰화는 단어와 문자 단위 토큰화의 중간에 있는 형태로. 둘의 장점만을 취한 형태이다.
어휘 집합 크기가 지나치게 커지지 않으면서도 미등록 토큰 문제를 피하고,
분석된 토큰 시퀀스가 너무 길어지지 않게 한다.
- 대표적인 서브워드 단위 토큰화 기법이라면 바이트 페어 인코딩을 들 수 있는데 아래에서 소개하겠다.

 

 

※ Byte Pair Encoding  Algorithm

- BPE는 정보를 압축하는 알고리즘으로 원래 제안된 것으로 데이터에서 최빈문자열을 병합해 압축하는 기법이다.

최근에는 자연어 처리모델에서 쓰이는 토큰화 기법이다.

GPT 모델은 BPE기법으로 토큰화를 수행

BERT모델은 BPE와 유사한 워드피스(wordpiece)를 토크나이저로 사용

 

예를 들어 다음과 같은 데이터가 있다고 가정하자.

  • aaabdaaabac

BPE는 데이터에 등장한 글자(a, b, c, d)를 초기 사전으로 구성하며, 연속된 두 글자를 한 글자로 병합한다.

이 문자열에선 aa가 가장 많이 나타났으므로 이를 Z로 병합(치환)하면 다음과 같이 압축할 수 있다.

  • ZabdZabac

이 문자열은 한번 더 압축 가능한데,  ab가 가장 많이 나타났으므로 이를 Y로 병합(치환)한다.

  • ZYdZYac

물론 ab 대신 Za를 병합할 수도 있지만 둘의 빈도수가 2로 같으므로 알파벳 순으로 앞선 ab를 먼저 병합한다.

ZY 역시 X로 병합할 수 있습니다. 이미 병합된 문자열 역시 한 번 더 병합할 수 있다는 얘기로 다음과 같다.

  • XdXac

 

※ BPE 어휘집합 구축하기.

1. pre-tokenize 진행 (말뭉치를 준비 후 모든 문장을 공백으로 나눠줌. 물론 다른 기준으로 나눌 수도 있음)

2. pre-tokenize 진행 후 그 빈도를 모두 세어 초기 어휘 집합을 구한다.

3. 위의 어휘집합을 바이그램 쌍(토큰을 2개씩 묶어 나열)으로 만들고 바이그램 쌍을 합친다.

4. 가장 많이 등장한 바이그램쌍을 합쳐 집합에 추가 (위를 예로 들면 u, g를 합친 ug를 바이그램에 추가)

>> b / g / h / n / p / s / u / ug

이후 계속 사용자가 정한 크기 전까지 반복해서 진행.

 

5. 입력이 들어오면 입력을 문자단위로 분리 후 병합의 우선순위(by 빈도)에 따라 merge 진행.

만약 input으로 mug가 들어온다면?

따라서 출력은 다음과 같이  <unk>, ug로 나오며 <unk>는 unkown token(미등록 토큰)을 의미.

 

 

 

※ WordPiece.

BPE와 비슷하지만 빈도를 기준으로 merge를 진행하는 BPE와는 달리

Wordpiece는 likelihood를 기준으로 likelihood가 높은 쌍을 merge한다.

 

병합후보 A, B에 대해 워드피스의 병합기준 식은 다음과 같다.

이 식의 값이 높은 값을 기준으로 병합을 진행하며 

n은 전체 글자수를 가리키고 a, b, ab는 각각의 문자열의 빈도수를 뜻한다.

즉, a,b는 각각의 문자가 등장할 확률이고 ab는 ab가 연이어 등장할 확률이다.

 

 

 

 

 

※ 자연어와 자연어 처리

자연어(natural language)란 우리가 일상 생활에서 사용하는 언어로 자연어 처리(natural language processing)란 이러한 자연어의 의미를 분석하여 컴퓨터가 처리하는 것이다.
좀 더 구체화 시키면 입력(자연어)을 받아서 해당 입력이 특정 범주일 확률을 반환하는 확률함수이다.
이런 확률을 기반으로  후처리(post processing)을 해서 자연어형태로 바꿔줄 수 도 있다.

자연어 처리는 음성 인식, 내용 요약, 번역, 사용자의 감성 분석, 영화 평론의 긍정 및 부정, 텍스트 분류 작업(스팸 메일 분류, 뉴스 기사 카테고리 분류), 질의 응답 시스템, 챗봇과 같은 곳에서 사용되는 분야 등 다양하다.

이런 자연어 처리에 다양한 모델이 사용되고 요즘 가장 인기있는 모델은 단연, 딥러닝이다.
딥러닝 가운데서도 딥러닝 기반 자연어 처리 모델에는 BERT, GPT 등이 있다.

 

 

※ Task란?

- 준비한 모델, 최적화 방법 및 학습과정 등이 정의되어 있는 것.
- 우리는 특정 조건에서 모델의 output과 정답의 차이를 작게하는게 중요, optimizer, learning rate scheduler를 정의.

모델 학습은 batch단위로 이뤄지는데, batch를 모델에 입력한 후 모델 출력을 정답과 비교해 차이를 계산한다.
그 후 차이를 최소화하는 방향으로 모델을 update하는데, 이런 일련의 과정을 step이라 하며 task의 학습과정은 1step을 기준으로 정의한다.

 

 

 

 

※ Transfer Learning

특정 data를 학습한 모델을 다른 data train을 할 때 재사용하는 방법

- 장점: 학습속도가 기존보다 빠르고 새로운 data를 더 잘 수행할 수 있어 BERT, GPT 등도 transfer learning이 적용된다.

 

§ Upstream Task
- Transfer Learning이 주목된 것은 upstream task와 pretrain덕분으로 자연어의 다양한 context를 모델에 내재화하고 다양한 down stream task에 적용해 성능을 끌어올렸기 때문이다.
이는 기존의 지도학습과 달리 다량의 학습데이터를 웹문서, 뉴스 등의 쉽게 구할 수 있는 데이터와 이를 upstream task를 통해 수행하여 성능이 월등히 좋아졌다.
즉, 데이터 내에서 정답을 만들고 이를 통해 모델을 학습하는 자기지도학습(self-supervised learning)을 진행.

▶ Masked Language Model
- 아래와 같이 빈칸에 들어가야할 단어에 대해 주변 문맥을 보고 해당 빈칸의 단어에 해당하는 확률은 높이고
나머지 단어들의 확률을 낮추는 방향으로 모델 전체를 update한다.

 

 

§ Downstream Task
- 위에서 진행한 upstream으로 pretrain을 한 이유downstream task을 잘하기 위해서이다.
  이런 downstream task는 자연어처리의 구체적인 과제들이다.
  예를 들자면 분류(classification)처럼 입력이 어떤 범주에 해당하는지 확률형태로 반환한다.
- 문장생성을 제외대부분은 pretrain을 마친 Masked Language Model (BERT, etc.)을 사용한다.

ex. 문서분류, 자연어 추론, 개체명 인식, 질의응답, 문장생성 등에 대해 처리한다.


▶ Fine-tuning
- downstream task의 학습방식 중 하나로 pretrain을 마친 모델을 downstream task에 맞게 update하는 기법이다.

https://ratsgo.github.io/nlpbook/docs/introduction/transfer/#%EB%8B%A4%EC%9A%B4%EC%8A%A4%ED%8A%B8%EB%A6%BC-%ED%83%9C%EC%8A%A4%ED%81%AC

 

 

 

 

 

 

 

※ 모듈과 모듈 불러오기

모듈과 모듈 불러오기: 사람이 만든 py 파일으로 파이썬에서 불러와 사용하는 방법

import 모듈이름
from 모듈이름 import 모듈함수

 

※ 패키지

파이썬에서 모듈은 하나의 .py파일이다.

파이썬 패키지는 디렉토리와 파이썬 모듈로 이뤄진다.

 

 

 

 

※ 라이브러리 

python을 설치하면서 python 라이브러리는 자동으로 설치된다.

 

 

 

 

 

 

 

※ 내장 함수 

 

※ abs(x)

- x의 절댓값을 돌려주는 함수

 

 

※ pow(x, y)

- pow(x, y)는 x^y결과값을 돌려주는 함수

pow(3, 4)   #81 출력

 

※ round

round(number[, ndigits]) 함수는 숫자를 입력받아 반올림해 주는 함수

아래와 같이 소수점 3자리까지 반올림하여 표시할 수 있다.

print(round(5.6756438, 3))  # 5.676 출력

 

 

※ max와 min

iterable 즉, 반복가능한 자료형을 입력받아 최대, 최소값을 돌려주는 함수이다.

max([1, 2, 3])  # 3출력
min([1, 2, 3])  # 1출력

 

※ sum

sum(iterable) 은 입력받은 리스트나 튜플의 모든 요소의 합을 돌려주는 함수

sum((4,5,6))   # 15출력

 

※ divmod(x, y)

- (x//y ,  x%y)의 값을 돌려주는 함수로 튜플형태로 돌려주는 함수이다.

print(divmod(7, 3))     # (2, 1)출력

 

※ oct(x) 와  hex(x) 

- 8진수,  16진수로 변환해 돌려주는 함수다.

 

 

 

※ ord(x) 와 chr(x)

- x값 문자를 ASCII code값으로 출력하는 함수

- x의 ASCII code 값을 입력 받아 해당하는 문자를 출력하는 함수

print(ord("a"))     # 97 출력
print(ord("가"))    # 44032 출력
print(chr(97))      # a 출력
print(chr(44032))   # 가 출력

 

 

 

 

 

 

※ enumerate

- 순서가 있는 자료형인 리스트, 튜플, 문자열을 입력을 인덱스값을 포함하는 객체로 돌려준다.

for i, name in enumerate(['body', 'foo', 'bar']):
    print(i, name)

#----출력----#
0 body
1 foo
2 bar

 

 

※ eval 

- 실행가능한 문자열을 입력으로 받아 문자열을 실행한 결과를 돌려주는 함수

print(eval("divmod(4, 3)"))     #(1, 1) 출력

 

 

※ filter 

- filter함수는 첫번째 인수로 함수이름, 두번째 인수로 그 함수에 차례로 들어갈 반복가능한 자료형을 받는다.

이때, 반환값이 참인 것만 걸러서 돌려준다.

def positive(l):
    result = []
    for i in l:
        if i > 0:
            result.append(i)
    return result
print(positive([1,-3,2,0,-5,6]))




##### 와 같은 함수를 다음과 같이 사용가능하다.#####
def positive(x):
    return x > 0

print(list(filter(positive, [1, -3, 2, 0, -5, 6])))


##### 와 같은 함수를 다음과 같이 사용가능하다.#####
list(filter(lambda x: x > 0, [1, -3, 2, 0, -5, 6]))

 

 

 

※ len(s) 

- s의 길이 (요소의 전체 개수)를 돌려주는 함수

len("python")   # 6출력

len([1, 2, 3])  # 3출력

len((1, 'a'))   # 2출력

 

 

 

 

※ list와 map 

list("python")     #['p', 'y', 't', 'h', 'o', 'n']
b = list(a)
def two_times(x):
    return 2*x

list(map(two_times, [1, 2, 3, 4]))  # [2, 4, 6, 8] 출력
list(map(lambda a: 2*a, [1, 2, 3, 4]))

 

 

※ range 

- range([start,] stop [,step] )는 for문과 함께 자주 사용하는 함수

list(range(1,10,2))   # [1, 3, 5, 7, 9] 출력

 

 

※ sorted 

- sorted(iterable) 함수는 입력값을 정렬한 후 그 결과를 리스트로 돌려주는 함수

sorted((3, 2, 1))   # [1, 2, 3]

 

 

※ str 

- str(object)은 문자열 형태로 객체를 변환하여 돌려주는 함수

str('hi'.upper())   # HI 출력

 

 

 

 

 

※ 함수

def add(a, b):   #a, b라는 매개변수
    return a+b

print(add(10,14))   # 24출력

 

 

※ 입력값이 몇개가 될 지 모른다면?

def 함수명 (*매개변수):
    수행문장

 

Ex-1)

def adds(*arg):
    sum = 0
    for i in arg:
        sum += i
    return sum


print(adds(1,2,3,3,4,5,6,6,6,77))   # 113 출력

 

Ex-2)

def add_mul(choice, *args):
    if choice == "add":
        result = 0
        for i in args:
            result = result + i

    elif choice == "mul":
        result = 1
        for i in args:
             result = result * i

    return result

print(add_mul("add", 1,2,3,3,4,5,6,6,6,77))   # 113 출력
print(add_mul("mul", 1,2,3,3,4,5,6,6,6,77))   # 5987520 출력

 

 

※ 키워드 파라미터 - feat. 딕셔너리

입력값의 개수를 모르고 딕셔너리로 만들고 싶을 때, **를 이용할 수 있다.

def print_kwargs(**kwargs):
    print(kwargs)

print_kwargs(name = "V2LLAIN", age = 22)

#--------출력--------#
{'name': 'V2LLAIN', 'age': 22}

 

 

 

 

※ lambda 

함수를 생성 시 사용하는 예약어로 보통 함수를 한줄로 간결하게 만들 때 사용

add = lambda a, b: a+b

print(add(3, 4))

※ lambda 함수는 return 명령이 없어도 결과값을 돌려준다.

 

 

 

 

 

 

 

 

 

 

※ 클래스 

class Calculator:
    def __init__(self):
        self.result = 0

    def add(self, num):
        self.result += num
        return self.result

cal1 = Calculator()     # 객체 cal1 생성
cal2 = Calculator()     # 객체 cal2 생성

print(cal1.add(3))
print(cal1.add(4))
print(cal2.add(3))
print(cal2.add(7))


#----출력----#
3
7
3
10

 

class Calculator:
    def setAddData(self, first, second):
        self.first = first
        self.second = second
        return first+second

cal = Calculator()

print(cal.setAddData(4, 2))     # 6출력

python에서는 this대신 self를 사용한다. 이때, 첫번째 매개변수인 self는 관례적 사용이다.

python은 다른 언어와 달리 self를 명시적으로 구현한다.

출처: https://wikidocs.net/28

 

class Calculator:
    def setData(self, first, second):
        self.first = first
        self.second = second
    def AddData(self):
        result = self.first + self.second
        return result

cal = Calculator()
cal.setData(10, 14)

print(cal.AddData())     # 24출력

 

 

 

※ _ _init_ _  초기화 함수

파이썬 함수이름으로 __init__을 사용하면 이 함수는 생성자가 된다.

class Calculator:
    def __init__(self, first, second):
        self.first = first
        self.second = second

    def setData(self, first, second):
        self.first = first
        self.second = second

    def AddData(self):
        result = self.first + self.second
        return result

cal = Calculator(10, 14)

print(cal.AddData())     # 24출력

 

 

 

 

 

 

 

※ 클래스의 상속 

상속은 기존 클래스를 변경하지 않고 기능을 추가, 변경 시 사용한다.

class Calculator:
    def __init__(self, first, second):
        self.first = first
        self.second = second

    def setData(self, first, second):
        self.first = first
        self.second = second

    def AddData(self):
        result = self.first + self.second
        return result

class CalPower(Calculator):
    def power(self):
        return self.first ** self.second

cal = CalPower(10, 4)

print(cal.power())     # 10000출력

 

 

 

 

 

 

 

 

 

 

 

 

 

※ AND, OR, NOT

다른 언어에서 &&, ||, ! 처럼 사용하는 것에 비해 파이썬에서는 다음과 같이 사용한다.

and, or, not

이를 이용한 if문을 다음과 같이 만들 수 있다.

money = 10000
card = True

if money >= 15000 or card:
    print("restauraunt")   # <= 이거 출력
else:
    print("CU")

 

 

※ pass

조건문에서 아무일도 일어나지 않게 설정하고 싶을 때 사용하는 키워드

a = [1, 2, 3]

if 1 in a:
    pass   
else:
    print("not here")

 

 

 

※ 리스트, 튜플, 문자열과 관련된 in 조건문

다른 언어와 달리 파이썬이 갖는 특이한 조건문으로 in과 not in을 이용하는 조건문이 있다.

str = "Python is nice"

if "is" in str:
    print("It's here")   # <= 이거 출력
else:
    print("not here")
a = [1, 2, 3]

if 1 in a:
    print("It's here")   # <= 이거 출력
else:
    print("not here")

 

 

 

 

※ 조건부 표현식

마치 3항연산자처럼 다음과 같은 형식을 갖고 있다.

조건이 참일 때 if  조건문 else 조건이 거짓일 때
a = [1, 2, 3]

print("It's here") if 1 in a else print("not here")

 

 

 

 

 

 

※ while문을 이용한 조건문

prompt = """
1. Add  2. Del  3. List 4. Quit
Enter num: """

num = 0

while num != 4:
    print(prompt)
    num = int(input())

 

 

 

※ for문을 이용한 조건문

§ for문의 기본구조

for i in 리스트, 튜플, 문자열:
    수행문장

Ex-1)

a = ['one', 'two', 'three']

for i in a:
    print(i)

#---출력---#
one
two
three

 

Ex-2)

a = [(1,2), (3,4), (5,6)]
for (first, last) in a:
    print(first + last)

#---출력---#
3
7
11

이는 튜플을 사용한 변수대입 방법과 매우 비슷하다.

(first, last) = (1,2)

 

 

Ex-3)

marks = [90, 25, 67, 45, 80]

number = 0
for mark in marks:
    number = number +1
    if mark >= 60:
        print("%d번 학생은 합격입니다." % number)
    else:
        print("%d번 학생은 불합격입니다." % number)
        
#--------출력--------#
1번 학생은 합격입니다.
2번 학생은 불합격입니다.
3번 학생은 합격입니다.
4번 학생은 불합격입니다.
5번 학생은 합격입니다.

 

 

 

※ for문과 함께 자주 사용하는 range 함수 

§ range(시작 숫자, 끝 숫자)

이때, 끝 숫자는 포함되지 않는다.

 

Ex-1)

add = 0
for i in range(1, 11):
    add = add + i
print(add)  # 55출력

 

Ex-2)

marks = [90, 25, 67, 45, 80]

number = 0 
for mark in marks: 
    number = number +1 
    if mark < 60:
        continue 
    print("%d번 학생 축하합니다. 합격입니다. " % number)

#--------출력--------#
1번 학생 축하합니다. 합격입니다.
3번 학생 축하합니다. 합격입니다.
5번 학생 축하합니다. 합격입니다.

 

marks = [90, 25, 67, 45, 80]
for number in range(len(marks)):
    if marks[number] < 60:
        continue
    print("%d번 학생 축하합니다. 합격입니다." % (number+1))

#--------출력--------#
1번 학생 축하합니다. 합격입니다.
3번 학생 축하합니다. 합격입니다.
5번 학생 축하합니다. 합격입니다.

 

 

Ex-3)

end=" "은 print가 출력할 때 개행처리를 하지 않고 계속 처리하게 한다.

for i in range(2,10):        # 1번 for문
     for j in range(1, 10):   # 2번 for문
         print(i*j, end=" ")
     print()  # 단이 종료되면 결과값을 다음줄에 출력하게 함

#--------출력--------#
2 4 6 8 10 12 14 16 18
3 6 9 12 15 18 21 24 27
4 8 12 16 20 24 28 32 36
5 10 15 20 25 30 35 40 45
6 12 18 24 30 36 42 48 54
7 14 21 28 35 42 49 56 63
8 16 24 32 40 48 56 64 72
9 18 27 36 45 54 63 72 81

 

 

 

 

 

※ 리스트 안에 for문 포함 (리스트 내포)

a = [1,2,3,4]
result = []
for num in a:
    result.append(num*3)

print(result)

#--------출력--------#
[3, 6, 9, 12]

이 코드를 다음과 같이 표현할 수 있다.

a = [1,2,3,4]
result = [num * 3 for num in a]

print(result)

#--------출력--------#
[3, 6, 9, 12]

 

 

만약 짝수 숫자에만 3을 곱하고 싶다면?

리스트 내포 안에 if조건문을 사용!

a = [1,2,3,4]
result = [num * 3 for num in a if num % 2== 0]

print(result)

#--------출력--------#
[6, 12]

 

이는 다음과 같이도 사용할 수 있다.

result = [x * y for x in range(2,10)
          for y in range(1,10)]

print(result)

#--------출력--------#
[2, 4, 6, 8, 10, 12, 14, 16, 18, 3, 6, 9, 12, 15, 18, 21, 24, 27, 4, 8, 12, 16, 20, 24, 28, 32, 36, 5, 10, 15, 20, 25, 30, 35, 40, 45, 6, 12, 18, 24, 30, 36, 42, 48, 54, 7, 14, 21, 28, 35, 42, 49, 56, 63, 8, 16, 24, 32, 40, 48, 56, 64, 72, 9, 18, 27, 36, 45, 54, 63, 72, 81]

※ 딕셔너리

key : value 쌍의 형태가 { }로 둘러쌓인 구조로 이루어져있으며 쉼표로 구분되어 있는 자료형이다.

(key는 불변값, value는 불변과 가변 모두 사용할 수 있다.)

따라서! key값이 중복해서 사용하지 말아야 한다는 것을 유의하자!

dic = {"name" : "V2LLAIN", "height" : "175", "country" : "Korea"}

print(dic["name"])  # V2LLAIN 출력
key value
name V2LLAIN
height 175
country Korea

 

 

 

 

 

※ 딕셔너리에 쌍 추가,삭제하기

§ 딕셔너리 쌍 추가하기

a = {1 : "a"}

a[2] = "b"
a["country"] = "Korea"

print(a)

#-----------------출력----------------#
{1: 'a', 2: 'b', 'country': 'Korea'}

§ 딕셔너리 쌍 삭제하기

a = {1 : "a"}
a[2] = "b"
a["country"] = "Korea"
# {1: 'a', 2: 'b', 'country': 'Korea'}

del a["country"]

print(a)    #출력: {1: 'a', 2: 'b'}

 

 

 

※ 딕셔너리 관련 함수 (keys, values, items, clear, get, in)

§ Key로 이루어진 리스트 만들기 (keys)

list 고유의 append, insert, pop, remove, sort함수를 사용할 수는 없다.

a = {'name': 'pey', 'phone': '0119993323', 'birth': '1118'}

print(a.keys())

print(list(a.keys()))

for i in a.keys():
    print(i)

#-----------------출력----------------#
dict_keys(['name', 'phone', 'birth'])
['name', 'phone', 'birth']
name
phone
birth

 

 

§ Value 리스트 만들기 (values)

a = {'name': 'pey', 'phone': '0119993323', 'birth': '1118'}

print(a.values())

print(list(a.values()))

for i in a.values():
    print(i)

#-----------------출력----------------#
dict_values(['pey', '0119993323', '1118'])
['pey', '0119993323', '1118']
pey
0119993323
1118

 

 

§ Key, Value 쌍 얻기 (items)

a = {'name': 'pey', 'phone': '0119993323', 'birth': '1118'}

print(a.items())

print(list(a.items()))

for i in a.items():
    print(i)

#-----------------출력----------------#
dict_items([('name', 'pey'), ('phone', '0119993323'), ('birth', '1118')])
[('name', 'pey'), ('phone', '0119993323'), ('birth', '1118')]
('name', 'pey')
('phone', '0119993323')
('birth', '1118')

 

 

§ Key : Value 쌍 모두 지우기 (clear)

a = {'name': 'pey', 'phone': '0119993323', 'birth': '1118'}

a.clear()
print(a)    # {} 출력

 

 

§ Key로 Value 얻기 (get)

a = {'name': 'pey', 'phone': '0119993323', 'birth': '1118'}

print(a.get('name'))    # pey 출력

 

 

§ Key가 딕셔너리에 있는지 조사 (in)  -  True, False 반환

a = {'name': 'pey', 'phone': '0119993323', 'birth': '1118'}

print('name' in a)    # True 출력
print('height' in a)  # False 출력  

 

 

 

 

 

 

 

 

 

 

 

※ 집합 (set) 

set 키워드를 사용해 집합에 관련된 것을 쉽게 처리하기 위한 자료형이다.

s1 = set([1,2,3])
s2 = set("Hello")

print(s1)    # {1, 2, 3} 출력
print(s2)    # {'e', 'l', 'H', 'o'}과 같이 출력 (출력값 바뀔 수도 있음)

위에서 보면 print(s2)의 결과가 예상과 달리 나와 의문이었다.

이와 관련해 집합의 2가지 특징이 작용한다.

1. 중복을 허용하지 않는다.
2. 순서가 없다.

리스트나 튜플은 순서가 있기에 indexing을 통한 자료형값을 얻을 수 있다.

하지만 딕셔너리나 set 자료형은 순서가 없어서 indexing으로 값을 얻을 수 없다.

따라서 저장된 값을 indexing으로 접근하려면 리스트나 튜플로 변환 후 가능하다!

 

s = set([1,2,3])
a = list(s)

print(a)    
# {1, 2, 3}와 같은 set형식이 아닌 [1, 2, 3]같은 list형식으로 출력
s = set([1,2,3])
a = list(s)

print(a[2]) # 3출력

 

 

 

 

 

※ 합집합, 교집합, 차집합 구하기  ( |, &, -  )

s1 = set([1, 2, 3, 4, 5, 6])
s2 = set([4, 5, 6, 7, 8, 9])

 

§ 합집합 ( | )

s1 = set([1, 2, 3, 4, 5, 6])
s2 = set([4, 5, 6, 7, 8, 9])

print(s1 & s2)  # {4, 5, 6} 출력

 

§ 교집합 ( & )

s1 = set([1, 2, 3, 4, 5, 6])
s2 = set([4, 5, 6, 7, 8, 9])

print(s1 | s2)  # {1, 2, 3, 4, 5, 6, 7, 8, 9} 출력

 

§ 차집합 ( - )

s1 = set([1, 2, 3, 4, 5, 6])
s2 = set([4, 5, 6, 7, 8, 9])

print(s1 - s2)  # {1, 2, 3} 출력

 

 

 

 

 

 

 

 

※ 딕셔너리 관련 함수 (add, update, remove)

§ 값 1개 추가 (add)

s = set([1, 2, 3])
s.add(4)

print(s)  # {1, 2, 3, 4} 출력

 

§ 값 여러 개 추가 (update)

s = set([1, 2, 3])
s.update([4, 5, 6])

print(s)  # {1, 2, 3, 4, 5, 6} 출력

 

§ 특정값 제거 (remove)

s = set([1, 2, 3])
s.remove(2)

print(s)  # {1, 3} 출력

 

※ 리스트

리스트는 다른 언어의 배열과 같은 역할을 하며 다음과 같이 사용한다.

리스트형 변수 = [요소1, 요소2, ... ]

 

a = [1, 2, ['a', 'b', ['Life', 'is']]]

print(a[-1][-1][0])
print(a[2][2][0])

#--------출력--------#
# 둘 다 Life가 출력됨

 

 

 

※ 리스트 슬라이싱(slicing)

문자열 슬라이싱과 동일한 방법으로 진행된다.

a = [1, 2, 3, 4, 5]

print(a[1:3])   #출력: [2, 3]

 

 

 

 

※ 리스트 연산

§ 리스트 덧셈

a = [1, 2, 3]
b = [4, 5, 6]

print(a+b)

#--------출력--------#
[1, 2, 3, 4, 5, 6]

 

리스트는 같은 자료형의 집합이기에 다른 리스트간의 덧셈을 위해서는 형변환이 필요하다.

이때, str함수는 정수,실수를 문자열형태로 바꿔주는 내장함수이다.

a = [1, 2, 3]

print(str(a[2]) + "hi")   # 3hi

 

 

 

§ 리스트 반복

a = [1, 2, 3]

print(a*3)

#--------출력--------#
[1, 2, 3, 1, 2, 3, 1, 2, 3]

 

 

§ 리스트 길이(len)

a = [1, 2, 3]

print(len(a))   # 3출력

 

 

§ 리스트 수정과 삭제(del)

a = [1, 2, 3]

a[2]=4
print(a)    #출력: [1, 2, 4]

del a[1]
print(a)    #출력: [1, 4]

arr = [1,2,3,4,5]
del arr[2:]
print(arr)  #출력: [1, 2]

 

 

 

 

§ 리스트 복사

a = [1,2,3]
b = a

print(id(a))
print(id(b))

#-----출력-----#
2423373358208
2423373358208

a와 b의 값이 동일함을 알 수 있는데, 이를 아래와 같이 알 수 있다.

a = [1,2,3]
b = a

print(a is b)   # True

따라서 a객체와 b객체가 동일한 주소값을 갖고 있음을 알 수 있기에

 

아래와 같은 양상이 일어날 수 있다.

a = [1,2,3]
b = a

a[1] = 4
print(a)    # [1, 4, 3]
print(b)    # [1, 4, 3]

그렇다면 a값을 가져오지만 a와 다른 주소를 가리키도록 할 수는 없을까?

 

1. slicing 이용

a = [1,2,3]
b = a[:]

a[1] = 4

print(a)    # [1, 4, 3]
print(b)    # [1, 2, 3]

 

2. copy()함수나 copy를 import하여 사용 

a = [1,2,3]
b = a.copy()

a[1] = 4

print(a)    # [1, 4, 3]
print(b)    # [1, 2, 3]

 

from copy import copy

a = [1,2,3]
b = copy(a)

a[1] = 4

print(a)    # [1, 4, 3]
print(b)    # [1, 2, 3]

 

 

 

 

 

 

 

 

 

 

※ 리스트 관련 함수(append, sort, reverse, index, insert, remove, pop, count, extend)

 

§ 리스트 요소 추가 (append)

a = [1, 2, 3]

a.append(4)
print(a)    # [1, 2, 3, 4] 출력

a.append([5, 6])
print(a)    # [1, 2, 3, 4, [5, 6]] 출력

 

 

§ 리스트 정렬과 뒤집기 (sort ,reverse)

a = [1, 4, 3, 2]

a.sort()
print(a)    # [1, 2, 3, 4] 출력
a = [1, 4, 3, 2]

a.reverse()
print(a)    # [2, 3, 4, 1] 출력

 

 

§ 리스트 위치반환 (index)

a = [1, 4, 3, 2]

print(a.index(4))    # 1출력

 

 

 

§ 리스트 요소 삽입 ( insert(i, x) )

insert(i, x)는 i번째에 x를 삽입하는 함수이다.

a = [1, 4, 3, 2]
a.insert(4, 5)

print(a)    # [1, 4, 3, 2, 5] 출력

 

 

 

§ 리스트 요소 삭제 (remove)

첫 번째로 나오는 값을 삭제

a = [1, 2, 3, 1, 2, 3]
a.remove(2)

print(a)    # [1, 3, 1, 2, 3] 출력

 

 

 

§ 리스트 요소 끄집어내기 (pop)

리스트 마지막 값을 pop(출력 후 삭제)

pop(i)로 i번째 index를 출력 후 삭제

a = [1, 2, 3, 1, 2, 3]

a.pop()
print(a)         # [1, 2, 3, 1, 2] 출력

print(a.pop(2))  # 3출력
print(a)         # [1, 2, 1, 2] 출력

 

 

 

§ 리스트에 포함된 요소x 개수 세기 ( count (x) )

a = [1, 2, 3, 1, 1, 1]

print(a.count(1))   # 4출력

 

 

 

§ 리스트 확장 (extend(리스트))

a.extend(x)에서는 x값은 리스트만 올 수 있으며 원래 리스트 a에 x를 더한다.

a = [1, 2, 3]
b = [4, 5]

a.extend(b)
a.extend([6, 7])
print(a)   # [1, 2, 3, 4, 5, 6, 7] 출력

 

 

 

 

 

 

 

 

 

※ 튜플

리스트와 몇가지를 제외하면 거의 비슷하다.

 

<리스트와 다른점>

- 리스트는 [ ]이고 튜플은 ( )이며 (생략가능) 한 개의 요소만 가질 때는 쉼표가 필요하다.

- 리스트는 값의 생성, 삭제, 수정이 가능

- 튜플은 위와 같은 값의 변경이 불가능하다.

 

따라서 이런 값의 불변성 때문에 평균적으로는 리스트를 더 많이 사용한다.

리스트형 변수 = [요소1, 요소2, ... ]

 

a = [1, 2, ['a', 'b', ['Life', 'is']]]

print(a[-1][-1][0])
print(a[2][2][0])

#--------출력--------#
# 둘 다 Life가 출력됨

 

 

 

※ 튜플의 인덱싱과 슬라이싱(slicing)

a = (1, 2, 'a', 'b')

print(a[0])     # 1출력
print(a[0:3])   # (1, 2, 'a') 출력

 

 

※ 튜플의 덧셈, 곱셈, 길이구하기

t1 = (1, 2, 'a', 'b')
t2 = (3, 4)

print(t1+t2)    # (1, 2, 'a', 'b', 3, 4)
print(t2 * 3)   # (3, 4, 3, 4, 3, 4)
print(len(t1))  # 4 출력

 

※ python 입력, 출력 받기

§ 입력받기

a = input()

 

a = input("입력하세요: ")
print(a)

#--------출력--------#
입력하세요: 3
3

 

 

§ 출력 형식

print("Life"+"is"+"too"+"short")
print("Do", "Python")   # 콤마(,)로 문자열 사이 띄어쓰기 가능

#--------출력--------#
Lifeistooshort
Do Python

 

 

※ 곱셈, n제곱, 나눗셈, 몫 출력

a = 7*4   # 7x4
a = 7**4  # 7^4

print(a)
a = 7 / 4    # 나눗셈 결과 반환 (1.75 출력)
a = 7 // 4   # 나눗셈 후 몫 반환 (1 출력)

print(a)

 

 

§ 문자열 길이구하기

head = "Python"
print(len(head))

 

 

※ 문자열과 개행처리(\n)

str = "Life is too short\nYou need python"
print(str)

#-------출력-------#
# Life is too short
# You need python

출처:&nbsp;https://wikidocs.net/13

 

 

 

※ 문자열 더하기와 곱하기

head = "Python"
tail = " is EZ"

print("-"*15+"\n"+head+tail+"\n"+"-"*15)

<출력>
---------------
Python is EZ
---------------

 

cf. 쉼표(,)를 넣으면 한칸씩 띄워서 출력된다.

head = "Python"
tail = " is EZ"

print("-"*15,"\n",head+tail, "\n","-"*15)

<출력>
--------------- 
 Python is EZ 
 ---------------

 

 

 

 

※ 문자열 포매팅

a = "Python%d is %s" %(3, "EZ")

print(a)
a = "Python{0} is {1}".format(3, "EZ")

print(a)

 

 

 

 

※ 문자열 인덱싱과 슬라이싱

§ 문자열 인덱싱 - 한 문자만 뽑아내는 것

a = "Life is too short, You need Python"
print(a[3])  # e 출력
a = "Life is too short, You need Python"
print(a[-1])  # 가장 마지막 글자인 n 출력
a = "Life is too short, You need Python"
print(a[-6])  # P 출력

 

 

§ 문자열 인덱싱 - 한 단어를 뽑아내는 것

형식: a[시작번호:끝번호]  , 끝번호에 해당하는 것은 포함하지 않음 (0<= a < 3)

a = "Life is too short, You need Python"
print(a[0:4])   # Life 출력
a = "Life is too short, You need Python"
print(a[12:17])   # short 출력

 

a = "Life is too short, You need Python"

print(a[19:])   # 19부터 끝까지 뽑아내기에 You need Python 출력
print(a[:17])   # 처음부터 19까지 뽑아내기에 Life is too short 출력
print(a[:])     # 처음부터 끝까지, Life is too short, You need Python 모두 출력
print(a[19:-7]) # 19~끝-7까지 뽑아내기에 You need 출력

 

 

활용) Pithon을 Python으로 고치기

a = "Pithon"

print(a[:1]+"y"+a[2:])

 

 

 

 

 

 

 

 

※ 문자열관련 함수

§ 문자 개수세기  (count)

a = "My Hobby is play baseball"

print(a.count("b"))  # b의 개수인  4 출력

 

§ 문자 위치찾기  (find, index)

a = "My Hobby is play baseball"

print(a.find("b"))  # b가 처음 나오는 위치를 출력(0부터 시작)
print(a.index("b"))  # b가 처음 나오는 위치를 출력(0부터 시작)

 

§ 문자열 삽입 (join) 

a = "My Hobby is play baseball"

print(",".join(["My", "Hobby", "is", "play", "baseball"]))

#출력: My,Hobby,is,play,baseball

 

 

 

§ 문자열 바꾸기, 나누기 (replace, split)

a = "My Hobby is play baseball"

print(a.replace("baseball", "game"))
# 출력: My Hobby is play game

print(a.split("play"))
# 출력: ['My Hobby is ', ' baseball']

 

 

 

§ 대문자와 소문자 바꾸기  (upper, lower)

a = "My Hobby is play baseball"

print(a.upper())  # 출력: MY HOBBY IS PLAY BASEBALL
print(a.lower())  # 출력: my hobby is play baseball

 

※ Supervised learning 과 Unsupervised learning

 Supervised learning (지도학습) _ Classification, Regression, etc.

정답과 오답 등과 같은 답이 있는 train dataset (학습데이터)로 학습시키는 것

 

§ 지도학습 알고리즘

  • 선형 회귀(linear regression)
  • 로지스틱 회귀(logistic regression)
  • k-최근접 이웃(k-NN : k-Nearest Neighbors)
  • 결정 트리(decision trees)
  • 신경망(neural networks), Deep NN
  • 서포트 벡터 머신(SVC : support vector machines)
  • 랜덤 포레스트(randome forests)

 

Unsupervised learning (비지도학습) _ Clustering, PCA, etc.

정답과 오답 등과 같은 답이 없는 train dataset (학습데이터)로 학습시키는 것

 

 

 

 

 

 

 

 

※ (Linear) Regression

장점: 사용하기 쉽고 설명력이 있다. (popular and easy to use, explain with prediction)

단점: 정확도와 linear 관계성을 설명해야 한다. (redundant features, irrelevant features)

 

Examples

▶ 목적:  how to predict y-values (continuous values)

 

 

 

§ β값은 어떻게 찾을 것인가?

1차 직선그래프에 대해 빨간 점과 그래프 사이의 y축과 평행한 거리가 error값이 된다.

 

 

[ β_hat 구하는 방법 증명 ]

 

 

 

 

 

 

 

※ Model evaluation (모델 평가) [ feat.   y,  y_hat ]

Correlation value: 상관계수

 

 

 

 

 

 

 

※ Regularization (규제화)

 

 

 

 

 

 

 

 

※ Nonlinear Regression

- input과 output사이의 관계성이 선형(nonlinear)일 때

 

 

 

 

※ Logistic Regression

 

※ Logistic Function

 

 

 

 

 

※ Logistic Regression 의 해석 방법

 

 

 

 

 

※ (Linear)Regression  vs  Logistic Regression

§ Regression

장점: 사용하기 쉽고 설명력이 있다. (popular and easy to use, explain with prediction)

단점: 정확도와 linear 관계성을 설명해야 한다. (redundant features, irrelevant features)

 

 

§ Logistic Regression

장점: 해석력이 괜찮고 사용하기 편하다. (Interpretability, Easy to use)

단점: 예측력(prediction)이 다른 모델에 비해 뛰어난 편에 속하지는 않는다. (Performance)

 

 

 

 

'A.I > Machine Learning_이론' 카테고리의 다른 글

[Machine Learning].Bayesian Classifier_이론  (0) 2022.11.04


※ Bayesian Classifier (2-class-Classification)

Ex. 연어와 배스에 대해 구별하는 문제상황에 대해 생각해보자.

- 옵션1: 사람의 경험에 의해 어느 바다에서 어떤 물고기가 더 잘 잡히는지에 대한 연평균 데이터
- 옵션2: 자동적인 system [전처리-특징추출-classification]


class
X1 (Lightness) X2 (Width) Y (target)
Fish 1
Fish 2
.
.
.
Fish n
.
.



.
.
.



.
Sea Bass
Salmon



Salmon


위의 class에 대해 우리는 분류를 해야하며 이때, Bayesian Classifier를 사용할 수 있는데,
다른 model들과 Bayesian이 가장 확연히 다른 점이 하나 있다. 아래 수식을 살펴보자.
먼저 Bayesian의 공식은 조건부확률로 이루어져 있다.

Bayes' Formula


여기서 가장 중요한 것은 Prior이다.

다른 머신러닝 모델들과 확연히 다른 Bayesian 만이 갖는 특징으로 사용자 주관이 개입될 수 있다는 점이다.


예를 들어 어떤 바다에서 물고기를 잡았을 때, 70%정도가 salmon이라 판별된다면,
이런 자연적인 분포비율을 model에 집어넣을 수 있다는 뜻이다.
예를 들어, 모델이 fish5에 대해 salmon일 확률을 0.3이라 예측했다면, 70%의 주관의 개입으로 모델의 분류효과를 달리할 수 있다는 점이다.

Likelihood만으로 측정한 결과값이 왼쪽이라면, 이 값에&amp;nbsp; prior를 추가해 오른쪽과 같은 값을 만들 수 있으며 좀 더 세밀한 분류도 가능해진다.







※ Generative vs Discriminative // Parametric vs Non-parametric

§ Generative vs Discriminative

Generative
- modeling의 결과로부터 data를 만들 수 있다.
- Output: 확률 분포 (Probability distribution)

Discriminative
- data를 모아 판별함수를 찾을뿐, 생성하지는 못하는 함수 (Just looking for a discriminant function)

§ Parametric vs Non-parametric

Parametric
- 미리 지정된 모델의 파라미터를 최적화함 (optimize pre-defined parameters in a model)

Non-parametric
- 모델에 파라미터자체가 없음 (no parameters in a model)







※ Parameter Estimation_ Discriminant Function for Decision Boundary

§ Decision Boundary


단항함수와 다항함수 Gaussian (Univariate and multivariate Gaussian)
- 단항함수 Gaussian (Univariate Gaussian)

뮤와 시그마 만 알면 값을 구할 수 있음

- 다항함수 Gaussian (Multivariate Gaussian)

d/2, 시그마, 뮤만 알면 값을 구할 수 있음




※ Maximum Likelihood Estimation

빨간색 점이 data를 뜻함

위 그래프에서 data 밀집이 평균과 가까워질수록 값이 커진다.
최댓값은 미분했을 때, 0일 때! (접선의 기울기 = 0)

§ 뮤(평균) 추정값








※ Naive Bayesian classifier

위와 같이 고차원 공간의 세타값 추정 방법

이 방법은 너무 복잡하고 시간소비가 심하다.


§ Naive Bayesian classifier => 매우 강한 추정방식 (모든 특징 변수들이 독립적이어서)

장점: 모든 변수가 다 독립이며 매우 string한 assumption이 가능하다.
따라서 각 클래스 별로 변수끼리 따로따로 계산해서 추정한다.

아래를 보면 Bayesian과 Naive간의 차이점을 볼 수 있다.





다중변수 추정을 나이브하게 만들어 단변수 추정으로 만들 수 있다.
(Multivariate distribution estimation => Univariate distribution estimation)





+ Recent posts