728x90
반응형

감성분석

import pandas as pd
df = pd.read_csv('review_data.csv')
df

	score	review	y
0	1	예약할 때는 룸을 주기로 하고 홀을 주고, 덥고, 직원들이 정신이 없어 그 가격에 ...	0
1	5	점심식사 잘했던곳.후식커피한잔 하기도 좋고 주차가능합니다. 음식 맛있고 직원분 친절...	1
2	5	新鮮でおいしいです。	1
3	4	녹는다 녹아	1
4	4	NaN	1
...	...	...	...
75	2	이렇게 대기가 긴 맛집인줄 모르고 갔다가 엄청 기다림 예써라는 어플로 대기 하던데 ...	0
76	1	단짠의 정석. 진짜 정석으로 달고 짬. 질리는 맛. 사장님이랑 와이프로 추정되는 ...	0
77	4	만족스러움! 맛있어용	1
78	1	곱창은 없고 대창만 들어있어서 느끼한데 양념은 너무 매워서 위에 탈이나 고생했습니다ㅠㅠ	0
79	5	대창덮밥도 맛있고 곱도리탕도 맛나요 완전 소주각입니다. 자리가 쫍아서 테이블마다 ...	1
80 rows × 3 columns

 

import re
def text_cleaning(text) :
    hangul = re.compile('[^ ㄱ-ㅣ가-힣]+')
    result = hangul.sub('', text)
    return result
text_cleaning("abc가나다123 라마사아 123")

'가나다 라마사아 '

 

df['ko_text'] = df['review'].apply(lambda x : text_cleaning(str(x))) # null 값
df['ko_text']

0     예약할 때는 룸을 주기로 하고 홀을 주고 덥고 직원들이 정신이 없어 그 가격에 내가...
1     점심식사 잘했던곳후식커피한잔 하기도 좋고 주차가능합니다 음식 맛있고 직원분 친절하여...
2                                                      
3                                                녹는다 녹아
4                                                      
                            ...                        
75    이렇게 대기가 긴 맛집인줄 모르고 갔다가 엄청 기다림 예써라는 어플로 대기 하던데 ...
76    단짠의 정석 진짜 정석으로 달고 짬 질리는 맛  사장님이랑 와이프로 추정되는 서빙해...
77                                           만족스러움 맛있어용
78    곱창은 없고 대창만 들어있어서 느끼한데 양념은 너무 매워서 위에 탈이나 고생했습니다ㅠㅠ 
79    대창덮밥도 맛있고 곱도리탕도 맛나요 완전 소주각입니다  자리가 쫍아서 테이블마다 가...
Name: ko_text, Length: 80, dtype: object

 

df['review'].head()

0    예약할 때는 룸을 주기로 하고 홀을 주고, 덥고, 직원들이 정신이 없어 그 가격에 ...
1    점심식사 잘했던곳.후식커피한잔 하기도 좋고 주차가능합니다. 음식 맛있고 직원분 친절...
2                                           新鮮でおいしいです。
3                                               녹는다 녹아
4                                                  NaN
Name: review, dtype: object

 

df1 = df.loc[df['ko_text'].apply(lambda x : len(x)) > 0]
df1.isnull().value_counts()

score  review  y      ko_text
False  False   False  False      65
dtype: int64

 

del df['review']
df.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 80 entries, 0 to 79
Data columns (total 3 columns):
 #   Column   Non-Null Count  Dtype 
---  ------   --------------  ----- 
 0   score    80 non-null     int64 
 1   y        80 non-null     int64 
 2   ko_text  80 non-null     object
dtypes: int64(2), object(1)
memory usage: 2.0+ KB

 

from konlpy.tag import Okt

 

# 텍스트 데이터 형태소 추출
def get_pos(x) :
    tagger = Okt()
    pos = tagger.pos(x)
    # word : konlpy 모듈 형태소 분석단어
    # tag : 형태소 분석된 품사
    pos = ['{0}/{1}'.format(word, tag) for word, tag in pos]
    return pos

result = get_pos(df['ko_text'].values[0])
print(result)

