|
| 1 | +# 호텔 리뷰로 감정 분석하기 |
| 2 | + |
| 3 | +지금까지 자세히 데이터셋을 살펴보았으며, 열을 필터링하고 데이터셋으로 NLP 기술을 사용하여 호텔에 대한 새로운 시각을 얻게 될 시간입니다. |
| 4 | + |
| 5 | +## [강의 전 퀴즈](https://jolly-sea-0a877260f.azurestaticapps.net/quiz/39/) |
| 6 | + |
| 7 | +### 필터링 & 감정 분석 작업 |
| 8 | + |
| 9 | +알고 있는 것처럼, 데이터셋에 약간의 이슈가 있었습니다. 일부 열은 필요없는 정보로 채워져있으며, 부정확해 보입니다. 만약 맞는 경우, 어떻게 계산되었는지 불투명하고, 답을 스스로 계산해서 독립적으로 확인할 수 없습니다. |
| 10 | + |
| 11 | +## 연습: 조금 더 데이터 처리하기 |
| 12 | + |
| 13 | +조금 더 데이터를 정리합니다. 열을 추가하는 것은 나중에 유용하며, 다른 열에서 값을 변경하고, 특정한 열을 완전히 드랍하게 됩니다. |
| 14 | + |
| 15 | +1. 초기 column 처리합니다 |
| 16 | + |
| 17 | + 1. `lat` 과 `lng`를 드랍합니다 |
| 18 | + |
| 19 | + 2. `Hotel_Address` 값을 다음 값으로 치환합니다 (만약 주소에 도시와 국가가 같다면, 도시와 국가만 변경합니다). |
| 20 | + |
| 21 | + 데이터셋에서 도시와 국가만 있습니다: |
| 22 | + |
| 23 | + Amsterdam, Netherlands |
| 24 | + |
| 25 | + Barcelona, Spain |
| 26 | + |
| 27 | + London, United Kingdom |
| 28 | + |
| 29 | + Milan, Italy |
| 30 | + |
| 31 | + Paris, France |
| 32 | + |
| 33 | + Vienna, Austria |
| 34 | + |
| 35 | + ```python |
| 36 | + def replace_address(row): |
| 37 | + if "Netherlands" in row["Hotel_Address"]: |
| 38 | + return "Amsterdam, Netherlands" |
| 39 | + elif "Barcelona" in row["Hotel_Address"]: |
| 40 | + return "Barcelona, Spain" |
| 41 | + elif "United Kingdom" in row["Hotel_Address"]: |
| 42 | + return "London, United Kingdom" |
| 43 | + elif "Milan" in row["Hotel_Address"]: |
| 44 | + return "Milan, Italy" |
| 45 | + elif "France" in row["Hotel_Address"]: |
| 46 | + return "Paris, France" |
| 47 | + elif "Vienna" in row["Hotel_Address"]: |
| 48 | + return "Vienna, Austria" |
| 49 | + |
| 50 | + # Replace all the addresses with a shortened, more useful form |
| 51 | + df["Hotel_Address"] = df.apply(replace_address, axis = 1) |
| 52 | + # The sum of the value_counts() should add up to the total number of reviews |
| 53 | + print(df["Hotel_Address"].value_counts()) |
| 54 | + ``` |
| 55 | + |
| 56 | + 지금부터 국가 레벨 데이터로 쿼리할 수 있습니다: |
| 57 | + |
| 58 | + ```python |
| 59 | + display(df.groupby("Hotel_Address").agg({"Hotel_Name": "nunique"})) |
| 60 | + ``` |
| 61 | + |
| 62 | + | Hotel_Address | Hotel_Name | |
| 63 | + | :--------------------- | :--------: | |
| 64 | + | Amsterdam, Netherlands | 105 | |
| 65 | + | Barcelona, Spain | 211 | |
| 66 | + | London, United Kingdom | 400 | |
| 67 | + | Milan, Italy | 162 | |
| 68 | + | Paris, France | 458 | |
| 69 | + | Vienna, Austria | 158 | |
| 70 | + |
| 71 | +2. 호텔 Meta-review 열을 처리합니다 |
| 72 | + |
| 73 | + 1. `Additional_Number_of_Scoring`을 드랍합니다 |
| 74 | + |
| 75 | + 1. `Total_Number_of_Reviews`를 데이터셋에 실제로 있는 총 호텔 리뷰로 치환합니다 |
| 76 | + |
| 77 | + 1. `Average_Score`를 계산해둔 점수로 치환합니다 |
| 78 | + |
| 79 | + ```python |
| 80 | + # Drop `Additional_Number_of_Scoring` |
| 81 | + df.drop(["Additional_Number_of_Scoring"], axis = 1, inplace=True) |
| 82 | + # Replace `Total_Number_of_Reviews` and `Average_Score` with our own calculated values |
| 83 | + df.Total_Number_of_Reviews = df.groupby('Hotel_Name').transform('count') |
| 84 | + df.Average_Score = round(df.groupby('Hotel_Name').Reviewer_Score.transform('mean'), 1) |
| 85 | + ``` |
| 86 | + |
| 87 | +3. 리뷰 열을 처리합니다 |
| 88 | + |
| 89 | + 1. `Review_Total_Negative_Word_Counts`, `Review_Total_Positive_Word_Counts`, `Review_Date` 그리고 `days_since_review`를 드랍합니다 |
| 90 | + |
| 91 | + 2. `Reviewer_Score`, `Negative_Review`, 그리고 `Positive_Review` 를 두고, |
| 92 | + |
| 93 | + 3. 당장 `Tags` 도 둡니다 |
| 94 | + |
| 95 | + - 다음 섹션에서 태그에 추가적인 필터링 작업을 조금 진행하고 태그를 드랍하게 됩니다 |
| 96 | + |
| 97 | +4. 리뷰어 열을 처리합니다 |
| 98 | + |
| 99 | + 1. `Total_Number_of_Reviews_Reviewer_Has_Given`을 드랍합니다 |
| 100 | + |
| 101 | + 2. `Reviewer_Nationality`를 둡니다 |
| 102 | + |
| 103 | +### Tag 열 |
| 104 | + |
| 105 | +`Tag`열은 열에 저장된 (텍스트 폼의) 리스트라서 문제가 됩니다. 불행하게 순서와 열의 서브 섹션의 숫자는 항상 같지 않습니다. 515,000 행과 1427개 호텔이고, 각자 리뷰어가 선택할 수 있는 옵션은 조금씩 다르기 때문에, 사람에게 흥미로운 알맞은 문구를 가리기 힘듭니다. NLP가 빛나는 영역입니다. 텍스트를 스캔하고 가장 일반적인 문구를 찾으며, 셀 수 있습니다. |
| 106 | + |
| 107 | +불행히도, 단일 단어는 아니지만, multi-word 구문은 (예시. *Business trip*) 흥미롭습니다. 많은 데이터에 (6762646 단어) multi-word frequency distribution 알고리즘을 실행하는 것은 특별히 오래 걸릴 수 있지만, 데이터를 보지 않아도, 필요한 비용으로 보일 것입니다. `[' Business trip ', ' Solo traveler ', ' Single Room ', ' Stayed 5 nights ', ' Submitted from a mobile device ']` 처럼 태그 샘플로 보면, 해야 하는 처리로 많이 줄일 수 있는지 물어볼 수 있기 때문에, 탐색적 데이터 분석은 유용합니다. 운이 좋게도, - 그러나 먼저 관심있는 태그를 확실히 하고자 다음 몇 단계가 필요합니다. |
| 108 | + |
| 109 | +### tags 필터링 |
| 110 | + |
| 111 | +데이터셋의 목표는 좋은 호텔을 선택할 때 (호텔 추천 봇을 만들어 달라고 맡기는 클라이언트일 수 있습니다) 도움을 받고자 감정과 열을 추가하는 것이라고 되새깁니다. 태그가 최종 데이터셋에서 유용한지 스스로에게 물어볼 필요가 있습니다. 한 가지 해석이 있습니다 (만약 다른 사유로 데이터셋이 필요한 경우에 선택할 수 있거나 안하기도 합니다): |
| 112 | + |
| 113 | +1. 여행 타입이 적절하고, 유지되어야 합니다 |
| 114 | +2. 게스트 그룹 타입은 중요하고, 유지되어야 합니다 |
| 115 | +3. 게스트가 지낸 룸 타입, 스위트, 또는 스튜디오 타입은 관련 없습니다 (모든 호텔은 기본적으로 같은 룸이 존재합니다) |
| 116 | +4. 리뷰를 작성한 디바이스는 관련 없습니다 |
| 117 | +5. 만약 리뷰어가 좋아하는 호텔을 더 오래 지낸다면, 리뷰어가 지낸 숙박 기간과 *관련이 있을* 수 있지만, 확대 해석이며, 아마 관련 없습니다 |
| 118 | + |
| 119 | +요약하면, **2가지 종류 태그를 유지하고 나머지를 제거합니다**. |
| 120 | + |
| 121 | +먼저, 더 좋은 포맷이 될 때까지 태그를 안 세고 싶으므로, square brackets과 quotes를 제거해야 합니다. 여러 방식으로 할 수 있지만, 많은 데이터를 처리하며 오랜 시간이 걸리므로 빠르게 하길 원합니다. 운이 좋게도, pandas는 각 단계를 쉬운 방식으로 할 수 있습니다. |
| 122 | + |
| 123 | +```Python |
| 124 | +# Remove opening and closing brackets |
| 125 | +df.Tags = df.Tags.str.strip("[']") |
| 126 | +# remove all quotes too |
| 127 | +df.Tags = df.Tags.str.replace(" ', '", ",", regex = False) |
| 128 | +``` |
| 129 | + |
| 130 | +각자 태그는 이처럼 이루어집니다: `Business trip, Solo traveler, Single Room, Stayed 5 nights, Submitted from a mobile device`. |
| 131 | + |
| 132 | +다음으로 문제를 찾았습니다. 리뷰, 또는 행에 5개 열이 있고, 일부는 3개이거나, 6개입니다. 데이터셋이 어떻게 만들어졌는가에 따른 결과이며, 고치기 어렵습니다. 각 구문의 빈도 카운트를 얻고 싶지만, 각 리뷰의 순서가 다르므로, 카운트에 벗어날 수 있고, 호텔이 가치가 있는 태그로 할당받지 못할 수 있습니다. |
| 133 | + |
| 134 | +각 태그는 multi-word 지만 쉼표로 구분되어 있기 때문에, 대신 다른 순서로 사용하며 가산점을 받습니다! 간단한 방식은 태그에서 순서와 일치하는 열에 넣은 각 태그로 6개 임시 열을 만드는 것입니다. 6개 열을 하나의 큰 열로 합치고 결과 열에 `value_counts()` 메소드를 실행할 수 있습니다. 출력하면, 2428개 유니크 태그를 보게 됩니다. 여기 작은 샘플이 있습니다: |
| 135 | + |
| 136 | +| Tag | Count | |
| 137 | +| ------------------------------ | ------ | |
| 138 | +| Leisure trip | 417778 | |
| 139 | +| Submitted from a mobile device | 307640 | |
| 140 | +| Couple | 252294 | |
| 141 | +| Stayed 1 night | 193645 | |
| 142 | +| Stayed 2 nights | 133937 | |
| 143 | +| Solo traveler | 108545 | |
| 144 | +| Stayed 3 nights | 95821 | |
| 145 | +| Business trip | 82939 | |
| 146 | +| Group | 65392 | |
| 147 | +| Family with young children | 61015 | |
| 148 | +| Stayed 4 nights | 47817 | |
| 149 | +| Double Room | 35207 | |
| 150 | +| Standard Double Room | 32248 | |
| 151 | +| Superior Double Room | 31393 | |
| 152 | +| Family with older children | 26349 | |
| 153 | +| Deluxe Double Room | 24823 | |
| 154 | +| Double or Twin Room | 22393 | |
| 155 | +| Stayed 5 nights | 20845 | |
| 156 | +| Standard Double or Twin Room | 17483 | |
| 157 | +| Classic Double Room | 16989 | |
| 158 | +| Superior Double or Twin Room | 13570 | |
| 159 | +| 2 rooms | 12393 | |
| 160 | + |
| 161 | +`Submitted from a mobile device` 같은 일부 일반적인 태그는 사용하지 못해서, phrase occurrence를 카운트하기 전에 지우는 게 똑똑할 수 있지만, 빠르게 작업하려면 그냥 두고 무시할 수 있습니다. |
| 162 | + |
| 163 | +### length of stay 태그 지우기 |
| 164 | + |
| 165 | +이 태그를 지우는 것은 1단계이며, 고려할 태그의 총 개수를 약간 줄이게 됩니다. 데이터셋에서 지우지 말고, 리뷰 데이터셋에 카운트/유지할 값으로 고려할 대상에서 지우게 선택합니다. |
| 166 | + |
| 167 | +| Length of stay | Count | |
| 168 | +| ---------------- | ------ | |
| 169 | +| Stayed 1 night | 193645 | |
| 170 | +| Stayed 2 nights | 133937 | |
| 171 | +| Stayed 3 nights | 95821 | |
| 172 | +| Stayed 4 nights | 47817 | |
| 173 | +| Stayed 5 nights | 20845 | |
| 174 | +| Stayed 6 nights | 9776 | |
| 175 | +| Stayed 7 nights | 7399 | |
| 176 | +| Stayed 8 nights | 2502 | |
| 177 | +| Stayed 9 nights | 1293 | |
| 178 | +| ... | ... | |
| 179 | + |
| 180 | +룸, 스위트, 스튜디오, 아파트 등 매우 다양합니다. 대부분 같은 것을 의미하고 관련 없으므로, 대상에서 지웁니다. |
| 181 | + |
| 182 | +| Type of room | Count | |
| 183 | +| ----------------------------- | ----- | |
| 184 | +| Double Room | 35207 | |
| 185 | +| Standard Double Room | 32248 | |
| 186 | +| Superior Double Room | 31393 | |
| 187 | +| Deluxe Double Room | 24823 | |
| 188 | +| Double or Twin Room | 22393 | |
| 189 | +| Standard Double or Twin Room | 17483 | |
| 190 | +| Classic Double Room | 16989 | |
| 191 | +| Superior Double or Twin Room | 13570 | |
| 192 | + |
| 193 | +최종적으로, (많이 처리할 일이 없기 때문에) 즐겁게, 다음 *유용한* 태그만 남길 예정입니다: |
| 194 | + |
| 195 | +| Tag | Count | |
| 196 | +| --------------------------------------------- | ------ | |
| 197 | +| Leisure trip | 417778 | |
| 198 | +| Couple | 252294 | |
| 199 | +| Solo traveler | 108545 | |
| 200 | +| Business trip | 82939 | |
| 201 | +| Group (combined with Travellers with friends) | 67535 | |
| 202 | +| Family with young children | 61015 | |
| 203 | +| Family with older children | 26349 | |
| 204 | +| With a pet | 1405 | |
| 205 | + |
| 206 | +`Travellers with friends`는 `Group`과 거의 같다고 주장할 수 있어서, 둘을 합치면 공평할 것입니다. 올바른 태그로 식별하기 위한 코드는 [the Tags notebook](../solution/1-notebook.ipynb)에 있습니다. |
| 207 | + |
| 208 | +마지막 단계는 각 태그로 새로운 열을 만드는 것입니다. 그러면, 모든 리뷰 행에서, `Tag` 열이 하나의 새로운 열과 매치되면, 1을 추가하고, 아니면, 0을 추가합니다. 마지막 결과는 비지니스 vs 레저, 또는 애완동물 동반 언급하면서, 호텔 추천할 때 유용한 정보이므로, 얼마나 많은 리뷰어가 (총계) 호텔을 선택했는지 카운트합니다. |
| 209 | + |
| 210 | +```python |
| 211 | +# Process the Tags into new columns |
| 212 | +# The file Hotel_Reviews_Tags.py, identifies the most important tags |
| 213 | +# Leisure trip, Couple, Solo traveler, Business trip, Group combined with Travelers with friends, |
| 214 | +# Family with young children, Family with older children, With a pet |
| 215 | +df["Leisure_trip"] = df.Tags.apply(lambda tag: 1 if "Leisure trip" in tag else 0) |
| 216 | +df["Couple"] = df.Tags.apply(lambda tag: 1 if "Couple" in tag else 0) |
| 217 | +df["Solo_traveler"] = df.Tags.apply(lambda tag: 1 if "Solo traveler" in tag else 0) |
| 218 | +df["Business_trip"] = df.Tags.apply(lambda tag: 1 if "Business trip" in tag else 0) |
| 219 | +df["Group"] = df.Tags.apply(lambda tag: 1 if "Group" in tag or "Travelers with friends" in tag else 0) |
| 220 | +df["Family_with_young_children"] = df.Tags.apply(lambda tag: 1 if "Family with young children" in tag else 0) |
| 221 | +df["Family_with_older_children"] = df.Tags.apply(lambda tag: 1 if "Family with older children" in tag else 0) |
| 222 | +df["With_a_pet"] = df.Tags.apply(lambda tag: 1 if "With a pet" in tag else 0) |
| 223 | + |
| 224 | +``` |
| 225 | + |
| 226 | +### 파일 저장하기 |
| 227 | + |
| 228 | +마지막으로, 새로운 이름으로 바로 데이터셋을 저장합니다. |
| 229 | + |
| 230 | +```python |
| 231 | +df.drop(["Review_Total_Negative_Word_Counts", "Review_Total_Positive_Word_Counts", "days_since_review", "Total_Number_of_Reviews_Reviewer_Has_Given"], axis = 1, inplace=True) |
| 232 | + |
| 233 | +# Saving new data file with calculated columns |
| 234 | +print("Saving results to Hotel_Reviews_Filtered.csv") |
| 235 | +df.to_csv(r'../data/Hotel_Reviews_Filtered.csv', index = False) |
| 236 | +``` |
| 237 | + |
| 238 | +## 감정 분석 작업 |
| 239 | + |
| 240 | +마지막 섹션에서, 리뷰 열에 감정 분석을 적용하고 데이터셋에 결과를 저장힙니다. |
| 241 | + |
| 242 | +## 연습: 필터링된 데이터를 불러오고 저장하기 |
| 243 | + |
| 244 | +지금 원본 데이터셋 *말고*, 이전 색션에서 저장했던 필터링된 데이터셋을 불러오고 있습니다. |
| 245 | + |
| 246 | +```python |
| 247 | +import time |
| 248 | +import pandas as pd |
| 249 | +import nltk as nltk |
| 250 | +from nltk.corpus import stopwords |
| 251 | +from nltk.sentiment.vader import SentimentIntensityAnalyzer |
| 252 | +nltk.download('vader_lexicon') |
| 253 | + |
| 254 | +# Load the filtered hotel reviews from CSV |
| 255 | +df = pd.read_csv('../../data/Hotel_Reviews_Filtered.csv') |
| 256 | + |
| 257 | +# You code will be added here |
| 258 | + |
| 259 | + |
| 260 | +# Finally remember to save the hotel reviews with new NLP data added |
| 261 | +print("Saving results to Hotel_Reviews_NLP.csv") |
| 262 | +df.to_csv(r'../data/Hotel_Reviews_NLP.csv', index = False) |
| 263 | +``` |
| 264 | + |
| 265 | +### stop word 제거하기 |
| 266 | + |
| 267 | +만약 긍정적이고 부정적인 리뷰 열에 감정 분석을 하는 경우, 오랜 시간이 걸릴 수 있습니다. 빠른 CPU를 가진 강력한 노트북으로 테스트하면, 사용한 감정 라이브러리에 따라서 12 - 14 분 정도 걸립니다. (상대적)으로 오래 걸려서, 빠르게 할 수 있는지 알아볼 가치가 있습니다. |
| 268 | + |
| 269 | +문장의 감정을 바꾸지 않는 stop word나, 일반적인 영어 단어를 지우는 것은, 첫 단계입니다. 지우게 된다면, 감정 분석이 더 빠르게 되지만, 정확도가 낮아지지 않습니다 (stop word는 감정에 영향없지만, 분석이 느려집니다). |
| 270 | + |
| 271 | +긴 부정적 리뷰는 395 단어로 었지만 , stop word를 지우면, 195 단어만 남습니다. |
| 272 | + |
| 273 | +stop word를 지우는 것은 빨라서, 테스트 디바이스에서 515,000 행이 넘는 2개 리뷰 열에 stop word를 지우면 3.3초 걸립니다. 디바이스의 CPU 속도, 램, SSD 등에 따라 더 오래 걸리거나 빨리 끝날 수 있습니다. 작업이 상대적으로 빨라지고 감정 분석 시간도 향상시킬 수 있다면, 할 가치가 있음을 의미합니다. |
| 274 | + |
| 275 | +```python |
| 276 | +from nltk.corpus import stopwords |
| 277 | + |
| 278 | +# Load the hotel reviews from CSV |
| 279 | +df = pd.read_csv("../../data/Hotel_Reviews_Filtered.csv") |
| 280 | + |
| 281 | +# Remove stop words - can be slow for a lot of text! |
| 282 | +# Ryan Han (ryanxjhan on Kaggle) has a great post measuring performance of different stop words removal approaches |
| 283 | +# https://www.kaggle.com/ryanxjhan/fast-stop-words-removal # using the approach that Ryan recommends |
| 284 | +start = time.time() |
| 285 | +cache = set(stopwords.words("english")) |
| 286 | +def remove_stopwords(review): |
| 287 | + text = " ".join([word for word in review.split() if word not in cache]) |
| 288 | + return text |
| 289 | + |
| 290 | +# Remove the stop words from both columns |
| 291 | +df.Negative_Review = df.Negative_Review.apply(remove_stopwords) |
| 292 | +df.Positive_Review = df.Positive_Review.apply(remove_stopwords) |
| 293 | +``` |
| 294 | + |
| 295 | +### 감정 분석하기 |
| 296 | + |
| 297 | +지금부터 모든 부정적이고 긍정적인 리뷰 열에 대한 감정 분석을 계산하고, 2개 열에 결과를 저장해야 합니다. 감정 테스트는 같은 리뷰로 리뷰어의 점수를 비교할 예정입니다. 예시로, 만약 부정적인 리뷰가 1 (많이 긍정적인 감정) 감정이고 1 긍정적인 리뷰 감정이라고 감정을 내렸지만, 리뷰어가 낮은 점수로 호텔을 리뷰하면, 리뷰 텍스트가 점수와 어느 것도 매치되지 않거나, sentiment analyser가 감정을 똑바로 인식할 수 없습니다. 일부 감정 점수는 다 틀릴 수 있고, 그 이유를 자주 설명할 수 있습니다. 예시로. "Of course I LOVED sleeping in a room with no heating" 리뷰는 극도로 풍자적이고 sentiment analyser는 긍정적인 감정이라고 생각하지만, 사람이 읽으면 풍자라는 것을 알 수 있습니다. |
| 298 | + |
| 299 | +NLTK는 학습하는 다양한 sentiment analyzer를 제공하고, 이를 대신헤서 감정이 얼마나 정확한지 볼 수 있습니다. VADER sentiment analysis를 여기에서 사용했습니다. |
| 300 | + |
| 301 | +> Hutto, C.J. & Gilbert, E.E. (2014). VADER: A Parsimonious Rule-based Model for Sentiment Analysis of Social Media Text. Eighth International Conference on Weblogs and Social Media (ICWSM-14). Ann Arbor, MI, June 2014. |
| 302 | +
|
| 303 | +```python |
| 304 | +from nltk.sentiment.vader import SentimentIntensityAnalyzer |
| 305 | + |
| 306 | +# Create the vader sentiment analyser (there are others in NLTK you can try too) |
| 307 | +vader_sentiment = SentimentIntensityAnalyzer() |
| 308 | +# Hutto, C.J. & Gilbert, E.E. (2014). VADER: A Parsimonious Rule-based Model for Sentiment Analysis of Social Media Text. Eighth International Conference on Weblogs and Social Media (ICWSM-14). Ann Arbor, MI, June 2014. |
| 309 | + |
| 310 | +# There are 3 possibilities of input for a review: |
| 311 | +# It could be "No Negative", in which case, return 0 |
| 312 | +# It could be "No Positive", in which case, return 0 |
| 313 | +# It could be a review, in which case calculate the sentiment |
| 314 | +def calc_sentiment(review): |
| 315 | + if review == "No Negative" or review == "No Positive": |
| 316 | + return 0 |
| 317 | + return vader_sentiment.polarity_scores(review)["compound"] |
| 318 | +``` |
| 319 | + |
| 320 | +이후에 프로그램에서 감정을 계산하려 준비할 때, 다음 각 리뷰에서 적용할 수 있습니다: |
| 321 | + |
| 322 | +```python |
| 323 | +# Add a negative sentiment and positive sentiment column |
| 324 | +print("Calculating sentiment columns for both positive and negative reviews") |
| 325 | +start = time.time() |
| 326 | +df["Negative_Sentiment"] = df.Negative_Review.apply(calc_sentiment) |
| 327 | +df["Positive_Sentiment"] = df.Positive_Review.apply(calc_sentiment) |
| 328 | +end = time.time() |
| 329 | +print("Calculating sentiment took " + str(round(end - start, 2)) + " seconds") |
| 330 | +``` |
| 331 | + |
| 332 | +이 컴퓨터에서 120초 정도 걸리지만, 각자 컴퓨터마다 다릅니다. 만약 결과를 출력하고 감정이 리뷰와 매치되는지 보려면 아래와 같이 진행합니다: |
| 333 | + |
| 334 | +```python |
| 335 | +df = df.sort_values(by=["Negative_Sentiment"], ascending=True) |
| 336 | +print(df[["Negative_Review", "Negative_Sentiment"]]) |
| 337 | +df = df.sort_values(by=["Positive_Sentiment"], ascending=True) |
| 338 | +print(df[["Positive_Review", "Positive_Sentiment"]]) |
| 339 | +``` |
| 340 | + |
| 341 | +마지막으로 할 일은 도전에서 사용하기 전, 파일을 저장하는 것입니다! 쉽게 작업하도록 모든 새로운 열로 다시 정렬을 (사람인 경우, 외형 변경) 고려해야 합니다. |
| 342 | + |
| 343 | +```python |
| 344 | +# Reorder the columns (This is cosmetic, but to make it easier to explore the data later) |
| 345 | +df = df.reindex(["Hotel_Name", "Hotel_Address", "Total_Number_of_Reviews", "Average_Score", "Reviewer_Score", "Negative_Sentiment", "Positive_Sentiment", "Reviewer_Nationality", "Leisure_trip", "Couple", "Solo_traveler", "Business_trip", "Group", "Family_with_young_children", "Family_with_older_children", "With_a_pet", "Negative_Review", "Positive_Review"], axis=1) |
| 346 | + |
| 347 | +print("Saving results to Hotel_Reviews_NLP.csv") |
| 348 | +df.to_csv(r"../data/Hotel_Reviews_NLP.csv", index = False) |
| 349 | +``` |
| 350 | + |
| 351 | +(Hotel_Reviews_Filtered.csv 파일 만들어서 [your filtering notebook](solution/notebook-filtering.ipynb) 실행한 후에) [the analysis notebook](solution/notebook-sentiment-analysis.ipynb)으로 전체 코드를 실행해야 합니다. |
| 352 | + |
| 353 | +검토하는, 단계는 이렇습니다: |
| 354 | + |
| 355 | +1. 원본 데이터셋 **Hotel_Reviews.csv** 파일은 이전 강의에서 [the explorer notebook](../../4-Hotel-Reviews-1/solution/notebook-explorer.ipynb)으로 살펴보았습니다 |
| 356 | +2. Hotel_Reviews.csv는 [the filtering notebook](../solution/notebook-filtering.ipynb)에서 필터링되고 **Hotel_Reviews_Filtered.csv**에 결과로 남습니다 |
| 357 | +3. Hotel_Reviews_Filtered.csv는 [the sentiment analysis notebook](../solution/notebook-sentiment-analysis.ipynb)에서 처리되어 **Hotel_Reviews_NLP.csv**에 결과로 남습니다 |
| 358 | +4. 다음 NLP 도전에서 Hotel_Reviews_NLP.csv를 사용합니다 |
| 359 | + |
| 360 | +### 결론 |
| 361 | + |
| 362 | +시작했을 때, 열과 데이터로 이루어진 데이터셋이 었었지만 모두 다 확인되거나 사용되지 않았습니다. 데이터를 살펴보았으며, 필요없는 것은 필터링해서 지웠고, 유용하게 태그를 변환했고, 평균을 계산했으며, 일부 감정 열을 추가하고 기대하면서, 자연어 처리에 대한 일부 흥미로운 사실을 학습했습니다. |
| 363 | + |
| 364 | +## [강의 후 퀴즈](https://jolly-sea-0a877260f.azurestaticapps.net/quiz/40/) |
| 365 | + |
| 366 | +## 도전 |
| 367 | + |
| 368 | +이제부터 감정을 분석해둔 데이터셋을 가지고 있으므로, 이 커리큘럼 (clustering, perhaps?)에서 배웠던 전략으로 감정 주변 패턴을 결정해봅니다. |
| 369 | + |
| 370 | +## 검토 & 자기주도 학습 |
| 371 | + |
| 372 | +[this Learn module](https://docs.microsoft.com/en-us/learn/modules/classify-user-feedback-with-the-text-analytics-api/?WT.mc_id=academic-15963-cxa)로 더 배우고 다른 도구도 사용해서 텍스트에서 감정을 찾습니다. |
| 373 | + |
| 374 | +## 과제 |
| 375 | + |
| 376 | +[Try a different dataset](../assignment.md) |
0 commit comments