데이터 분석 Data Analytics/프로그래머스 데이터분석 데브코스 2기

[TIL] 데이터분석 데브코스 62일차 (1) - 임베딩(Embedding)/단어 임베딩/문장 임베딩/원핫인코딩(One-Hot Encoding)

상급닌자연습생 2024. 5. 16. 22:11

언어 (Language)

: 특정 개념을 표현하기 위한 약속의 집합

 

 

컴퓨터가 언어를 이해하는 방식

  1. 사람이 특정 단어를 컴퓨터에 입력하고 싶어함
  2. 컴퓨터는 특정 단어를 숫자(벡터)의 형태로 받아들임 → 단어를 숫자의 형태로 변환
  3. 벡터 값을 바탕으로  컴퓨터는 특정 단어를 인식함

 

 

 

 

 

 

임베딩 (Embedding)

: 텍스트 데이터를 벡터로 변환하는 기술

 

 

임베딩 프로세스

  1. 데이터 준비 : 원문 데이터 or 다른 소스로부터 데이터 수집
  2. 전처리 : 불용어, 오타 등의 데이터 제거
  3. 임베딩 : 목적에 맞는 알고리즘 적용
  4. 시각화 : 필요시 임베딩 결과를 그려보고 이를 확인

 

임베딩의 종류

  • 단어 임베딩 : 단어 → 벡터
  • 문장 임베딩 : 문장 → 벡터

 

 

벡터 공간

: 벡터가 존재하는 공간

  • 임베딩의 결과 = 벡터 → 임베딩의 결과를 벡터 공간에 표현 가능
  • 예시) 단어들을 2차원 벡터로 표현 → 단어들을 평면 위에 점의 형태로 표시 가능
    • 좋은 임베딩이 이루어지면 비슷한 의미의 단어는 비슷한 공간에 존재
  • 일반적으로 단어는 고차원으로 표현됨 ← 다양한 종류의 단어를 포괄 + 단어의 의미를 담은 벡터 생성 가능

 

 

 

 

임베딩 발전 과정

1. 원핫 인코딩 (One-hot Encoding)

: 특정 단어를 표현하는 위치만 1로, 나머지의 위치는 0으로 구성하는 임베딩 방법

  • 단어의 수 만큼의 크기를 갖는 벡터가 생성
  • 각 단어의 위치(=1이 표현되는 위치)는 설정하기에 따라 다름
  • 단어를 직관적으로 벡터 변환 가능
  • 예시) 전체 단어가 ʻdog’, ʻcat’, ʻapple’ 이 있다고 할 때
    • dog : [1, 0, 0]
    • cat : [0, 1, 0]
    • apple : [0, 0, 1]

 

인코딩 vs. 임베딩

인코딩(Encoding) 임베딩(Embedding)
데이터를 새로운 형태로 변환하는 과정
- 본질적으로 의미가 변하지 않음(정보 손실 X)
- 압축과 비슷한 과정
- 저장, 데이터 전송에 용이
- 데이터의 '형식'을 변환
- ML 모델이 처리하기 쉬운 형태로 변환
- 데이터의 의미적, 문맥적 특성을 모델이 이해할 수 있는 형태로 변환

 

 

 

 

한계점

1. 차원의 저주

  • 하나의 단어를 표현하는 벡터의 크기는 전체 단어 수와 같음
  • 즉, 매우 큰 차원을 갖을 수 있음
  • 차원이 크면 효율성과 계산 복잡도가 증가함

 

2. 의미 부재

  • 의미적으로 비슷한 단어끼리 비슷한 공간에 존재하지 않음
  • 축구 ↔ 농구의 관계와 축구 ↔ 비행기의 관계의 차이가 없음

 

3. 정보의 희소성

  • 특정 단어의 위치만 1이므로
  • 중요한 정보가 매우 매우 희소함
  • 대부분 0이 많음

 

 

 

 

 

 

2. 분산 표현 (Distribution Representation)

