➕ Data Science/▹ ML

2. IMDB 영화리뷰 데이터 분류

Ardor924 2025. 6. 2. 16:17

IMDB 영화리뷰 데이터 분류

데이터셋

🔶 영문 영화 리뷰 데이터셋
🔶 라벨 : neg(부정), pos(긍정), unsup(라벨없음 - 비지도학습용)
🔶 100,000개 데이터로 구성

1. 데이터 셋 불러오기

코드

df = pd.read_csv(base_path + 'imdb_master.csv', encoding='latin-1')
df.head(5)

결과
![[Screenshot_426.png]]

2. 전처리

🔶사용할 컬럼만 선택 (review, label)

코드

df_2 = df[['review','label']]

결과
![[Screenshot_427.png]]

3. EDA

🔶EDA : 데이터를 수정하지 않고 눈으로 확인하는 작업 ◻ 오류, 결측치 , 이상치 유무 확인 ◻ 편향유무 ◻ 분산,평균확인 ◻ 시각화

🔶 피쳐엔지니어링 : 요구사항에 맞게 데이터를 가공하는 작업

🔶 라벨 클래스의 갯수확인 -> 범주형 데이터의 편향을 확인

코드

df2['label'].value_counts()

결과
![[Screenshot_428.png]]

🔶 unsup 제거

코드

filter_mask =  df2['label'] == 'unsup'
df2.drop(df2[filter_mask].index, inplace=True)
df2['label'].value_counts()

결과
![[Screenshot_429.png]]

🔶 review 컬럼 에 영문만 남기기 코드

df['review'] = df2['review'].apply(lambda x: re.sub('[^A-Za-z\\\\s]','',x))

결과 ![[Screenshot_430.png]]

🔶 review 컬럼 에 비어있는지 확인

코드

df2[df2['review'] == '']

결과
![[Screenshot_431.png]]

  • --> 빈 데이터는 따로 없음

4. 학습준비

🔶 훈련/검증 데이터 분리

코드

X = df2['review']
y = df2['label']

X_train,X_val, y_train, y_val = train_test_split(X,y, test_size=0.25, random_state=SEED)

X_train.shape,  X_val.shape, y_train.shape, y_val.shape

결과 ((37500,), (12500,), (37500,), (12500,))

🔶 텍스트마이닝

◻ 토큰화/인코딩 ◽ Count Vectorizer

cv = CountVectorizer(max_features=10000)

cv.fit(X_train)

X_train_cv = cv.transform(X_train).toarray()
X_val_cv = cv.transform(X_val).toarray()

◽ TF-IFD Vectorizer

tf = TfidfVectorizer(max_features=10000)

tf.fit(X_train)

X_train_tf = tf.transform(X_train).toarray()
X_val_tf = tf.transform(X_val).toarray()

5. 학습/검증

◻ 사용모델 ◽ Linear Regression ◽ Random Forest ◽ Light GBM

◻ 훈련 ◽ Count Vectorizer

# 훈련(CountVectorizer)
lr_model = LogisticRegression(C=10,max_iter=15000)

lr_model.fit(X_train_cv, y_train)

train_score_cv = lr_model.score(X_train_cv, y_train)
valid_score_cv = lr_model.score(X_val_cv, y_val)
print(f'train score : {train_score_cv*100:.2f}%')
print(f'valid score : {valid_score_cv*100:.2f}%')

◽ TF-IFD Vectorizer

# 훈련(TF-IDF Vectorizer)
lr_model = LogisticRegression(C=10,max_iter=15000)

lr_model.fit(X_train_tf, y_train)

train_score_tf = lr_model.score(X_train_tf, y_train)
valid_score_tf = lr_model.score(X_val_tf, y_val)

print(f'train score : {train_score_tf*100:.2f}%')
print(f'valid score : {valid_score_tf*100:.2f}%')

6. 예측

◻ 예측 ◽ 랜덤포레스트

# 랜덤 포레스트 모델 훈련/예측
rf_model = RandomForestClassifier()

rf_model.fit(X_train_cv, y_train)

train_score_cv = rf_model.score(X_train_cv, y_train)
valid_score_cv = rf_model.score(X_val_cv, y_val)
print(f'train score : {train_score_cv*100:.2f}%')
print(f'valid score : {valid_score_cv*100:.2f}%')

# 예측(CountVectorizer)
pred = rf_model.predict(X_val_cv)
score = accuracy_score(pred,y_val)
print(f'accuracy score : {score*100:.1f}%')

◽ LightGBM

