AIFFEL(220218)_정보이론 톺아보기

NODE : 28. 정보이론 톺아보기


학습목표

  1. 머신러닝 이론의 이론적 토대를 이루는 가장 중요한 이론 중 하나인 정보이론(Information Theory)에 대해 알아본다.
  2. 머신러닝에서 많이 사용되는 Entropy, Cross Entropy, KL divergence 등의 개념과 이런 개념들이 머신러닝 이론과 연결되는 사례를 파악해 본다.

📖 Information Content

정보 이론(information theory)이란 추상적인 '정보'라는 개념을 정량화하고 정보의 저장과 통신을 연구하는 분야이다.

Information Content


눈에 보이지 않는 '정보'를 어떻게 정량적으로 표현할 수 있을까? 아래 그림처럼 두 개의 주머니에 공이 들어 있다고 생각해보자. 왼쪽 주머니에는 4가지 색깔의 공들이 들어있고, 오른쪽 주머니에 들어 있는 공은 모두 파란색이다.

왼쪽 주머니에서 공을 하나 꺼내서 색깔을 보고 다시 넣는 과정을 반복하면, 관찰된 공의 색깔은 4가지 중 무작위이다. 반면에 오른쪽 주머니에서 공을 꺼낸다면 파란색 공만 관찰될 것이다. 직관적으로 주머니에서 공을 꺼낼 때 우리가 얻을 수 있는 정보의 양은 왼쪽이 더 많다. 오른쪽 주머니에서는 공을 꺼내봤자 어차피 파란색이니 별다른 정보가 없는 것이다. 오늘 아침에 해가 동쪽에서 떴다는 이야기가 뉴스거리가 되지 못하는 것과 같은 이유이다.

상황을 약간 바꿔서, 파란색 공 999개와 빨간색 공 1개가 들어 있는 주머니가 있다고 하자. 어떤 사람이 공을 하나 꺼내고 다시 넣는 실험을 반복한다. 이 사람은 주머니에 어떤 색깔의 공이 몇 개씩 들어 있는지 모르기 때문에, 공을 하나씩 뽑을 때마다 이 사람이 추측하는 확률 분포가 업데이트된다. 파란색 공을 처음 몇 번 뽑았을 때, 파란색 공을 뽑는 사건은 정보량이 높다. 하지만 파란색 공만 수십, 수백 번 뽑고 나서는 파란색 공을 뽑는 사건은 확률이 1에 가깝기 때문에 큰 의미를 주지 못한다. 그러다가 만약에 하나 있는 빨간색 공을 뽑는다면, 이 사건은 정보량이 엄청나게 높을 것이다. 빨간색 공을 뽑기 전까지 관찰된 파란색 공의 수가 많을수록(즉 빨간색 공이 뽑힐 확률이 낮을수록) 빨간색 공을 뽑는 사건의 정보량은 높아진다.

Goodfellow, Bengio, Courville의 책 Deep Learning에는 정보를 정량적으로 표현하기 위해 필요한 세 가지 조건이 설명되어 있다.

  1. 일어날 가능성이 높은 사건은 정보량이 낮고, 반드시 일어나는 사건에는 정보가 없는 것이나 마찬가지이다.
  2. 일어날 가능성이 낮은 사건은 정보량이 높다.
  3. 두 개의 독립적인 사건이 있을 때, 전체 정보량은 각각의 정보량을 더한 것과 같다.

사건 xx가 일어날 확률을 P(X=x)P(X=x)

I(x)=logbP(x)I(x)=−log_bP(x)

이 식은 위의 세 가지 조건을 모두 만족하는 것을 확인할 수 있다. 로그의 밑 bb에는 주로 2,
ee, 10과 같은 값이 사용되는데, b=2b=2

import numpy as np
import math
import random

# 주머니 속에 들어있는 공의 개수입니다. 숫자를 바꾸면서 실험해보세요!
total = 1000

#---------------#

count = 1   # 실험이 끝날 때까지 꺼낸 공의 개수

# 1부터 total까지의 정수 중에서 하나를 뽑고 total과 같으면 실험 종료
# total=1000인 경우 1~999: blue / 1000: red
while True:
    sample = random.randrange(1,total+1)
    if sample == total:
        break
    count += 1

