← Back to portfolio
Project · NLP

리뷰 분석을 통한 상품 추천 여부 예측

ToyProjectNLP · TF-IDF데이터 전처리 · 모델링

🪢데이터 출처

https://www.kaggle.com/datasets/nicapotato/womens-ecommerce-clothing-reviews

📌프로젝트 개요

➡️ 작성한 리뷰가 해당 제품을 추천하는 리뷰인지, 비추천하는 리뷰인지 예측해보는 분류모델로 구현해보기

1. 데이터 확인

→ Unnamed, unnamed는 필요없는 칼럼. (인덱스임)

→ Title이랑 Review Text로 Recommend IND (0,1)을 예측해보는 모델 설계!

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 23486 entries, 0 to 23485
Data columns (total 12 columns):
 #   Column                   Non-Null Count  Dtype 
---  ------                   --------------  ----- 
 0   Unnamed: 0.1             23486 non-null  int64 
 1   Unnamed: 0               23486 non-null  int64 
 2   Clothing ID              23486 non-null  int64 
 3   Age                      23486 non-null  int64 
 **4   Title                    19676 non-null  object
 5   Review Text              22641 non-null  object**
 6   Rating                   23486 non-null  int64 
 **7   Recommended IND          23486 non-null  int64** 
 8   Positive Feedback Count  23486 non-null  int64 
 9   Division Name            23472 non-null  object
 10  Department Name          23472 non-null  object
 11  Class Name               23472 non-null  object
dtypes: int64(7), object(5)
memory usage: 2.2+ MB
Unnamed: 0.1 Unnamed: 0 Clothing ID Age Rating Recommended IND Positive Feedback Count
count 23486.000000 23486.000000 23486.000000 23486.000000 23486.000000 23486.000000
mean 11742.500000 11742.500000 918.118709 43.198544 4.196032 0.177638
std 6779.968547 6779.968547 203.298980 12.279544 1.110031 0.382216
min 0.000000 0.000000 0.000000 18.000000 1.000000 0.000000
25% 5871.250000 5871.250000 861.000000 34.000000 4.000000 0.000000
50% 11742.500000 11742.500000 936.000000 41.000000 5.000000 0.000000
75% 17613.750000 17613.750000 1078.000000 52.000000 5.000000 0.000000
max 23485.000000 23485.000000 1205.000000 99.000000 5.000000 1.000000

2. 데이터 결측치 처리: Outlier

→ 새롭게 만든 df_clean 데이터 프레임으로 시작

Clothing ID                   0
Age                           0
Title                      3810
**Review Text                 845**
Rating                        0
Recommended IND               0
Positive Feedback Count       0
Division Name                14
Department Name              14
Class Name                   14
dtype: int64

Title, Review text에 결측치 좀 있고, 아래 3개 14개 있음.

Clothing ID                   0
Age                           0
Title                      2966
**Review Text                   0**
Rating                        0
Recommended IND               0
Positive Feedback Count       0
Division Name                13
Department Name              13
Class Name                   13
dtype: int64

Review Text 삭제 했음.

3. 데이터 시각화: 워드 클라우드

📌 re.findall(): 띄어쓰기 단위로 단어를 가져오는 메서드!
Ex. df_clean_title['Title'].str.lower().str.cat(sep=' ')
=>'some major design flaws my favorite buy! flattering ….’
⇒ 띄어쓰기 단위로 만들었음
⇒ 이걸 findall()에 대입해서 사용

→ 잘 출력되는 거 확인

['some',
 'major',
 'design',
 'flaws',
 'my',
 'favorite',
 'buy',
 'flattering',
 'shirt',
 'not',
 'for',
 'the',
 'very',
 'petite',
 'cagrcoal',
 'shimmer',
 'fun',
 ....
 ]

📌 tokesn에서 stopwords(불용어 처리 메서드)에 해당되지 않는 단어를 따로 저장하면 → 불용어가 아닌 쓸모 있는 단어들만 채택됨.

filtered_sentence = [token for token in tokens if not token in en_stops]

en_stops → 여기에 불용어가 저장됨. a, an, the, all, am 등

Untitled

→ Love, Beautiful, pretty, perfect, dress, cute가 크게 보임 ⇒ 많이 쓰인다는 뜻.

Review Text에 적용하기

Untitled