# LightGBM 모델 훈련/예측
lgbm_model = LGBMClassifier(verbose=-1)

lgbm_model.fit(X_train_tf, y_train)

train_score_tf = lgbm_model.score(X_train_tf, y_train)
valid_score_tf = lgbm_model.score(X_val_tf, y_val)
print(f'train score : {train_score_cv*100:.2f}%')
print(f'valid score : {valid_score_cv*100:.2f}%')

# 예측(TF-IDF Vectorizer)
pred = lgbm_model.predict(X_val_tf)
score = accuracy_score(pred,y_val)
print(f'accuracy score : {score*100:.1f}%')

7. 임베딩후 훈련

임베딩 사용을 위한 gensim 설치 주의! : Colab이용시, numpy와 충돌발생하므로 설치후 세션 재시작

!pip install gensim

🔶 토큰화 코드

# 토큰화
from tqdm.auto import tqdm
def tokenize_text(texts) :
    return [word_tokenize(text) for text in tqdm(texts)]

X_train_token = tokenize_text(X_train)
X_val_token = tokenize_text(X_val)

🔶FastText로 임베딩 코드

fasttext_model = FastText(sentences=tqdm(X_train_token), vector_size=100, window=3, min_count=1, sg=1)

def get_sentence_vector(tokens,model):
  vectors = [model.wv[word] for word in tokens if word in model.wv]
  return np.mean(vectors, axis=0) if vectors else np.zeros(model.vector_size)

X_train_vec = np.array([get_sentence_vector(tokens,fasttext_model) for tokens in X_train_token])
X_valid_vec = np.array([get_sentence_vector(tokens,fasttext_model) for tokens in X_val_token])

🔶 훈련/검증 코드

lr_model = LogisticRegression(C=10,max_iter=15000)
lr_model.fit(X_train_vec, y_train)

rf_model = RandomForestClassifier(random_state=SEED,n_estimators=100)
rf_model.fit(X_train_vec, y_train)

lgbm_model = LGBMClassifier(verbose=-1)
lgbm_model.fit(X_train_vec, y_train)

# 훈련/검증
lr_score_train   = lr_model.score(X_train_vec, y_train)
rf_score_train   = rf_model.score(X_train_vec, y_train)
lgbm_score_train = lgbm_model.score(X_train_vec, y_train)

lr_score_val   = lr_model.score(X_valid_vec, y_val)
rf_score_val   = rf_model.score(X_valid_vec, y_val)
lgbm_score_val = lgbm_model.score(X_valid_vec, y_val)

print('='*150)
print(f'Linear Regression train score : {lr_score_train*100:.2f}%')
print(f'Random Forest train score : {rf_score_train*100:.2f}%')
print(f'LGBM train score : {lgbm_score_train*100:.2f}%')
print('-'*50)
print(f'Linear Regression valid score : {lr_score_val*100:.2f}%')
print(f'Random Forest valid score : {rf_score_val*100:.2f}%')
print(f'LGBM valid score : {lgbm_score_val*100:.2f}%')
print('='*150)

결과
![[Screenshot_433 1.png]]

🔶예측
코드

# 예측
lr_pred = lr_model.predict(X_valid_vec)
rf_pred = rf_model.predict(X_valid_vec)
lgbm_pred = lgbm_model.predict(X_valid_vec)

# 스코어
lr_score = accuracy_score(lr_pred,y_val)
rf_score = accuracy_score(rf_pred,y_val)
lgbm_score = accuracy_score(lgbm_pred,y_val)

# 스코어 출력
print(f'Linear Regression  score : {lr_score*100:.2f}%')
print(f'Random Forest  score : {rf_score*100:.2f}%')
print(f'LGBM  score : {lgbm_score*100:.2f}%')

결과
![[Screenshot_434.png]]

랜덤 포레스트

🔶 주요 하이퍼 파라미터
◻ 트리의개수 : n_estimate
◻ 특징의 최대수 : max_feature
◻ 랜덤값 : randomseed

🔶Tip! :

  • 기존 결정트리의 단점은 너무 복잡하다 = 모든 특성을 맞춰야 해서 과대적합발생
  • (=만족조건이 너무까다로움)
  • ex) 핸드폰의 조건은 ? 사각형이다,카메라가몇개다,액정이있고..등등 자세한조건에 맞추면 형태가 다른 모델은 핸드폰으로 예측할수 없음
  • 때문에 일반화가 필요하다.
  • 예를들어 여러모델의 앙상블 즉 투표를 통해 평균을 내는 방식으로 진행한다고 보면 이해가 쉬움