['예약/Noun', '할/Verb', '때/Noun', '는/Josa', '룸/Noun', '을/Josa', '주기/Noun', '로/Josa', '하고/Verb', '홀/Noun', '을/Josa', '주고/Verb', '덥고/Adjective', '직원/Noun', '들/Suffix', '이/Josa', '정신/Noun', '이/Josa', '없어/Adjective', '그/Noun', '가격/Noun', '에/Josa', '내/Noun', '가/Josa', '직접/Noun', '구워/Verb', '먹고/Verb', '갈비살/Noun', '등심/Noun', '은/Josa', '질/Noun', '기고/Noun', '냉면/Noun', '은/Josa', '맛/Noun', '이/Josa', '없고/Adjective', '장어/Noun', '양념/Noun', '들/Suffix', '도/Josa', '제/Noun', '때/Noun', '안/Noun', '가져다/Verb', '주고/Verb', '회식/Noun', '으로/Josa', '한/Determiner', '시간/Noun', '만에/Josa', '만원/Noun', '을/Josa', '썼는데/Verb', '이런/Adjective', '경험/Noun', '처음/Noun', '입니다/Adjective']

 

from sklearn.feature_extraction.text import CountVectorizer
                     #글뭉치(corpus) 인덱스로 생성
index_vectorizer = CountVectorizer(tokenizer = lambda x : get_pos(x))
# 
 # 형태소분석하고 단어품사로 분리
x = index_vectorizer.fit_transform(df['ko_text'].tolist())
x.shape

# (80, 779)

 

for a in x[:10] :
    print(a)
    
(0, 504)	1
  (0, 743)	1
  (0, 224)	2
  (0, 162)	1
  (0, 236)	1
  (0, 538)	3
  (0, 631)	1
  (0, 235)	1
  (0, 721)	1
  (0, 769)	1
  (0, 629)	2
  (0, 189)	1
  (0, 650)	1
  (0, 210)	2
  (0, 546)	3
  (0, 609)	1
  (0, 485)	1
  (0, 97)	1
  (0, 18)	1
  (0, 491)	1
  (0, 141)	1
  (0, 13)	1
  (0, 651)	1
  (0, 87)	1
  (0, 281)	1
  (0, 34)	1
  (0, 222)	1
  (0, 537)	2
  (0, 653)	1
  (0, 107)	1
  (0, 145)	1
  (0, 258)	1
  (0, 481)	1
  (0, 588)	1
  (0, 468)	1
  (0, 192)	1
  (0, 610)	1
  (0, 453)	1
  (0, 29)	1
  (0, 772)	1
  (0, 536)	1
  (0, 738)	1
  (0, 417)	1
  (0, 250)	1
  (0, 251)	1
  (0, 439)	1
  (0, 551)	1
  (0, 61)	1
  (0, 672)	1
  (0, 573)	1
  (0, 650)	1
  (0, 13)	1
  (0, 604)	1
  (0, 585)	1
  (0, 761)	1
  (0, 79)	1
  (0, 776)	1
  (0, 691)	1
  (0, 723)	1
  (0, 618)	1
  (0, 635)	1
  (0, 22)	1
  (0, 540)	1
  (0, 261)	1
  (0, 363)	1
  (0, 689)	1
  (0, 600)	1
  (0, 321)	1
  (0, 648)	1

  (0, 154)	1
  (0, 155)	1


  (0, 162)	1
  (0, 546)	1
  (0, 491)	1
  (0, 192)	1
  (0, 251)	1
  (0, 672)	1
  (0, 529)	1
  (0, 238)	1
  (0, 451)	1
  (0, 454)	2
  (0, 443)	1
  (0, 444)	1
  (0, 506)	1
  (0, 247)	1
  (0, 516)	1
  (0, 397)	1
  (0, 49)	1
  (0, 129)	1
  (0, 641)	1
  (0, 333)	1
  (0, 66)	1
  (0, 511)	1
  (0, 116)	1
  (0, 54)	2
  (0, 318)	1
  (0, 643)	1
  (0, 509)	1
  (0, 460)	1
  (0, 547)	1
  (0, 58)	1
  (0, 409)	1
  (0, 569)	1
  (0, 71)	1
  (0, 446)	1
  (0, 301)	1
  (0, 265)	1
  (0, 649)	1
  (0, 191)	1
  (0, 168)	1
  (0, 510)	1
  (0, 48)	1
  (0, 660)	1
  (0, 389)	1
  (0, 657)	1
  (0, 186)	1
  (0, 132)	1
  (0, 538)	2
  (0, 454)	1
  (0, 66)	1
  (0, 450)	1
  (0, 300)	1
  (0, 246)	1
  (0, 527)	1
  (0, 477)	1
  (0, 237)	1
  (0, 285)	2
  (0, 62)	1
  (0, 88)	1
  (0, 337)	1
  (0, 159)	1
  (0, 314)	1
  (0, 352)	1
  (0, 652)	1
  (0, 373)	1
  (0, 437)	1
  (0, 142)	1
  (0, 663)	1
  (0, 637)	1
  (0, 382)	1
  (0, 504)	1
  (0, 546)	2
  (0, 491)	2
  (0, 536)	1
  (0, 49)	1
  (0, 531)	1
  (0, 178)	1
  (0, 599)	1
  (0, 326)	1
  (0, 628)	1
  (0, 297)	1
  (0, 577)	1
  (0, 68)	1
  (0, 457)	1
  (0, 483)	1
  (0, 746)	1
  (0, 669)	1
  (0, 597)	1
  (0, 690)	1
  (0, 494)	1
  (0, 463)	1
  (0, 632)	1
  (0, 239)	1
  (0, 165)	1
  (0, 695)	1
  (0, 213)	1
  (0, 367)	1
  (0, 296)	1
  (0, 298)	1
  (0, 475)	1
  (0, 727)	1
  (0, 713)	1
  (0, 399)	1
  (0, 702)	1
  (0, 412)	1
  (0, 182)	1
  (0, 567)	1
  (0, 255)	1
  (0, 358)	1
  (0, 346)	1
  (0, 18)	1
  (0, 13)	1
  (0, 573)	1
  (0, 397)	1
  (0, 129)	1
  (0, 182)	1
  (0, 428)	1
  (0, 774)	1
  (0, 542)	1
  (0, 147)	1
  (0, 339)	1

 

