코딩테스트 연습 - [3차] n진수 게임 | 프로그래머스 (programmers.co.kr)

문제는 위 링크에서 확인하는것이 더욱 나을것같다.

 

일단 문제를 푸는데있어서 3가지 주요 부위로 나눴다.

첫번째는 divmod를 활용하여, N진수  String을 만들어주는 부분

두번째는 튜브가 말해야하는 길이보다 좀 더 길게, 그 순서까지 텍스트를 뽑으며 추가해주는 부분

세번째는 , 순서에 맞게 튜브가 말할 answer를 만드는 부분

# n진수 게임 (카카오 2018블라인드)
def solution(n,t,m,p):
    def getdiv(n, div):
        words = "0123456789ABCDEF"
        ans=""
        tmp=[]
        while n>=div:
            tmp.append(divmod(n,div)[1])
            n=divmod(n,div)[0]
        tmp.append(divmod(n,div)[1])
        while tmp:
            ans+=words[tmp.pop()]
        return ans

    start=0
    tmp = ''
    while len(tmp)< (t)*(m+1) :
        tmp +=  getdiv(start,n)
        start+=1
    
    answer = ""
    idx = p-1
    while len(answer) < t :
        answer+=tmp[idx]
        idx += m
    return answer

# n,t,m,p = 2,4,2,1
# n,t,m,p = 16,16,2,1
n,t,m,p = 16,16,2,2
solution(n,t,m,p) # n진법, 미리구할 수 t, 게임인원 m , 튜브의 순서 p

코딩테스트 연습 - 다단계 칫솔 판매 | 프로그래머스 (programmers.co.kr)

문제에 대한 설명은 링크를 직접 들어가서 확인하는것이 가장 좋을것이라고 생각된다.

일단, enroll과 referral를 사용해서, 각자의 부모 ( 추천자) 가 누구인지 확인할 수 있는 형태의 dictionary를 만들고, 
seller와 amount를 처리한다.

여기서 주의해야할점이있는데, 15원과 같이 남아있을 때, 돈의 처리이다.

15//10을 하면 1원이므로, 부모에게 1원만큼을 넘기고, 자신이 14원을 갖는 형태로 진행해야한다.
이 부분에 대한 아이디어를 생각하지 못하고 문제를 풀다가 , 계속 막혀서 한참 고생했다.

일단 DFS로 문제를 풀었다.

from collections import defaultdict
def mktree(enroll, referral):
    dic=defaultdict()
    for ee, ref in zip(enroll,referral):
        if ref=="-":
            dic[ee] = ['',0]
        else:
            dic[ee]=[ref,0]
    return dic
def solution(enroll, referral, seller, amount):
    dic=mktree(enroll,referral)
    # print(dic)
    for sell,amou in zip(seller,amount):
        coin = amou*100
        forparent=coin//10
        
        if dic[sell][0]=='':# 부모가센터
            dic[sell][1] += coin-forparent
            # print('부모가센터',dic[sell][1])
        
        else: # 다른추천자가있어
            que=[]
            que.append(sell)
            while que:
                now = que.pop()
                # print(now, coin, forparent)
                if now in dic:
                    if coin >= 1:
                        # print(now,':',dic[now][1],'+',round(coin-forparent))
                        dic[now][1] += round(coin-forparent)
                        que.append(dic[now][0])
                        coin = forparent
                        forparent = coin//10
                    else:
                        dic[now][1] += coin
    answer = [int(i[1][1]) for i in dic.items()]
    return answer

전형적인 BFS풀이 

위와같은 맵에서 0,0 에서 시작하여 오른쪽 맨 밑의 출구로 나가는 미로를 탈출하는데 최소한으로 움직여야하는 거리를 측정하기

한칸 움직일때마다 +1 이며, 0은 막힌공간임을 의미한다. 

 

 

 

# 미로탈출

from collections import deque
maps=[
    [1,0,1,0,1,0],
    [1,1,1,1,1,1],
    [0,0,0,0,0,1],
    [1,1,1,1,1,1],
    [1,1,1,1,1,1]
]
n,m = len(maps),len(maps[0])
dx=[-1,1,0,0]
dy=[0,0,-1,1]