: 정수가 아닌 실수(연속적인 값)로 이루어진 벡터로 임베딩하는 방법

  • 연속적인 실수의 값으로 단어를 변경하면서 데이터의 의미를 여러 특성(feature)에 걸쳐 분산시켜 표현
  • 다양한 의미와 문맥적 특성을 풍부하게 포착 가능
  • 분산 표현으로 임베딩이 잘 될 경우 :
    • 비슷한 의미를 갖는 단어들은 비슷한 분포를 갖게 됨
      • 농구는 의미적으로 축구와 비슷
      • 비행기는 농구와 축구와는 의미적으로 비슷하지 않음
      • 따라서 벡터 공간에 멀리 위치
    •  임베딩 벡터도 수의 집합이기 때문에 의미 차원에서 연산 가능
      • 왕 ‒ 남자 + 여자 = 여왕
      • 서울 ‒ 대한민국 + 일본 = 도쿄

 

 

 

 

 

 

 

 

 

단어 임베딩 (Word Embedding)

: 단어숫자의 형태로 변환하는 과정

  • 단어의 의미, 문맥적 유사성, 동의어 등과 같이 단어 수준에서 의미를 활용하는 경우에 사용
  • 전체적인 문장의 의미를 한번에 포착하기는 어려움

 

단어에 원핫 인코딩 적용

  1. 문장을 단어의 형태로 분해해야 함 (Tokenize)
    ► "사과는 맛있다. 바나나는 맛있다" → "사과는" "맛있다." "바나나는" "맛있다"
  2. 고유한 단어 집합 생성
     
    ► ʻ사과는’, ʻ바나나는’, ʻ맛있다’
  3. 고유한 단어에 인덱스 부여

    ► 사과는 = 0, 바나나는 = 1, 맛있다 = 2

  4. 벡터 생성 : 각 단어의 인덱스에 1 부여, 나머지 자리에 0 채우기

    ► 사과는 = [1, 0, 0] / 바나나는 = [0, 1, 0] / 맛있다 = [0, 0, 1]

 

 

But, 원핫 인코딩은 한계점이 존재

 

 

분포 가설 (Distribution Hypothesis)

: 단어의 의미는 그 단어가 나타나는 문맥에 의해서 결정된다.

 

► 특정 단어의 의미를 숫자 벡터로 표현하기 위해 문맥과 주변 단어를 이용해서 학습 진행

 

 

 

 

 

임베딩 알고리즘 (1) - Word2Vec

: 2013년 Google에 의해 개발된 임베딩 알고리즘

 

프로세스

  1. 문장 위를 움직이는 슬라이딩 윈도우 만듦 (7:00~)
  2. 해당 윈도우는 이동하면서 동일한 개수의 단어를 포함
  3. 포함된 단어들 사이의 연산을 진행해 각 단어들을 임베딩
    임베딩 방법 :
    • CBOW : 이웃한 단어들로 가운데 단어가 무엇인지 예측하는 과정에서 임베딩을 진행
    • Skip-gram : 가운데 단어로 이웃한 단어들을 예측하는 과정으로 임베딩 진행

     

📌 윈도우 (window)
: 기준으로 삼은 scope

 

 

 

 

 

 

임베딩 알고리즘 (2) -GloVe (Global Vectors for Word Representation)

: 공동으로 자주 출현하는 단어들을 벡터 공간 내 비슷한 위치에 존재하도록 임베딩하는 알고리즘

 

프로세스

  1. 전체 글에 단어 간 공동 출현 통계를 이용해서 각 단어의 의미를 벡터로 표현
  2. 각 단어 쌍이 얼마나 자주 나타나는 지를 '공동출현행렬'로 기록

 

 

 

 

 

임베딩 알고리즘 (3) - BERT (딥러닝 기반)

  • 2018년 구글에서 개발된 알고리즘
  • 단어 별 중요도 기반의 모듈을 활용해 문장 내적 & 외적 관계를 바탕으로 임베딩을 진행
  • 과정에서 단어 임베딩 이외에 문장 임베딩도 생성

 

 

 

임베딩 알고리즘 (4) - CLIP (딥러닝 기반)

  • 2021년 OpenAI에서 개발된 알고리즘
  • 이미지를 설명하는 글에서 이미지와 텍스트의 공동 의미를 임베딩

 

 

 

 

 

 

 

 

 


OneHotEncoding 실습