print('number of blue samples: '+str(count-1))
print('information content: '+str(-math.log(1/count)))
# 실험결과
number of blue samples: 1620
information content: 7.390798521735676

📖 Entropy

이전 스텝을 돌이켜보면, 사건 xx의 정보량 I(x)I(x)는 사건이 일어날 확률 P(x)P(x)에 의해 결정되었다.

I(x)=logP(x)I(x)=−logP(x)

정보량은 한 가지 사건에 대한 값이다. 예를 들면 주사위를 던졌을 때 1이 나오는 사건, 여러 색깔의 공이 들어 있는 주머니에서 빨간색 공을 꺼내는 사건 등이다. 그러면 여러 가지 경우의 수가 존재하는 실험의 정보량도 구할 수 있을까? 직관적으로 확률 변수가 가지는 모든 경우의 수에 대해 정보량을 구하고 평균을 내면 확률 변수의 평균적인 정보량을 구할 수 있을 것이다. 특정 확률분포를 따르는 사건들의 정보량 기댓값을 엔트로피(entropy)라고 한다.

For Discrete Random Variables


이산 확률 변수 XXx1,x2,,xnx_1, x_2, \dots, x_n

아래 그림은 동전을 던질 때 앞면이 나올 확률에 따른 엔트로피를 나타낸 그래프이다. 앞면이 나올 확률이 0.5일 때(앞면과 뒷면의 확률이 각각 0.5로 같은 균등 분포(uniform distribution)) 엔트로피 값이 최대가 된다. 앞면이 나올 확률이 90%인 동전을 던질 때보다 앞면과 뒷면의 확률이 같은 동전을 던질 때 결과를 예측하기가 더 어렵기 때문에 불확실성이 크다고 할 수 있다.

For Continuous Random Variables


XX가 이산 확률 변수일 때 엔트로피는 위와 같이 정보량에 확률을 각각 곱해서 모두 더한 값으로 정의된다. XX가 연속적인 값을 갖는 연속 확률 변수일 때는 유한합 대신 적분의 형태로 정의한다. 확률 변수 XX의 확률 밀도 함수가 p(x)p(x)일 때 엔트로피는 다음과 같다.

h(X)=p(x)logp(x)dxh ( X ) = − ∫ p ( x ) \log p ( x ) d x

연속 확률 변수의 엔트로피를 이산 확률 변수와 구분하여 미분 엔트로피(differential entropy)라고 부르기도 한다.

📖 Kullback Leibler Divergence

머신러닝의 목표는 새로운 입력 데이터가 들어와도 예측이 잘 되도록, 모델의 확률 분포를 데이터의 실제 확률 분포에 가깝게 만드는 것이다. 머신 러닝 모델은 크게 두 가지가 있다. 우선 결정 모델(discriminative model)은 데이터의 실제 분포를 모델링 하지 않고 결정 경계(decision boundary)만을 학습한다. 예를 들면 모델의 결괏값이 0보다 작을 경우 데이터를 1번 클래스로 분류하고, 0보다 클 경우 2번 클래스로 분류하는 식이다. 반면에 생성 모델(generative model)은 데이터와 모델로부터 도출할 수 있는 여러 확률 분포와 베이즈 이론을 이용해서 데이터의 실제 분포를 간접적으로 모델링 한다. 그렇기 때문에 생성 모델을 학습시킬 때는 두 확률 분포의 차이를 나타내는 지표가 필요한데, 대표적인 예가 쿨백-라이블러 발산(Kullback-Leibler divergence, KL divergence)이다.

데이터가 따르는 실제 확률 분포를 P(x)P(x), 모델이 나타내는 확률 분포를 Q(x)Q(x)라고 하자. 두 확률 분포의 KL divergence는 P(x)P(x)를 기준으로 계산된 Q(x)Q(x)의 평균 정보량과, P(x)P(x)를 기준으로 계산된 P(x)P(x)의 평균 정보량의 차이로 정의할 수 있다. 실제 확률 분포 P(x)P(x) 대신 근사적인 분포 Q(x)Q(x)를 사용했을 때 발생하는 엔트로피의 변화량을 나타내는 값이다.

연속 확률 변수의 경우에는 다음과 같다.

DKL(PQ)=P(x)log(P(x)Q(x))dxD_{KL}(P||Q)=\int P(x)\log\Big(\frac{P(x)}{Q(x)}\Big)dx