def bfs(x,y):
    que = deque()
    que.append((x,y))
    while que:
        x,y = que.popleft()
        for i in range(4):
            nx=x+dx[i]
            ny=y+dy[i]
            if nx==n-1 and ny==m-1 : 
                print('skip')
                return maps[x][y]+1
            if nx < 0 or ny < 0 or nx >= n or ny >= m : continue
            if maps[nx][ny]==0:
                continue
            if maps[nx][ny]==1:
                maps[nx][ny] = maps[x][y]+1
                que.append((nx,ny))
    return maps[n-1][m-1]
print(bfs(0,0))
maps

N * M 크기의 얼음틀이 있다. 
구멍이 뚫려있는 부분은 0, 칸막이가 존재하는 부분은 1로 표시. 

구멍이 뚫려있는 부분끼리 상,하,좌,우 로 붙어있는 경우 서로 연결되어있는것으로 간주

얼음틀의 모양이 주어졌을 때 생성되는 총 아이스크림의 개수를 구하는 프로그램 작성하기 

ex )

위와 같은 얼음틀에서는 아이스크림 3개가 생성된다고 보면 된다. 

풀이 : 

DFS를 이용하면서, 방문하는 순간 1로 바꾸는 것으로 한다. 

# 음료수 얼려먹기
# N X M 크기의 얼음틀, 구명이 뚫려있는부분은 0, 칸막이가 존재하는 부분은 1로 표시
# 한번에 만들 수 있는 아이스크림의 개수를 출력
ices=[
    [0,0,1,1,0],
    [0,0,0,1,1],
    [1,1,1,1,1],
    [0,0,0,0,0]
]

n=len(ices)
m=len(ices[0])

def dfs(x,y):
    if x<=-1 or x>=n or y<=-1 or y>= m:
        return False
    if ices[x][y]==0:
        ices[x][y]=1
        dfs(x-1,y)
        dfs(x,y-1)
        dfs(x+1,y)
        dfs(x,y+1)
        return True
    return False
ans=0
for i in range(n):
    for j in range(m):
        if dfs(i,j)==True: ans+=1
ans

'CODING TEST' 카테고리의 다른 글

이코테 _ 떡볶이떡  (0) 2021.06.18
파이썬 Python KAKAO_2019 인턴- 불량사용자  (0) 2021.06.18
파이썬 Python KAKAO_2018 캐시  (0) 2021.06.16
파이썬 Python KAKAO_2018 파일명 정렬  (0) 2021.06.15
Greedy  (0) 2021.05.31

서포트벡터머신

결정경계 (Decision Boundary), 즉 분류를 위한 기준 선을 정의하는 모델

그리하여, 분류되지 않은 새로운 점이 나타나면, 경계의 어느 쪽에 속하는지 확인해서 분류 과제를 수행할 수 있게됨.

차원이 늘어남에따라, 선이 아닌 평면의 형태로 결정경계가 바뀌는데, 더욱 고차원으로 가게되면 이를 초평면 (Hyperplane)이라 함

어떤 경계가 좋을까

위와 같은 경계들을 보면, A~E 보다 F가 더욱 안정적으로 보인다. 결정경계가 데이터 군으로부터 최대한 멀리 떨어지는게 좋다는 것이다.
실제로 Support Vectors는 결정경계와 가까이 있는 데이터 포인트들을 의미한다.

Margin 마진

마진은 결정경계와 서포트벡터 사이의 거리를 의미한다.

초록실선이 결정경계이고, 그 실선으로부터 검은 테두리가 있는 빨간 점 1개, 파란 점 2개가 영역을 두고 점선을 그려놓았는데, 점선으로부터 결정경계 까지의 거리가 바로 마진(margin)이다.

최적의 결정경계는 마진을 최대화 한다.

위 그림엔 2개의 속성을 가진 데이터들을 기반으로 결정경계를 그었는데, 이때 총 3개의 데이터포인트가 필요했다. 즉 n개의 속성을 가진 데이터에는 최소 n+1개의 서포트 벡터가 존재한다는 것을 알 수 있다.

SVM에서는 결정경계를 정의하는것이 결국 서포트벡터이기에, 데이터포인트 중 서포트벡터만 잘 골라낸다면, 나머지 쓸데없는 수많은 데이터포인트들을 무시할 수 있기에 매우 빠르다.

이상치를 얼마나 허용할것인가

선을 튀어나가버린 데이터가 발생하기마련이다.

여기서 하드마진과 소프트마진을 이야기한다.

하드마진