print(str(index_vectorizer.vocabulary_)[:60]+"..")

{'예약/Noun': 504, '할/Verb': 743, '때/Noun': 224, '는/Josa': 162..

# TF-IDF 변환

# TF : 1개 텍스트에 맛집 3번 있으면 3
# IDF : INVERSE역산 DF
#       모든 데이터에서 맛집단어가 10번이 존재, 0.1값
# TF - IDF 전체문서에서 나타나지 않지만 현재문서에서 많이 나타나면
#             그 단어가 현재문서에서 중요한 단어로 판단

 

from sklearn.feature_extraction.text import TfidfTransformer
tfidf_vectorizer =  TfidfTransformer()
x = tfidf_vectorizer.fit_transform(x)
print(x.shape)
print(x[0])

(80, 779)
  (0, 772)	0.13918867813287145
  (0, 769)	0.13918867813287145
  (0, 743)	0.13918867813287145
  (0, 738)	0.12718431152605908
  (0, 721)	0.12718431152605908
  (0, 672)	0.10666271126619092
  (0, 653)	0.12718431152605908
  (0, 651)	0.12718431152605908
  (0, 650)	0.09465834465937853
  (0, 631)	0.13918867813287145
  (0, 629)	0.2783773562657429
  (0, 610)	0.12718431152605908
  (0, 609)	0.13918867813287145
  (0, 588)	0.13918867813287145
  (0, 573)	0.11206059819730396
  (0, 551)	0.11866707787300333
  (0, 546)	0.22748699966260583
  (0, 538)	0.31998813379857277
  (0, 537)	0.17228222201264556
  (0, 536)	0.09814547761313519
  (0, 504)	0.12718431152605908
  (0, 491)	0.07253600802895468
  (0, 485)	0.12718431152605908
  (0, 481)	0.11866707787300333
  (0, 468)	0.11866707787300333
  (0, 453)	0.11206059819730396
  (0, 439)	0.13918867813287145
  (0, 417)	0.11866707787300333
  (0, 281)	0.11206059819730396
  (0, 258)	0.07762387735326703
  (0, 251)	0.11866707787300333
  (0, 250)	0.13918867813287145
  (0, 236)	0.13918867813287145
  (0, 235)	0.10209886289470016
  (0, 224)	0.19629095522627038
  (0, 222)	0.12718431152605908
  (0, 210)	0.21332542253238185
  (0, 192)	0.07101739767756768
  (0, 189)	0.13918867813287145
  (0, 162)	0.08377133371130897
  (0, 145)	0.13918867813287145
  (0, 141)	0.12718431152605908
  (0, 107)	0.12718431152605908
  (0, 97)	0.11206059819730396
  (0, 87)	0.12718431152605908
  (0, 61)	0.13918867813287145
  (0, 34)	0.13918867813287145
  (0, 29)	0.13918867813287145
  (0, 18)	0.11866707787300333
  (0, 13)	0.08377133371130897

 

# 긍부정 리뷰분류
# 데이터셋 분리
from sklearn.model_selection import train_test_split
y = df['y']
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.3)