→ 뭔가 Title이랑 비슷해보임?

→ Top, dres, look, skirt, fabric, 등이 보임.

추천하는지, 안하는지 → Recommended IND 0, 1 분포 확인

Recommended IND
0 18540
1 4101
Name: count, dtype: int64

Untitled

→ 데이터 불균형이 있는 상태임. 이 상태로 하면 머신러닝 모델의 성능이 떨어지겠지만 그래도 자연어 전처리를 시도해보는 게 이 프로젝트의 의의니까 그냥 패스하기로 함.

4. 데이터 전처리 - (1) 자연어 전처리: TF-IDF

📌 자연어 데이터 → 머신러닝 입력값으로 바꿔줘야 함.
자연어 빈도 기반으로 → 수치로 변환한다는 뜻!

from sklearn.feature_extraction.text import TfidfVectorizer

# 객체 불러오기, 불용어처리는 영어로 
vectorizer = TfidfVectorizer(stop_words = 'english')
# Review Text 전부 소문자로 -> 그 다음 TF-IDF 적용하기 
X = vectorizer.fit_transform(df_clean['Review Text'].str.lower())

(22641, 13855)

y = df_clean['Recommended IND']
y = y.to_numpy().ravel() 
# 1 차원 벡터 형태로 출력하기 위해 ravel 사용
y

→ array([0, 0, 1, ..., 1, 0, 0])

4. 데이터 전처리 - (2) 학습셋 vs 테스트셋

5. 머신러닝 모델 학습

  1. DecisionTreeClassifier

Accuracy

1.0
0.8039302274232722

→ 과적합이 일어남. 데이터 불균형때문에 어쩔 수 없다고 판단함.

  1. 나머지 모델 한번에 학습하기

KNN, MultinomialNB, BernoulliNB, RandomForestClassifier, SVC, XGB 시도

KNN - train_score : 0.885987, test score : 0.831972
NB-M - train_score : 0.836020, test score : 0.814749
NB-B - train_score : 0.907078, test score : 0.866416
RF - train_score : 1.000000, test score : 0.847207
SVM - train_score : 0.821996, test score : 0.806359
XGB - train_score : 0.946720, test score : 0.868404

→ 학습셋으로 보면 랜덤포레스트가 가장 나은데, 시험셋이랑 같이 보면 XGB가 가장 뛰어남. XGB 모델로 변수 중요도 확인해보기

Untitled

→ 특성 중요도를 기반으로 그에 대한 단어로 출력하도록 함.

unflattering, cheap, perfect, returning, huge라는 단어들이 상위 5위로 출력됨.

6. 평가 및 예측: Confusion Matrix

Recomended IND
추천한다 0
추천하지 않는다 1

→ 여기서 0에 치우쳐진 데이터였음.

추천하지 않는다 1에 대한 평가도 확인을 해봐야 할 듯.

from sklearn.metrics import confusion_matrix

# XGB 모델로 Confusion matrix 확인하기 
model_predition_xgb = models[-1][1].predict(x_test)
cm_xgb = confusion_matrix(y_test, model_predition_xgb)

# 히트맵으로 2x2 출력하기 
plt.rcParams['figure.figsize'] = (5, 5)
sns.set(style = 'dark', font_scale = 1.4)
ax = sns.heatmap(cm_xgb, annot=True)
plt.xlabel('Real Data')
plt.ylabel('Prediction')
plt.show()
cm_xgb

Untitled

array([[3510, 142],
[ 454, 423]])

| ‘추천’ 예측시
→ 실제 추천인 갯수 | ‘비추천’ 예측시
→ 실제 추천인 갯수 |
| --- | --- |
| ‘추천’ 예측시
→ 실제 비추천 갯수 | ‘비추천’ 예측시
→ 실제 비추천 갯수 |
- recall, precision 성능 점수 확인하기

from sklearn.metrics import recall_score
from sklearn.metrics import precision_score

print("Recall score: {}".format(recall_score(y_test, model_predition_xgb )))
print("Precision score: {}".format(precision_score(y_test, model_predition_xgb )))

Recall score: 0.22006841505131128
Precision score: 0.8935185185185185

→ 비추천에 대한 데이터가 적어서 Recall 성능 점수 현저히 낮음

→ 추천에 대해 치우쳐진 데이터라서 Precision 성능 높음.

💡깨달은 점