아웃라이어를 허용하지않고 까다로운 기준으로 세운것을 말한다. 그렇기에 서포트벡터와 결정경계 사이의 거리가 매우 좁다. (Margin이 작아진다).

이렇게 될 경우 오버피팅문제가 발생할 수 있다.

소프트마진

아웃라이어들이 마진안에 어느정도 포함되도록 너그럽게 기준을 잡은것이다. 이렇게 잡으니, 서포트벡터와 결정경계 사이의 거리가 멀어진다 (margin이커진다)

즉 대충대충 학습하는 꼴이라 언더피팅문제가 발생할 수 있다.

파라미터 C

from sklearn.svm import SVC
classifier = SVC(C=0.01)

이런식으로 C를 설정할 수 있는데, SVM모델이 오류를 어느정도 허용할 것인지 파라미터를 통해 지정할 수 있다.

C값이 클 수록 하드마진 (오류허용X) , 작을수록 소프트마진 (허용)이다.

Kernel 커널

poly

선으로 그을 수 없는 경우라면?

SVM을 사용할 떄 kernel을 지정하여 해결할 수 있다.

from sklearn.svm import SVC
SVC(kernel = 'poly') 

와 같이 사용함으로써 사용할 수 있다. 그치만, 다른 커널을 사용할 떄 주의가 필요하다.

단순히 outlier때문에 선형분리가 불가능하다고 판단해서는 안된다.

RBF (방사기저함수 = 가우시안커널)

RBF커널은 2차원의 점을 무한한 차원의 점으로 변환한다.. 상당히 선형대수학적으로 어려운 내용이다..

Kernel 커널

poly

선으로 그을 수 없는 경우라면?

SVM을 사용할 떄 kernel을 지정하여 해결할 수 있다.

from sklearn.svm import SVC
SVC(kernel = 'poly') 

와 같이 사용함으로써 사용할 수 있다. 그치만, 다른 커널을 사용할 떄 주의가 필요하다.

단순히 outlier때문에 선형분리가 불가능하다고 판단해서는 안된다.

RBF (방사기저함수 = 가우시안커널)

RBF커널은 2차원의 점을 무한한 차원의 점으로 변환한다.. 상당히 선형대수학적으로 어려운 내용이다..

파라미터 gamma

결정경계를 얼마나 유연하게 그을 것인가.

gamma값을 높이면 학습 데이터에 많이 의존해서 결정경계를 구불구불 긋게된다. → 오버피팅

낮추면, 결정경계를 직선에 가깝게 긋게된다 → 언더피팅

 

요약

어쩜 이렇게 잘 정리하셨을까.... 대단하시다..

  • SVM은 분류에 사용되는 지도학습 머신러닝 모델이다.
  • SVM은 **서포트 벡터(support vectors)**를 사용해서 결정 경계(Decision Boundary)를 정의하고, 분류되지 않은 점을 해당 결정 경계와 비교해서 분류한다.
  • **서포트 벡터(support vectors)**는 결정 경계에 가장 가까운 각 클래스의 점들이다.
  • 서포트 벡터와 결정 경계 사이의 거리를 **마진(margin)**이라고 한다.
  • SVM은 허용 가능한 오류 범위 내에서 가능한 최대 마진을 만들려고 한다.
  • **파라미터 C**는 허용되는 오류 양을 조절한다. C 값이 클수록 오류를 덜 허용하며 이를 **하드 마진(hard margin)**이라 부른다. 반대로 C 값이 작을수록 오류를 더 많이 허용해서 **소프트 마진(soft margin)**을 만든다.
  • SVM에서는 선형으로 분리할 수 없는 점들을 분류하기 위해 **커널(kernel)**을 사용한다.
  • **커널(kernel)**은 원래 가지고 있는 데이터를 더 높은 차원의 데이터로 변환한다. 2차원의 점으로 나타낼 수 있는 데이터를 다항식(polynomial) 커널은 3차원으로, RBF 커널은 점을 무한한 차원으로 변환한다.
  • RBF 커널에는 **파라미터 감마(gamma)**가 있다. 감마가 너무 크면 학습 데이터에 너무 의존해서 오버피팅이 발생할 수 있다.

 

참조의 첫번째 아무튼워라밸님의 블로그에 정말 잘 소개되어있는것을 보고 기억하고자 많은 부분을 가져왔다. 
이분의 블로그에 SVM말고도 다른 많은 좋은 자료들이 있으니, 들어가서 찾아보면 공부할거리들을 많이 얻을 수 있을 것이다. 

