team-i-Five / code_Machine-learning

mumo 프로젝트 머신 러닝 코드 repo
4 stars 0 forks source link

뮤지컬 데이터(샘플) 이용한 추천 시스템 #13

Open minjung00 opened 11 months ago

minjung00 commented 11 months ago

1. 콘텐츠 기반 필터링


해당코드는 branch 0.0.3/work2vec_test → Model_test/Content_mock.ipynb 있습니다.

qkrtnqls1216 commented 11 months ago

FAST API를 사용한 컨텐츠 기반 필터링 응답 확인


  1. 가상환경 실행하기 가상환경 실행이유: 로컬에서 여러가지를 다운받지 않고 격리된 환경에서 설치 및 테스트를 진행하기 위해 $ python3 -m venv ~/ML $ source ~/ML/bin/activate image image [만약 가상환경이 없는 경우] $ mkdir ~/ML $ python3 -m venv ~/ML $ source ~/ML/bin/activate image
  2. FastAPI설치하기 pip install fastapi
  3. FastAPI 애플리케이션을 실행하기 위해 Uvicorn을 설치 pip install uvicorn
  4. FastAPI 앱 만들기 FastAPI를 테스트를 진행하려는 프로젝트로 이동하여 app.py를 생성한 후 FastAPI를 정의한다.

    # 필요한 라이브러리 및 모듈 import
    import os  # 운영 체제와 상호 작용하기 위한 모듈
    import pandas as pd  # 데이터 조작 및 분석을 위한 라이브러리
    import numpy as np  # 수치 계산을 위한 라이브러리
    from konlpy.tag import Okt  # 한국어 형태소 분석을 위한 라이브러리
    from gensim.models.word2vec import Word2Vec  # 단어 임베딩을 위한 Word2Vec 모델
    import re  # 정규 표현식을 사용하기 위한 라이브러리
    import html  # HTML 엔터티를 변환하기 위한 라이브러리
    from sklearn.metrics.pairwise import euclidean_distances  # 유클리디언 거리 계산을 위한 라이브러리
    from sklearn.preprocessing import StandardScaler  # 데이터 스케일링을 위한 라이브러리
    from fastapi import FastAPI  # FastAPI 웹 프레임워크
    
    # FastAPI 애플리케이션 초기화
    app = FastAPI()
    
    # Java 환경 변수 설정
    os.environ["JAVA_HOME"] = "C:\Program Files\Java\jdk-11"
    
    # 뮤지컬 데이터 파일 URL
    file = "https://drive.google.com/uc?id=구글드라이브 해당 csv파일의 id값을 넣기"
    
    # CSV에서 뮤지컬 데이터 불러오기
    musical_data = pd.read_csv(file, encoding='utf-8')
    # 모든 열에서 특수 문자와 HTML 엔터티 정제
    for col in musical_data.columns:
      musical_data[col] = musical_data[col].apply(lambda x: re.sub(r'[^\w\s]', '', html.unescape(str(x))))
    
    # Konlpy를 사용한 텍스트 전처리
    twitter = Okt()
    
    # 텍스트 전처리 함수
    def preprocessingText(synopsis):
      stems = []  # 형태소 추출 결과를 저장할 리스트
      tagged_review = twitter.pos(synopsis, stem=True)  # 한국어 형태소 분석기를 사용하여 형태소 추출
    
      # 각 단어와 형태소의 품사에 대해 반복
      for word, pos in tagged_review:
          # 명사(Noun) 또는 형용사(Adjective)인 경우에만 추출 리스트에 추가
          if pos == "Noun" or pos == 'Adjective':
              stems.append(word)
    
      # 공백을 이용하여 추출한 형태소들을 하나의 문자열로 결합하여 반환
      return " ".join(stems)
    
    # 각 시놉시스에 대해 전처리 함수 적용
    musical_data['synopsis_clear'] = musical_data['synopsis'].fillna('').apply(preprocessingText)
    
    # 시놉시스 데이터를 리스트로 변환
    sentences = musical_data['synopsis'].tolist()
    
    # 시놉시스 열의 각 텍스트에 대해 앞서 정의한 전처리 함수(preprocessingText)를 적용하고 NaN 값은 빈 문자열로 대체
    tokenized_data = musical_data['synopsis'].apply(lambda x: preprocessingText(str(x))).fillna('')
    
    # 새로운 열 'synopsis_clear'에 전처리된 텍스트 추가 및 공백 추가
    musical_data["synopsis_clear"] = musical_data['synopsis_clear'].astype(str) + " "
    
    # 'synopsis_clear' 열의 각 텍스트를 공백을 기준으로 분할하여 리스트로 변환하여 'tokenized_data' 열에 추가
    musical_data["tokenized_data"] = musical_data["synopsis_clear"].apply(lambda data: data.split(" "))
    
    model = Word2Vec(musical_data["tokenized_data"],
                   vector_size=100,
                   window=3,
                   min_count=2,
                   sg=1)
    
    model.save("word2vec_model2.bin")
    
    # WordVector 단어를 문자열로 변환
    word2vec_words = model.wv.key_to_index.keys()
    
    # 시놉시스를 벡터화하고 문자열로 저장
    string_array = []
    
    # 데이터프레임의 행 수 만큼 반복
    for index in range(len(musical_data)):
      # 각 행에서 'musical_id', 'title', 'tokenized_data' 열의 데이터 추출
      NUM = musical_data.loc[index, "musical_id"]
      TITLE = musical_data.loc[index, "title"]
      LINE = musical_data.loc[index, "tokenized_data"]
    
      # 문장 벡터 초기화
      doc2vec = None
      # 해당 문장에 포함된 단어 수 초기화
      count = 0
    
      # 각 단어에 대해 Word2Vec 모델 적용
      for word in LINE:
          # 모델이 학습한 단어일 경우
          if word in word2vec_words:
              # 해당 단어의 벡터를 더함
              count += 1
              if doc2vec is None:
                  doc2vec = model.wv[word]
              else:
                  doc2vec = doc2vec + model.wv[word]
    
      # 문장의 벡터값 계산 (평균값)
      if doc2vec is not None:
          doc2vec = doc2vec / count
    
     # 문자열로 변환하여 저장
     string_array.append(doc2vec.tostring())
    
    # 데이터프레임에 새로운 열 추가
    musical_data["doc2vec_vec"] = string_array
    
    # 날짜에서 start_date와 end_date 추출
    musical_data['start_date'] = pd.to_datetime(musical_data['date'].str[:8], format="%Y%m%d")
    musical_data['end_date'] = pd.to_datetime(musical_data['date'].str[:6], format="%Y%m")
    # 열 재정렬
    musical_data = musical_data[['musical_id', 'title', 'poster_url', 'genre', 'date', 'start_date', 'end_date', 'location',
                               'actors', 'age_rating', 'running_time', 'describe', 'synopsis', 'synopsis_clear',
                               'tokenized_data', 'doc2vec_vec']]
    
    # 필요시 CSV로 저장
    # musical_data.to_csv('../musical_data_vector.csv', index=False, encoding='utf-8')
    
    # 추천 시스템
    # doc2vec_vec을 numpy 배열로 변환
    musical_data["doc2vec_numpy"] = musical_data["doc2vec_vec"].apply(lambda x: np.fromstring(x, dtype="float32"))
    
    # 데이터 스케일 조정
    scaler = StandardScaler()
    scaler.fit(np.array(musical_data["doc2vec_numpy"].tolist()))
    musical_data["doc2vec_numpy_scale"] = scaler.transform(np.array(musical_data["doc2vec_numpy"].tolist())).tolist()
    
    # 유클리디언 거리 계산
    sim_score = euclidean_distances(musical_data["doc2vec_numpy_scale"].tolist(), musical_data["doc2vec_numpy_scale"].tolist())
    sim_df = pd.DataFrame(data=sim_score, index=musical_data["title"], columns=musical_data["title"])
    
    # 예시: "빨간모자2"와 유사한 5개의 뮤지컬 가져오기
    similar_musicals = sim_df["빨간모자2"].sort_values()[1:6]
    
    # FastAPI 초기 엔드포인트용 route
    @app.get("/")
    def init():
      return similar_musicals

    => 이전페이지에서 작성했던 컨텐츠 기반 추천 시스템 코드를 REST API에서 응답을 확인하기 위해 app.py로 이동한것.

  5. FastAPI 애플리케이션을 실행 uvicorn app:app --reload --host 0.0.0.0 --port 8080 [실행결과 추가 예정]