📌 OneHotEncoder 클래스

  • `sklearn`의 클래스
  • 전체 문장을 입력해야 각 단어의 벡터 생성 가능
  • `get_feature_names_out()` 메서드 : 특정 벡터가 어떤 단어를 표현하는지 확인 가능

 

 

1단계. 필요한 패키지 불러오기

# 필요한 패키지 불러오기
from sklearn.preprocessing import OneHotEncoder
import numpy as np

# 사용할 문장
sentence = "사과는 맛있다 바나나는 맛있다"

 

 

2단계. 문장을 단어로 분리

# 문장을 단어로 분리
# 띄어쓰기 단위를 사용
words = sentence.split()
print(words)

 

 

3단계. 단어 배열을 Numpy 배열로 변환

원핫 인코더에 넣을 수 있게 넘파이 형식으로 바꿔줘야 한다.

# 단어 배열을 NumPy 배열로 변환
words_array = np.array(words).reshape(-1, 1)
print(words_array)

 

 

4단계. 원핫 인코딩 적용

# OneHotEncoder 객체 생성
encoder = OneHotEncoder(sparse_output=False) # sparse_output=False : 수업에서 다룬 0과 1로 이루어진 행렬의 형태로 변환

# 원핫 인코딩 적용
one_hot_encoded = encoder.fit_transform(words_array)
print(one_hot_encoded)

encoder.get_feature_names_out() # 각 열이 어떤 단어를 나타내는지를 표시

 

 

위의 과정을 함수로 정의하면 호출만으로도 단어 임베딩이 가능하다.

# 원핫 인코딩 함수 정의
def one_hot_encode_words(sentence):
    words = sentence.split()
    words_array = np.array(words).reshape(-1, 1)

    encoder = OneHotEncoder(sparse_output=False)
    one_hot_encoded = encoder.fit_transform(words_array)

    return one_hot_encoded, encoder.get_feature_names_out()
# 예제 문장
example_sentence = '오늘 날씨가 참 맑습니다.'

encoded_words, feature_names = one_hot_encode_words(example_sentence)

encoded_words, feature_names

 

 

 

 

 

 

 


Word2Vec 실습

📌 Gensim 패키지

  • 내장 함수로 모델 다운로드 가능
  • 전체 단어를 이용해 학습한 모델로, 학습 당시 사용되지 않았던 단어는 이해하지 못함

 

 

 

1단계. 필요한 패키지 불러오기

from gensim.models import KeyedVectors
from gensim.downloader import load

def use_word2vec(word, model):
    try:
        word_vector = model[word]
        return word_vector
    except KeyError:
        return "단어가 모델의 어휘에 없습니다."

word2

2018년 까지의 구글 뉴스 데이터를 모아둔 것이기 때문에 2018년 이후의 어휘에 대해서는 임베딩 하지 못한다.

# 제공하는 기본 Word2Vec 모델 불러오기
# 약 10~12분 정도 소요
word2vec_model = load('word2vec-google-news-300')
print(use_word2vec('apple', word2vec_model))
print(use_word2vec('instagram', word2vec_model)) # 학습 당시에 존재하지 않던 단어는 임베딩 불가

 

 

 

2단계. 두 단어 사이의 유사도 구하기

from scipy.spatial.distance import cosine

# 코사인 유사도 함수 정의
def word_similarity(word1, word2, model):
    try:
        vector1 = model[word1]
        vector2 = model[word2]

        similarity = 1 - cosine(vector1, vector2) # 코사인 유사도 계산
        return similarity
    except KeyError as e:
        return str(e)

# 가장 유사한 단어를 보여주는 함수 정의
def most_similar(word, model, topn=5):
    try:
        similar_words = model.most_similar(word, topn=topn) # 가장 유사한 단어 찾기
        return similar_words
    except KeyError as e:
        return str(e)
# 두 단어 사이의 유사도 확인
print('football & basketball 유사도 : ' , word_similarity('football', 'basketball', word2vec_model))
print('football & airplane 유사도 : ' , word_similarity('football', 'airplane', word2vec_model))

 

 

 

 

 

 

 

 


GloVe 실습