참조 : http://hleecaster.com/ml-svm-concept/ , https://scikit-learn.org/stable/modules/svm.html

'Machine Learning' 카테고리의 다른 글

크로스엔트로피 Cross Entropy, KL Divergence  (0) 2021.06.07

참조 :
https://www.youtube.com/watch?v=7GBXCD-B6fo
https://www.youtube.com/watch?v=Jt5BS71uVfI
https://theeluwin.postype.com/post/6080524
https://velog.io/@vanang7/%EC%97%94%ED%8A%B8%EB%A1%9C%ED%94%BC%EC%99%80-%ED%81%AC%EB%A1%9C%EC%8A%A4-%EC%97%94%ED%8A%B8%EB%A1%9C%ED%94%BC

머신러닝/딥러닝에서 분류문제를 풀 때 크로스엔트로피를 써서 손실을 구한다.

틀릴 수 있는 정보를 갖고 구한 엔트로피. 즉 불확실성 정도의 양이라고 할 수 있는데, 이 틀릴 수 있는 정보는 바로 머신러닝모델의 아웃풋이 있다. 모델의 아웃풋은 예측값이기에 틀릴 수 있다.

Cross Entropy is optimal entropy When ifro is from estimated probability

간단한 딥러닝 분류문제이다. 최종단에 softmax레이어가있고, 이것을 활용해 예측값을 구할 수 있다.
이것을 정답과 비교할 땐 정답값을 원-핫 인코딩으로 비교하는 형태이다. 이 과정에서 softmax값과 one-hot인코딩된 실제 값을 사용한다.

소프트맥스 값을 Q라고 하고, 실제 라벨을 P라고 했을 때
Q : Estimated Probability , P : True Probability

H(P,Q)가 크로스 엔트로피 공식이고, H(X)가 엔트로피 공식이다.
각각 클래스마다 어떤 확률로 존재하는지를 나타낸다 -> 여기서 $p_i$는 (어떠한 정보의) 확률이다.

$ log_2{1\over{q_i}}$ 는 정보의 양을 나타낸다

왜 크로스엔트로피에서 정보의 양에 $log_2$ $1\over{q_i}$ 을 사용하는걸까?

첫번쨰로 우리는 딥러닝 모델을 학습시킬때 이 예측값이 정답과 얼마나 근사한지 알고싶다.
그를 위해 실제 확률값을 사용해야한다. 단 정보의 양은 모델을 통해 온 정보의 양(예측값의 확률)을 사용해야해서 위의 log 안에 q 가 들어간것이다.
실제 정답의 확률을 사용함으로써 이 엔트로피값이 과연 실제 정답값과 얼마나 근사한지를 알 수 있게되는것이다.

틀릴 수 있는 정보를 갖고 구한 엔트로피값이다 라고 한마디로 정리할 수 있다.

KL Divergence

단순히 어떠한 모델을 설명할때, 차이가 크다-작다 보다 정확한 수치로 얼마만큼 차이난다! 라고 나타냄으로써 어떤 모델이 더 정답과 비슷하게 유추하는지 나타낼 수 있도록 하기위하여 KL Divergence를 사용한다.
이는 수치값으로 분포도를 나타낸다.

P : 정답,   Qa : 모델a,   Qb : 모델b

$Q_A$가 실제 정답과 상당히 비슷한 분포를 갖고있다고 할 수 있다.

KL Divergence는 실제 정답값의 분포도에서 상대적으로 얼마만큼 다른지에 대해 수치적으로 나타내는 값이다. 

상대엔트로피값과 같다. 

1. 항상 0과 같거나, 0보다 크다. 
2. 비대칭적이다.

 

 

그렇다면 왜? 크로스엔트로피를 cost func으로 쓰고, minimize함으로써 최적화를 하는데, 왜 KL Divergence를 쓰지 않는가?

실제로, 크로스엔트로피를 쓰거나, KL Divergence를 쓰거나 같은 현상을 일으킨다. 

결국 KL-Divergence 를 사용해도, Entropy(P)가 상수이므로 뒷부분이 무시되고, 크로스엔트로피를 쓰는것과 같은 효과를 발휘하는것. 

 

 

 

'Machine Learning' 카테고리의 다른 글

SVM 서포트벡터머신 (Support Vector Machine)  (0) 2021.06.10

+ Recent posts