KL divergence는 두 확률 분포의 차이를 나타내는 값이기 때문에 거리 함수와 비슷한 성질을 가지고 있다. 다만 KL divergence의 식에는 기준이 되는 확률 분포가 존재하기 때문에 DKL(PQ)D_{KL}(P||Q)

KL divergence의 대표적인 특성은 아래와 같다.

  1. DKL(PQ)0D_{KL}(P||Q) \ge 0
  2. DKL(PQ)=0D_{KL}(P||Q)=0
  3. non-symmetric : DKL(PQ)DKL(QP)D_{KL}(P||Q) \neq D_{KL}(Q||P)

머신러닝 문제에서는 두 확률 분포의 차이를 줄여 DKL(PQ)D_{KL}(P||Q)

Cross Entropy


P(x)P(x)에 대한 Q(x)Q(x)의 교차 엔트로피 식을 다시 적으면 다음과 같다.

KL divergence의 계산식으로부터 엔트로피와 교차 엔트로피, KL divergence 사이의 관계식을 얻을 수 있다.

H(P,Q)=H(P)+DKL(PQ)H(P,Q)=H(P)+D_{KL}(P||Q)

이렇게 해서 정답셋의 확률분포 P와 우리 모델의 추론 결과의 확률분포 Q 의 차이 KL divergence를 최소화하는 것, 즉 우리 모델의 추론 결과가 정답셋과 최대한 유사하게 하는 것과 교차 엔트로피(Cross Entropy)를 최소화하는 것이 수학적으로 같다는 것을 확인하였다.

📖 Kullback Leibler Divergence

Cross Entropy Loss


머신러닝에서 모델이 나타내는 확률 분포와 데이터가 따르는 실제 확률 분포 사이의 차이를 나타내는 함수를 손실 함수(loss function)라고 한다. 모델의 확률 분포는 파라미터에 따라 달라지기 때문에 손실 함수 역시 파라미터에 의해 결정된다. likelihood 노드에서 잠깐 다루었던 최소제곱법의 함수도 손실 함수라고 할 수 있다. 데이터가 연속적인 값을 가지는 회귀(regression) 문제와는 다르게, 이산적인 값을 가지는 분류(classification) 문제에서는 모델의 출력 결과가 로지스틱 함수(logistic function)로 표현된다. 분류 클래스가 2개인 로지스틱 함수를 클래스가 nn개일 때로 확장한 것이 딥러닝에서도 자주 사용되는 소프트맥스 함수(softmax function)이다. 이 함수와 데이터의 확률 분포의 차이가 분류 문제의 손실 함수가 된다.

앞에서 KL divergence를 최소화하는 것이 cross entropy를 최소화하는 것과 같다는 이야기를 했다. cross entropy 또한 손실 함수의 한 종류이다. cross entropy의 식을 다시 살펴보자.

분류 문제에서 데이터의 라벨은 one-hot encoding을 통해 표현된다. 클래스의 종류가 NN가지이고 특정 데이터가 nn번째 클래스에 속할 때, nn번째 원소만 1이고 나머지는 0으로 채운 NN차원 벡터로 놓는 것이다. 입력 데이터의 특성(feature) 값이 모델을 통과하면 출력 레이어의 소프트맥스 함수에 의해서 각각의 클래스에 속할 확률이 계산된다. 이 확률 값들이 모델이 추정한 확률 분포 Q(x)Q(x)를 구성하는 값들이다. 3개의 클래스 c1,c2,c3cc_1,c_2,c_3c

softmax(input)=(0.20.70.1)\text{softmax(input)} = \begin{pmatrix} 0.2 \\ 0.7 \\ 0.1 \\ \end{pmatrix}

이 결과는 곧 다음 식을 나타낸다.

Q(X=c1)=0.2Q(X=c2)=0.7Q(X=c3)=0.1Q(X=c_1)=0.2\\ Q(X=c_2)=0.7\\ Q(X=c_3)=0.1

데이터가 실제로 2번 클래스에 속할 경우, 데이터의 실제 확률 분포는 one-hot encoding과 같은 [0,1,0]이다. 데이터가 2번 클래스에 포함된다는 사실이 이미 확실하게 알려졌기 때문에 확률 분포가 이와 같이 계산되는 것이다.