2019년 까지의 단어만 학습되어있기 때문에 그 이후의 단어를 임베딩할 수 없다.

# gloVe 함수 정의
def use_glove(word, model):
    try:
        word_vector = model[word]
        return word_vector
    except KeyError:
        return "단어가 모델의 어휘에 없습니다."
        
        
# 제공하는 GloVe 모델 불러오기
# 약 5분정도 소요
glove_model = load('glove-wiki-gigaword-300')

 

 

 

 

 

 

 

 

 


문장 임베딩 (Sentence Embedding)

: 문장 자체를 숫자의 형태(벡터)로 변환하는 과정

  • 전반적인 글의 이해, 문맥 파악, 글 생성 등과 같이 문장 혹은 그 이상의 단위에서 정보를 포착하는 경우에 사용
  • 글의 전반적인 이해가 쉽게 가능
  • 보다 많은 자원과 계산이 필요
  • 단어 수준의 미묘한 변화를 잡아내기가 어려움

 

 

 

 

문장에 원핫 인코딩 적용

: 문장에 소속된 각 단어를 해당 단어의 인덱스 위치에 1을 부여하고 나머지 부분을 0으로 채움

 

 

임베딩 알고리즘 (1) - 단어 임베딩을 활용한 문자 임베딩

: 각 단어들의 임베딩 평균을 활용해 문장의 임베딩을 생성

 

 

임베딩 알고리즘 (2) - TF-IDF를 활용한 문장 임베딩

: 문장 내 단어의 중요도를 나타내는 척도(=TF-IDF)를 활용한 단어 가중치를 적용해 문장 임베딩을 생성

  • TF-IDF를 이용해 각 단어 임베딩에 가중
  • 가중된 값들을 활용해 평균 값 활용

 

임베딩 알고리즘 (3) - 딥러닝을 활용한 문장 임베딩

: 문장을 구성하는 단어를 입력으로 받으면 딥러닝적 연산을 통해 각 단어에서 정보를 공급받아 각각의 단어 임베딩 벡터를 생성

 

 

 

 

 

 

 

 

 

문장 임베딩 실습

📌 CountVectorizer 라이브러리

  • 각 문장에 나온 단어를 독립적인 인덱스로 바꿔줌
  • 또한, 해당 인덱스에 1의 값을 넣어줌

 

 

1단계. 필요한 라이브러리 불러오기

## 필요한 라이브러리 불러오기
from sklearn.feature_extraction.text import CountVectorizer

## 예제 문장
# 문장 리스트
sentences = ["사과는 맛있다",
             "바나나는 맛있다",
             "딸기는 맛있다",
             "김치는 맵다",
             "짜장면은 달다",
             "소고기는 좋다"]

 

 

 

 

 

2단계. CountVectorizer 객체 생성

# CountVectorizer를 생성
# CountVectorizer : 텍스트 데이터를 단어 빈도(count)로 변환하는 객체
# binary=True : 빈도가 2 이상이어도 1로 표현
# binary=False : BoW 코드로 사용 가능
vectorizer = CountVectorizer(binary=True)
vectorizer.fit(sentences)

 

 

 

 

 

3단계. 단어 - 인덱스 매핑

# 단어-인덱스 매핑
word_to_index = vectorizer.vocabulary_
print("단어-인덱스 매핑:", word_to_index)

 

 

 

4단계. 문장 임베딩

# 문장을 벡터로 변환
input_sentence = ["소고기는 맛있다"]
# input_sentence = ["소고기는 소고기는 소고기는 맛있다"]
sentence_vectors = vectorizer.transform(input_sentence).toarray()
print(f"입력 문장 '{input_sentence[0]}'의 원핫 임베딩 벡터 :", sentence_vectors[0])

 

 

`binary=True`로 설정했기 때문에 '소고기는'이 여러번 나와도 1로 임베딩 해준다.

# 문장을 벡터로 변환
# input_sentence = ["소고기는 맛있다"]
input_sentence = ["소고기는 소고기는 소고기는 맛있다"]
sentence_vectors = vectorizer.transform(input_sentence).toarray()
print(f"입력 문장 '{input_sentence[0]}'의 원핫 임베딩 벡터 :", sentence_vectors[0])