x_train.shape
# (56, 779)

 

from sklearn.linear_model import LogisticRegression
lr = LogisticRegression(random_state = 0)
lr.fit(x_train, y_train)
y_pred = lr.predict(x_test)

 

from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
print("accuracy :%.2f" %accuracy_score(y_test, y_pred)) # (TP+TN) / TP+TN+FP+FN
print("precision_score :%.2f" %precision_score(y_test, y_pred))
print("recall_score :%.2f" %recall_score(y_test, y_pred))
print("f1_score :%.2f" %f1_score(y_test, y_pred))

accuracy :0.58
precision_score :0.57
recall_score :1.00
f1_score :0.72

# (TP+TN) / TP+TN+FP+FN
# print("accuracy :%.2f" %accuracy_score(y_test, y_pred)) 
=> 그냥 다 TRUE로 하면 90%인데?

# TP / TP+FP
# print("precision_score :%.2f" %precision_score(y_test, y_pred))
=> 얼마나 적절하게 맞췄는가?, TRUE 예측 중에  실제 TRUE

# (TP+TN) / TP+FN
# print("recall_score :%.2f" %recall_score(y_test, y_pred))

# print("f1_score :%.2f" %f1_score(y_test, y_pred))

 

from sklearn.metrics import confusion_matrix
confmat = confusion_matrix(y_test, y_pred)
print(confmat)

[[ 1 10]
 [ 0 13]]

실0[][]
실1[][]
  예0예1
TP : 실제 T, 예측 P // 진짜 posi 54
TN : 실제 F, 예측 N // 진짜 nega8
FP : 실제 F, 예측 P 가짜 posi 31
FN : 실제 T, 예측 n 가짜 false 1
F[TN][FP]
T[FN][TP]
  N P
정확도 62(54+8) / 94(54+8+31+1)  = 0.659
정밀도 54 / 85(54+31) = 0.635
재현율 54 / 55(54 + 1) = 0.9818
F1score 2*( 0.635* 0.9818) / ( 0.635+ 0.9818)
    
# 특이도 specificity 모델이 false로 예측한 정답중 실제 false
tn / tn+fp

 

roc
roc
y : tpr true positive rate 진짜 양성비율
x : Fpr false positive rate 가짜 양성비율 1-특이율
auc (Area under the curve) : 곡선 아래 면적

 

# roc
from sklearn.metrics import roc_curve, roc_auc_score
import matplotlib.pyplot as plt
# y_pred 예측값
# y_pred_probability 예측값의 확률값
y_pred_probability = lr.predict_proba(x_test)[:,1]
false_positive_rate, true_positive_rate, thresholds = \
            roc_curve(y_test, y_pred_probability)
roc_auc = roc_auc_score(y_test, y_pred_probability)
print('AUC : %.3f' % roc_auc)
plt.rcParams['figure.figsize'] = [5, 4]
plt.plot(false_positive_rate, true_positive_rate, \
         label='ROC  Curve(area = %0.3f)' % roc_auc, 
         color = 'red', linewidth=4.0)
plt.plot([0,1], [0,1], 'k--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.0])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC curve of Logistic regression')
plt.legend(loc='lower right')

 

 

 

반응형

'Data_Science > Data_Analysis_Py' 카테고리의 다른 글

37. iris || Kmeans  (0) 2021.11.25
36. 강남역 고기집 후기분석 || 감성분석  (0) 2021.11.25
34. 강남역 고기집 후기분석 || 맵크로울링  (0) 2021.11.25
33. white wine || GBM  (0) 2021.11.24
32. titanic || GBM  (0) 2021.11.24

+ Recent posts