P(X=c1)=0P(X=c2)=1P(X=c3)=0P(X=c_1)=0\\ P(X=c_2)=1\\ P(X=c_3)=0

cross entropy를 사용하면 P(x)P(x)Q(x)Q(x)의 차이를 다음과 같이 계산할 수 있다.

H(P,Q)=P(x)logQ(x)=(0log0.2+1log0.7+0log0.1)=log0.70.357H(P,Q)=−∑P(x) \log Q(x)\\ =−(0⋅ \log 0.2+1⋅\log 0.7 + 0⋅\log 0.1)\\ =−\log 0.7≈0.357

분류 문제에서는 데이터의 확률 분포가 위와 같이 one-hot vector로 표현되기 때문에, P(x)P(x)Q(x)Q(x)의 차이를 cross entropy로 계산할 경우 계산이 간단해진다는 장점이 있다. 아래는 Q(x)Q(x) 분포가 랜덤하게 생성되었을 때 P(x)P(x)를 변형시키면서 cross entropy를 계산해 볼 수 있는 코드이다.

우선 아래 코드를 실행해 Q(x)Q(x) 생성한다. 실제 환경에서는 Q(x)Q(x)가 랜덤값으로 생성되는 것이 아니라 모델의 예측을 통해 얻게 된 값일 것이다. 그러니 softmax_output이라는 변수를 사용한다.

import numpy as np
import random

# generate random output
#-----------------#
# can be modified
class_num = 4
#-----------------#
q_vector = []
total = 1

for i in range(class_num-1):
    q = random.uniform(0,total)
    q_vector.append(round(q,3))
    total = total - q

q_vector.append(total)
softmax_output = np.array(q_vector)

print(softmax_output)
# 실행결과
[0.373      0.611      0.013      0.00349507]

이제 P(x)P(x)를 생성해 Cross Entropy를 계산해 보자. p_vector변수를 사용하는 P(x)P(x) 는 one-hot vector이므로 직접 class_index를 바꿔가며 확인해 볼 수 있다.

#-----------------#
# can be modified
class_index = 1
#-----------------#

p_vector = np.zeros(class_num)
p_vector[class_index-1] = 1

cross_entropy = -np.sum(np.multiply(p_vector, np.log(softmax_output)))

print('model prediction: '+str(softmax_output))
print('data label: '+str(p_vector))
print('cross entropy: '+str(round(cross_entropy,4)))
# 실행결과
model prediction: [0.373      0.611      0.013      0.00349507]
data label: [1. 0. 0. 0.]
cross entropy: 0.9862

Cross Entropy와 Likelihood의 관계


모델의 파라미터를 θ\theta로 놓으면, 모델이 표현하는 확률 분포는 Q(yX,θ)Q(\mathbf{y}|X,\theta)로, 데이터의 실제 분포는 P(yX)P(\mathbf{y}|X)로 나타낼 수 있다. 그런데 Q(yX,θ)Q(\mathbf{y}|X,\theta)는 데이터셋과 파라미터가 주어졌을 때 예측값의 분포를 나타내므로 모델의 likelihood와 같다.

H(P,Q)=P(yX)logQ(yX,θ)=P(yX)(logQ(yX,θ))H ( P , Q ) = − ∑ P ( y | X ) \log Q ( y | X , θ ) = ∑ P ( y | X ) ( − \log Q ( y | X , θ ) )

XXy\mathbf{y}는 데이터셋에 의해 결정되는 값이기 때문에 모델의 식이 바뀌어도 변하지 않는다. 우리가 바꿀 수 있는 부분은 logQ(yX,θ)-\log Q(\mathbf{y}|X,\theta)

📖 Decision Tree와 Entropy

딥러닝의 분류 모델 학습의 기초를 이루는 Cross Entropy 개념에 대해 지금까지 살펴보았다. 그 외에도 엔트로피 개념이 활발하게 쓰이는 분야를 하나만 더 짚어 보자면 의사결정나무(Decision Tree) 계열의 모델일 것이다.

