[ML] 문서 분류를 위한 로지스틱 회귀 모델 훈련

Woong·2024년 11월 6일
0

Python / Machine Learning

목록 보기
17/22

GridSearchCV

  • 머신러닝에서 모델의 성능향상을 위해 쓰이는 기법
  • 사용자가 모델의 하이퍼파라미터 값을 리스트로 입력
  • 입력 값에 대한 경우의 수마다 예측 성능을 측정 평가하여 비교 -> 최적의 하이퍼파라미터 값을 찾음

훈련 코드

  • ngram_range: 1어절 1-gram 표현
  • 첫번째 param_grid
    • TfidfVectorizer 기본 매개변수 세팅(use_idf=True, norm='l2') -> 해당 설정으로 tf-idf 계산
  • 두번째 param_grid
    • 단어 빈도를 사용하여 모델 훈련(use_idf=False, norm=None)
  • 로지스틱 회귀 분류기는 penalty 매개변수를 통해 L1,L2 규제를 적용.
  • 규제 강도는 C에 여러 값을 지정하여 비교
  • GridSearchCV 파라미터
    • cv: 교차검증을 위한 fold 횟수
    • verbose: 수행결과 메세지 출력
    • scoring: 성능을 측정할 평가 방법
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import GridSearchCV

tfidf = TfidfVectorizer(strip_accents=None,
                        lowercase=False,
                        preprocessor=None)

param_grid = [{'vect__ngram_range': [(1, 1)],
               'vect__stop_words': [stop, None],
               'vect__tokenizer': [tokenizer, tokenizer_porter],
               'clf__penalty': ['l1', 'l2'],
               'clf__C': [1.0, 10.0, 100.0]},
              {'vect__ngram_range': [(1, 1)],
               'vect__stop_words': [stop, None],
               'vect__tokenizer': [tokenizer, tokenizer_porter],
               'vect__use_idf':[False],
               'vect__norm':[None],
               'clf__penalty': ['l1', 'l2'],
               'clf__C': [1.0, 10.0, 100.0]},
              ]

lr_tfidf = Pipeline([('vect', tfidf),
                     ('clf', LogisticRegression(random_state=0, solver='liblinear'))])

gs_lr_tfidf = GridSearchCV(lr_tfidf, param_grid,
                           scoring='accuracy',
                           cv=5, verbose=1
                           n_jobs=1)
                           
gs_lr_tfidf.fit(X_train, y_train)

대용량 데이터 처리: 온라인 알고리즘과 외부 메모리학습

  • 그리드서치안에서 5만개 영화 리뷰 벡터를 만들면 많은 시간 소요
  • 대량 데이터셋을 다룰 수 있는 외부 메모리 학습 기법을 사용하여 시간 감소
  • 다음과 가티 한번에 문서 하나씩 읽어 반환하는 메소드 정의
def stream_docs(path):
    with open(path, 'r', encoding='utf-8') as csv:
        next(csv)  # 헤더 넘기기
        for line in csv:
            text, label = line[:-3], int(line[-2])
            yield text, label
			
			
  • 문서를 읽어 size 매개변수에서 지정한 만큼 문서를 반환하는 get_minibatch 함수 정의
def get_minibatch(doc_stream, size):
    docs, y = [], []
    try:
        for _ in range(size):
            text, label = next(doc_stream)
            docs.append(text)
            y.append(label)
    except StopIteration:
        return None, None
    return docs, y
  • 외부 메모리 학습에 CountVectorizer, TfidfVectorizer 를 사용할 수 없다.
    • (어휘사전, 특성 벡터를 메모리에 적재해야해서)
  • 대신 HashingVectorizer 를 사용. 데이터 종류 상관없이 사용 가능.
    • 어휘 사전을 저장할 필요가 없기 때문에 대규모 데이터 세트로 확장 가능. 메모리 사용량 적음
    • 생성자 매개변수 외에는 상태를 보유하지 않으므로 피클, 언피클 속도 빠름
    • 해시 함수를 사용하기 때문에 원본 단어의 의미 정보가 완전히 유지되지 않을 수 있음.
    • 충돌로 인해 서로 다른 단어가 동일한 해시 값으로 매핑될 수 있음
from sklearn.feature_extraction.text import HashingVectorizer
from sklearn.linear_model import SGDClassifier


vect = HashingVectorizer(decode_error='ignore', 
                         n_features=2**21,
                         preprocessor=None, 
                         tokenizer=tokenizer)
                         
clf = SGDClassifier(loss='log', random_state=1)


doc_stream = stream_docs(path='movie_data.csv')

--------------------

import pyprind
pbar = pyprind.ProgBar(45)

classes = np.array([0, 1])
for _ in range(45):
    X_train, y_train = get_minibatch(doc_stream, size=1000)
    if not X_train:
        break
    X_train = vect.transform(X_train)
    clf.partial_fit(X_train, y_train, classes=classes)
    pbar.update()

LDA (Latent Disrichlet Allocation)

  • 잠재 디리클레 할당
  • 주어진 문서들에서 주제를 추출하는 방법론
  • 문서가 포함하는 단어에 기반 하여 주제별로 문서를 분류할 수 있음
  • 십만개 이상의 문서가 있는 경우는 직접 토픽을 찾아내는 것이 어렵기 때문에 LDA를 이용하여 토픽 추출

LDA 과정

  • 데이터 불러오기 및 전처리
  • 단어 추출
  • 벡터 변환 및 토픽 추정
  • 토픽에 할당된 키워드 및 문서 추출

데이터 불러오기 및 전처리

  • 불용문자, 특문, 조사 등 제거
문서1 : 저는 사과랑 바나나를 먹어요.
문서2 : 우리는 귀여운 강아지가 좋아요.
문서3 : 저의 깜찍하고 귀여운 강아지가 바나나를 먹어요.

단어 추출

  • 각 문서별 전처리된 단어 나열
문서1 : 사과, 바나나, 먹어요
문서2 : 우리, 귀여운, 강아지, 좋아요
문서3 : 깜직하고, 귀여운, 강아지, 바나나, 먹어요

벡터 변환 및 토픽 추정

  • LDA는 각문서의 토픽 분포와 토픽 내 단어 분포를 추정
    • 2개 토픽을 추출한다고 가정(하이퍼파라미터 설정)
  • 각 단어를 벡터로 변환
from sklearn.feature_extraction.text import CountVectorizer
count = CounVectorizer(stop_words='english', max_df=.1, max_features=7)
X = count.fit_transform(df['review'].values)
  • 토픽 추정
    • batch는 lda 추정기가 한번 반복할 때 가능한 모든 훈련 데이터를 사용하여 학습
from sklearn.decomposition import LatentDirichletAllocation
lda = LatentDirichletAllocation(n_components=2, random_state=123, learning_method='batch')
X_topics = lda.fit_transform(X)
  • 각 문서의 토픽 분포
문서1 : 토픽 A 100%
문서2 : 토픽 B 100%
문서3 : 토픽 B 60%, 토픽 A 40%
  • 각 토픽의 단어 분포
토픽A : 사과 20%, 바나나 40%, 먹어요 40%, 귀여운 0%, 강아지 0%, 깜찍하고 0%, 좋아요 0%
토픽B : 사과 0%, 바나나 0%, 먹어요 0%, 귀여운 33%, 강아지 33%, 깜찍하고 16%, 좋아요 16%

0개의 댓글