검색 결과 스크래핑 & doc2vec의 기업 카테고리 (2)

검색 결과 스크래핑 & doc2vec의 기업 카테고리 (1) 의 계속입니다. 이번에는 Doc2vec에서 스크래핑 해 온 데이터를 학습시킵니다.

이번 구성


  • Google 검색결과에서 사이트 URL 가져오기 및 검색결과 텍스트 가져오기(beautifulsoup)
  • Doc2vec에서 벡터화 ← 지금 코코
  • 덴드로그램 작성

  • 이번에는 텍스트를 MeCab로 나누어 배열에 저장하고 Doc2vec에서 학습시킵니다.
    Doc2Vec의 구조와 gensim을 사용한 문서 유사도 계산 자습서 과, 문장을 벡터화하여 유사한 문장 찾기 를 참고로, 새로운 버젼의 gensim로 움직이도록 변경한 것과, 파일명을 라벨로 한 문서의 배열을 작성해 학습시키고 있습니다.

    읽은 파일의 크기


  • 2kb ~ 10kb 텍스트 250개
  • 총 단어 수: 20만 단어
  • 고유 단어 수: 2만 단어

  • 라이브러리 가져오기



    이번에는 나눠 쓰므로 MeCab을 사용합니다.
    import os
    import sys
    import re
    import MeCab
    import collections
    from gensim import models
    from gensim.models.doc2vec import LabeledSentence
    

    텍스트 파일의 배열 저장



    다음을 수행하는 함수를 만듭니다.
  • 지정된 디렉토리의 파일을 읽어, 파일명을 값으로 한 리스트를 작성
  • 파일 열기 및 읽기
  • 문장을 나누어 동사, 형용사, 명사만 남기기
  • 파일 이름을 태그로 사용하여 나누어진 문장과 세트의 배열을 만듭니다
  • path = "./keywords"
    
    # 全てのファイルのリストを取得
    def get_all_files(directory):
        for root, dirs, files in os.walk(directory):
            for file in files:
                yield re.match('[0-9]+', format(file)).group()
    
    # ファイルから文章を返す
    def read_document(fn):
        with open(path + "/" + fn + ".txt", 'r', encoding='utf-8', errors='ignore') as f:
            return f.read()
    
    # 文章から単語に分解して返す
    def split_into_words(doc, name=''):
        mecab = MeCab.Tagger("-Ochasen")
        #valid_doc = trim_doc(doc)
        lines = mecab.parse(doc).splitlines()
        words = []
        for line in lines:
            chunks = line.split('\t')
            if len(chunks) > 3 and (chunks[3].startswith('動詞') or chunks[3].startswith('形容詞') or (chunks[3].startswith('名詞') and not chunks[3].startswith('名詞-数'))):
                words.append(chunks[0])
        return LabeledSentence(words=words, tags=[name])
    
    # ファイルから単語のリストを取得
    def corpus_to_sentences(corpus):
        docs = [read_document(x) for x in corpus]
        for idx, (doc, name) in enumerate(zip(docs, corpus)):
            sys.stdout.write('\r前処理中 {} / {}'.format(idx, len(corpus)))
            yield split_into_words(doc, name)
    

    배열 저장 처리 실행


    corpus = list(get_all_files(path))
    sentences = list(corpus_to_sentences(corpus))
    

    모델 구축



    하이퍼 파라미터를 설정하고 학습합니다.
    전자의 참조원에 학습시의 최적치가 나와 있었습니다만, 이번은 샘플이 적은 (독특하고 2만어 정도) 탓인지, 참조원의 파라미터와 같이 정도가 딱 좋았습니다. 어떤 매개 변수도 놀리면 눈에 띄게 결과에 영향을 미칩니다.
    model = models.Doc2Vec(size=400, alpha=0.0015, sample=1e-4, min_count=1, workers=4)
    model.build_vocab(sentences)
    

    하이퍼 파라미터


  • size : 만들 차원의 수
  • alpha : 학습률
  • sample : 단어의 출현 빈도가 이 값보다 큰 경우는 무시되는 임계치
  • min_count : 이 값보다 출현 횟수가 작은 단어를 파기한다
  • 작업자 : 처리 할 스레드 수

  • 학습



    한 문장에서 단어를 연상시켜 그 단어를 건네주고 가까운 문장을 냈을 때에, 자신이 최상위였던 문장이 100개 중 90개 이상이라고 OK라고 판정하는 처리를 넣고 있습니다.
    18회 정도까지 가면 OK가 나오게 되었습니다.
    token_count = sum([len(sentence) for sentence in sentences])
    
    for x in range(30):
        print(x)
        model.train(sentences, total_examples = token_count, epochs = 10)
        ranks = []
        for doc_id in range(100):
            inferred_vector = model.infer_vector(sentences[doc_id].words)
            sims = model.docvecs.most_similar([inferred_vector], topn=len(model.docvecs))
            rank = [docid for docid, sim in sims].index(sentences[doc_id].tags[0])
            ranks.append(rank)
            if collections.Counter(ranks)[0] >= 90:
                print('ok')
                break
    

    모델 저장



    이 사이의 클러스터링에도 이용하므로, 나중에 참조할 수 있도록 저장해 둡니다.
    model.save("doc2vec.model")
    

    검증



    매우 아날로그이지만 다음을 시도하면서 튜닝했습니다.
  • 어떤 단어로 가까운 기업이 올라가는가
  • 적당한 기업을 선택하고 가까운 기업 목록이 정말로 가깝습니까



  • 코드는 참조 사이트 의 만마이므로 할애.

    매개 변수로 시도한 결과



    당연히, 하이퍼파라미터의 튜닝으로 상당히 결과가 바뀝니다.
    크로스 밸리데이션을 할 수 없기 때문에, 수동으로 파라미터를 바꾸어 보았던 범위에서 알았던 것은 이하.


    시험 내용
    결과


    반복에서 0.025에서 0.0001까지 학습률을 선형 감쇠
    수렴하지 않습니다. 딱 좋은 곳에서 고정하고 학습시키는 편이 좋았다.

    epoch 변경
    반복수가 총 1000회(epoch=33)라면 수렴하지 않는다. epoch = 5보다 epoch = 10이 더 잘 분류되었습니다.

    size 변경
    많을수록 좋아진다.


    음, 다음에 드디어 덴드로그램을 만듭니다.

    좋은 웹페이지 즐겨찾기