의사결정나무를 설명하는 가장 간단한 데이터셋을 기준으로, 잠시 의사결정나무의 원리를 설명하겠다. 아래 그림은 날씨에 따른 운동경기 여부를 기록한 데이터이다. Day를 제외하고, 다음과 같은 4개의 데이터 컬럼이 있으며, Play(Yes/No) 컬럼이 라벨 역할을 하게 된다.

  • Outlook : 전반적 날씨 (Sunny(맑은), Overcast(구름 낀), Rainy(비 오는))
  • Temperature : 기온 정보(섭씨온도)
  • Humidity : 습도 정보 (수치형 변수(%), 범주형으로 변환된 경우 (high, normal))
  • Wind : 풍량 정보 (TRUE(바람 붊), FALSE(바람 안 붊))

    의사결정 트리는 가지고 있는 데이터에서 어떤 기준으로 전체 데이터를 나눴을 때 나누기 전보다 엔트로피가 감소하는지를 따져서, 엔트로피가 감소하면 그만큼 모델 내부에 정보 이득(Information Gain) 을 얻었다고 보는 관점이다. 엔트로피 증가가 정보 손실량이라고 정의하는 것의 반대 관점이다.
  • S : 전체 사건의 집합
  • F : 분류 기준으로 고려되는 속성(feature)의 집합
  • fFf \in F
  • SfS_f
  • X|X| : 집합 X의 크기(원소의 개수)
  • e(X)e(X) : X라는 사건 집합이 지닌 엔트로피

위 수식 IG(S,F)IG(S, F)FF라는 분류 기준을 선택했을 때의 엔트로피를 전체 사건의 엔트로피에 빼준 값, 즉 분류 기준 채택을 통해 얻은 정보 이득의 양을 말한다.

먼저 e(S)e(S)부터 구해 봅시다. 전체 14가지 경우 중 play하는 경우가 9번, 하지 않는 경우가 5번이다. 그렇다면 e(S)e(S)는 다음과 같다.

그럼 FF가 Outlook일 때, 즉 ff가 Sunny, Overcast, Rainy 중 하나일 때의 엔트로피를 각각 구해 보자.

그러므로 이때의 정보 이득은 다음과 같다.

이런 방식으로 가능한 모든 분류 기준 FF에 대해 정보 이득을 계산해서, 가장 정보 이득이 큰 순서대로 전체 사건을 2등분 한다. 그 후 다시 다른 분류 기준으로 위에서 했던 것과 동일하게, 이번에는 첫 번째로 사용했던 기준으로 나뉜 절반의 사건 집합 안에서의 정보 이득을 계산하는 방식으로 세부 분류 기준을 계속 찾아나간다. 그렇게 사건의 분류 기준을 세워나가다 보면 전체 사건 분류 기준이 트리 구조가 되기 때문에 이를 의사결정나무(Decision Tree) 라 부르게 된다.

그럼 엔트로피만 낮은 쪽으로 간다면 무조건 정교한 분류가 가능할까? 한번 의사결정나무 모델을 학습시켜 보고, 이를 시각화하는 과정을 통해 살펴보자.

위에서 예로 든 데이터셋은 실험하기에는 너무 작은 데이터셋이므로 다른 데이터셋을 준비해 보자. 캐글에서 제공하는 Pima Indians Diabetes Database을 사용한다.

import pandas as pd
import numpy as np
from sklearn.tree import DecisionTreeClassifier 
from sklearn.model_selection import train_test_split 
from sklearn import metrics
import os
csv_path = os.getenv('HOME')+'/aiffel/information_theory/diabetes.csv'

col_names = ['pregnant', 'glucose', 'bp', 'skin', 'insulin', 'bmi', 'pedigree', 'age', 'label']
# load dataset
df = pd.read_csv(csv_path, header=0, names=col_names)
df.head()

# 데이터셋 준비
feature_cols = ['pregnant', 'insulin', 'bmi', 'age', 'glucose', 'bp', 'pedigree']
X = df[feature_cols] # Features
y = df.label # Target variable

# Split dataset into training set and test set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1)

print('슝=3')
# Decision Tree  모델 학습
# Create Decision Tree classifer object
clf = DecisionTreeClassifier()

# Train Decision Tree Classifer
clf = clf.fit(X_train,y_train)

#Predict the response for test dataset
y_pred = clf.predict(X_test)

print("Accuracy:",metrics.accuracy_score(y_test, y_pred))
# 실행결과
Accuracy: 0.696969696969697

Decision Tree를 아무 제약조건 없이 학습시켜 나온 결과 정확도는 66% 정도 된다.
Decsion Tree의 장점은 어떻게 모델이 이런 결과를 내었는지 분류 기준을 따져보고 시각화를 통한 원인 추적이 가능하다는 점이다. 다음과 같이 방금 학습시킨 Decision Tree 모델을 시각화해 보자.

생성된 이미지 파일이 꽤 크기 때문에 저장된 이미지를 직접 열어 확인해도 좋다. diabetes1.png로 저장된다.

from sklearn.tree import export_graphviz
from six import StringIO  
from IPython.display import Image  
import pydotplus

dot_data = StringIO()
export_graphviz(clf, 
                out_file=dot_data,  
                filled=True, 
                rounded=True,
                special_characters=True, 
                feature_names=feature_cols, 
                class_names=['0','1'])
graph = pydotplus.graph_from_dot_data(dot_data.getvalue())  
graph.write_png('diabetes1.png')
Image(graph.create_png(), retina=True)


여기서 사용한 정보의 총량은 얼마나 될요? 사용되지 않은 정보가 적을 수록 많은 정보를 사용한 것일 테니, 정보 이득이 되지 않은 Impurity를 측정해 보자.

# 정보 이득이 되지 않고 남은 Impurity  총량 측정
ccp_path1 = clf.cost_complexity_pruning_path(X_train,y_train)
ccp_path2 = clf.cost_complexity_pruning_path(X_test,y_test)
print(np.mean(ccp_path1.impurities))
print(np.mean(ccp_path2.impurities))
# 실행결과
0.15339926842881257
0.14633934707314158

위 두 가지 사실을 볼 때 우리가 학습시킨 Decision Tree 는 정보 이득을 최대화할 수 있는 지점까지 극한적으로 많은 분류 기준을 적용한 경우임을 알 수 있었다. 그런데 이것이 과연 타당할까?

비교 실험을 해 보자. 우리는 Decision Tree를 3depth 까지만 발전시켜 볼 것이다.

clf = DecisionTreeClassifier(criterion="entropy", max_depth=3)

# Train Decision Tree Classifer
clf = clf.fit(X_train, y_train)

#Predict the response for test dataset
y_pred = clf.predict(X_test)

# Model Accuracy, how often is the classifier correct?
print("Accuracy:",metrics.accuracy_score(y_test, y_pred))
# 실행결과
Accuracy: 0.7705627705627706

오히려 훨씬 Accuracy가 올라갔다. 이때의 트리구조 및 정보 이득이 되지 않은 남은 엔트로피(Impurity) 총량은 어떨까?

dot_data = StringIO()
export_graphviz(clf, 
                out_file=dot_data,  
                filled=True, 
                rounded=True,
                special_characters=True,
                feature_names = feature_cols,
                class_names=['0','1'])
graph = pydotplus.graph_from_dot_data(dot_data.getvalue())  
graph.write_png('diabetes2.png')
Image(graph.create_png(), retina=True)

# 정보이득이 되지 않고 남은 Impurity  총량 측정
ccp_path1 = clf.cost_complexity_pruning_path(X_train,y_train)
ccp_path2 = clf.cost_complexity_pruning_path(X_test,y_test)
print(np.mean(ccp_path1.impurities))
print(np.mean(ccp_path2.impurities))
# 실행결과
0.7474881472739515
0.6878691771636323

분명 엔트로피 기준으로는 더욱 정보 이득을 얻을 수 있음에도 불구하고 분류 기준을 더 세우지 않는 것이 전체 모델의 정확도 향상에 낫다는 것을 알 수 있었다. 왜냐하면 Decision Tree 의 분류 기준은 임의로 정한 것이기 때문이다. 무한정 기준을 쪼개서 엔트로피를 떨어뜨릴 수 있지만, 그것은 Overfitting의 결과를 낳게 된다. 시각화된 결과를 통해 이를 확인해 보면 좋다.

하지만 다양한 분류 기준을 가진 Decision Tree 여러 개를 앙상블한 Random Forest 모델은 이러한 문제점을 극복하고 훌륭한 성능을 보일 수 있음도 우리는 알고 있다.

그렇다면 Decision Tree를 몇 depth까지 학습시키는 것이 가장 좋을까? 직접 실험해보자.

좋은 웹페이지 즐겨찾기