You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ML-For-Beginners/translations/ko/6-NLP/4-Hotel-Reviews-1
leestott aa4b119744
🌐 Update translations via Co-op Translator
3 weeks ago
..
solution 🌐 Update translations via Co-op Translator 3 weeks ago
README.md 🌐 Update translations via Co-op Translator 3 weeks ago
assignment.md 🌐 Update translations via Co-op Translator 3 weeks ago
notebook.ipynb 🌐 Update translations via Co-op Translator 3 weeks ago

README.md

호텔 리뷰를 활용한 감정 분석 - 데이터 처리

이 섹션에서는 이전 강의에서 배운 기술을 활용하여 대규모 데이터셋에 대한 탐색적 데이터 분석을 수행합니다. 다양한 열의 유용성을 충분히 이해한 후, 다음을 배우게 됩니다:

  • 불필요한 열 제거 방법
  • 기존 열을 기반으로 새로운 데이터를 계산하는 방법
  • 최종 과제에서 사용할 결과 데이터셋 저장 방법

강의 전 퀴즈

소개

지금까지 텍스트 데이터가 숫자형 데이터와는 매우 다르다는 것을 배웠습니다. 사람이 작성하거나 말한 텍스트는 패턴, 빈도, 감정 및 의미를 분석할 수 있습니다. 이번 강의에서는 실제 데이터셋과 실제 과제를 다룹니다: 유럽의 515K 호텔 리뷰 데이터. 이 데이터는 CC0: 퍼블릭 도메인 라이선스를 포함하며, Booking.com에서 공개 소스를 통해 수집되었습니다. 데이터셋의 제작자는 Jiashen Liu입니다.

준비

필요한 사항:

탐색적 데이터 분석

이 과제는 감정 분석과 고객 리뷰 점수를 활용하여 호텔 추천 봇을 구축하는 것을 목표로 합니다. 사용하게 될 데이터셋은 6개 도시의 1493개 호텔에 대한 리뷰를 포함하고 있습니다.

Python, 호텔 리뷰 데이터셋, 그리고 NLTK의 감정 분석을 사용하여 다음을 알아낼 수 있습니다:

  • 리뷰에서 가장 자주 사용되는 단어와 구는 무엇인가요?
  • 호텔을 설명하는 공식 태그가 리뷰 점수와 상관관계가 있나요? (예: 특정 호텔에 대해 어린 자녀를 동반한 가족혼자 여행하는 사람보다 더 부정적인 리뷰를 남겼다면, 이 호텔이 혼자 여행하는 사람에게 더 적합하다는 것을 나타낼 수 있을까요?)
  • NLTK 감정 점수가 호텔 리뷰어의 숫자 점수와 '일치'하나요?

데이터셋

다운로드한 데이터셋을 로컬에 저장한 후 탐색해 봅시다. VS Code나 Excel 같은 편집기에서 파일을 열어보세요.

데이터셋의 헤더는 다음과 같습니다:

Hotel_Address, Additional_Number_of_Scoring, Review_Date, Average_Score, Hotel_Name, Reviewer_Nationality, Negative_Review, Review_Total_Negative_Word_Counts, Total_Number_of_Reviews, Positive_Review, Review_Total_Positive_Word_Counts, Total_Number_of_Reviews_Reviewer_Has_Given, Reviewer_Score, Tags, days_since_review, lat, lng

다음과 같이 그룹화하면 더 쉽게 살펴볼 수 있습니다:

호텔 관련 열
  • Hotel_Name, Hotel_Address, lat (위도), lng (경도)
    • latlng를 사용하여 Python으로 호텔 위치를 표시하는 지도를 그릴 수 있습니다 (부정적 및 긍정적 리뷰에 따라 색상을 구분할 수도 있음)
    • Hotel_Address는 명확히 유용하지 않으므로, 더 쉽게 정렬 및 검색할 수 있도록 국가로 대체할 가능성이 있습니다.

호텔 메타 리뷰 열

  • Average_Score

    • 데이터셋 제작자에 따르면, 이 열은 지난 1년 동안의 최신 댓글을 기반으로 계산된 호텔의 평균 점수를 나타냅니다. 이는 다소 특이한 계산 방식이지만, 현재로서는 데이터를 그대로 받아들여야 할 것 같습니다.

    이 데이터의 다른 열을 기반으로 평균 점수를 계산할 다른 방법을 생각할 수 있나요?

  • Total_Number_of_Reviews

    • 이 호텔이 받은 총 리뷰 수 - 데이터셋의 리뷰를 참조하는지 여부는 코드 작성 없이 명확하지 않습니다.
  • Additional_Number_of_Scoring

    • 리뷰어가 긍정적 또는 부정적 리뷰를 작성하지 않고 점수만 남긴 경우를 의미합니다.

리뷰 관련 열

  • Reviewer_Score
    • 소수점 한 자리까지 표시되는 숫자 값으로, 최소값 2.5에서 최대값 10 사이입니다.
    • 왜 2.5가 가능한 최저 점수인지 설명되어 있지 않습니다.
  • Negative_Review
    • 리뷰어가 아무것도 작성하지 않은 경우, 이 필드는 "No Negative"로 표시됩니다.
    • 리뷰어가 부정적 리뷰 열에 긍정적 리뷰를 작성할 수도 있습니다 (예: "이 호텔에 나쁜 점은 없습니다").
  • Review_Total_Negative_Word_Counts
    • 부정적 단어 수가 많을수록 점수가 낮아집니다 (감정 분석을 확인하지 않은 경우).
  • Positive_Review
    • 리뷰어가 아무것도 작성하지 않은 경우, 이 필드는 "No Positive"로 표시됩니다.
    • 리뷰어가 긍정적 리뷰 열에 부정적 리뷰를 작성할 수도 있습니다 (예: "이 호텔에는 좋은 점이 전혀 없습니다").
  • Review_Total_Positive_Word_Counts
    • 긍정적 단어 수가 많을수록 점수가 높아집니다 (감정 분석을 확인하지 않은 경우).
  • Review_Datedays_since_review
    • 리뷰의 신선도 또는 오래됨을 측정할 수 있습니다 (오래된 리뷰는 호텔 관리 변경, 리노베이션, 수영장 추가 등으로 인해 최신 리뷰만큼 정확하지 않을 수 있음).
  • Tags
    • 리뷰어가 선택할 수 있는 짧은 설명으로, 게스트 유형 (예: 혼자 또는 가족), 객실 유형, 숙박 기간, 리뷰 제출 방법 등을 나타냅니다.
    • 불행히도, 이러한 태그를 사용하는 데는 문제가 있습니다. 아래 섹션에서 유용성에 대해 논의합니다.

리뷰어 관련 열

  • Total_Number_of_Reviews_Reviewer_Has_Given
    • 예를 들어, 수백 개의 리뷰를 작성한 리뷰어가 긍정적 리뷰보다 부정적 리뷰를 남길 가능성이 더 높다는 것을 알 수 있다면, 추천 모델에서 이 요소를 고려할 수 있습니다. 그러나 특정 리뷰의 리뷰어는 고유 코드로 식별되지 않으므로 리뷰 세트와 연결할 수 없습니다. 100개 이상의 리뷰를 작성한 리뷰어는 30명 있지만, 추천 모델에 어떻게 도움이 될지 판단하기 어렵습니다.
  • Reviewer_Nationality
    • 일부 사람들은 특정 국적이 긍정적 또는 부정적 리뷰를 남길 가능성이 더 높다고 생각할 수 있습니다. 하지만 이러한 견해를 모델에 포함할 때 주의해야 합니다. 이는 국가적 (때로는 인종적) 고정관념이며, 각 리뷰어는 자신의 경험을 바탕으로 리뷰를 작성한 개인입니다. 이전 호텔 숙박 경험, 여행 거리, 개인 성격 등 여러 관점에서 필터링되었을 수 있습니다. 리뷰 점수가 국적 때문이라고 생각하는 것은 정당화하기 어렵습니다.
예시
Average Score Total Number Reviews Reviewer Score Negative
Review
Positive Review Tags
7.8 1945 2.5 현재 이곳은 호텔이 아니라 공사 현장입니다. 긴 여행 후 휴식을 취하며 방에서 작업하는 동안 아침 일찍부터 하루 종일 용납할 수 없는 공사 소음에 시달렸습니다. 인접한 방에서 사람들이 하루 종일 작업했습니다. 즉, 잭해머를 사용했습니다. 방 변경을 요청했지만 조용한 방은 없었습니다. 상황을 더 악화시킨 것은 과도한 요금이 부과된 것입니다. 이른 아침 비행기로 떠나야 했기 때문에 저녁에 체크아웃했고 적절한 청구서를 받았습니다. 하루 후 호텔은 예약 가격을 초과하여 제 동의 없이 추가 요금을 부과했습니다. 끔찍한 곳입니다. 여기 예약하지 마세요. 아무것도 없음 끔찍한 곳 멀리하세요 비즈니스 여행 커플 스탠다드 더블룸 2박 숙박

보시다시피, 이 손님은 호텔에서 행복한 숙박을 하지 못했습니다. 호텔은 7.8의 좋은 평균 점수와 1945개의 리뷰를 가지고 있지만, 이 리뷰어는 2.5를 주고 숙박의 부정적인 점에 대해 115단어를 작성했습니다. 긍정적 리뷰 열에 아무것도 작성하지 않았다면 긍정적인 점이 없다고 추측할 수 있지만, 경고의 7단어를 작성했습니다. 단어 수만 계산하고 단어의 의미나 감정을 고려하지 않으면 리뷰어의 의도를 왜곡할 수 있습니다. 이상하게도, 2.5라는 점수는 혼란스럽습니다. 호텔 숙박이 그렇게 나빴다면 왜 점수를 주었을까요? 데이터셋을 자세히 조사하면 가능한 최저 점수가 2.5이고 0이 아님을 알 수 있습니다. 가능한 최고 점수는 10입니다.

태그

위에서 언급했듯이, 처음에는 Tags를 사용하여 데이터를 분류하는 아이디어가 합리적으로 보입니다. 그러나 이 태그는 표준화되어 있지 않아, 특정 호텔에서는 싱글룸, 트윈룸, 더블룸 옵션이 있을 수 있지만, 다른 호텔에서는 디럭스 싱글룸, 클래식 퀸룸, 이그제큐티브 킹룸 옵션이 있을 수 있습니다. 이것들이 동일한 것일 수도 있지만, 변형이 너무 많아 선택지가 다음과 같이 됩니다:

  1. 모든 용어를 단일 표준으로 변경하려고 시도하지만, 각 경우에 변환 경로가 명확하지 않아 매우 어렵습니다 (예: 클래식 싱글룸싱글룸으로 매핑되지만 정원 또는 도시 전망이 있는 슈페리어 퀸룸은 매핑하기 훨씬 어렵습니다).

  2. NLP 접근 방식을 사용하여 혼자, 비즈니스 여행객, 어린 자녀를 동반한 가족과 같은 특정 용어의 빈도를 측정하고 이를 추천에 반영합니다.

태그는 일반적으로 (항상 그런 것은 아니지만) 여행 유형, 게스트 유형, 객실 유형, 숙박 기간, 리뷰 제출 장치 유형에 맞춰 5~6개의 쉼표로 구분된 값을 포함하는 단일 필드입니다. 그러나 일부 리뷰어가 각 필드를 채우지 않는 경우 (하나를 비워둘 수 있음), 값이 항상 동일한 순서로 나타나지는 않습니다.

예를 들어, 그룹 유형을 살펴보면, Tags 열에서 이 필드에 1025개의 고유 가능성이 있으며, 불행히도 그중 일부만 그룹을 참조합니다 (일부는 객실 유형 등입니다). 가족을 언급하는 태그만 필터링하면 결과에 많은 가족룸 유형 결과가 포함됩니다. with라는 용어를 포함하여 가족과 함께 값을 계산하면 결과가 더 좋아지며, "어린 자녀를 동반한 가족" 또는 "나이 든 자녀를 동반한 가족"이라는 문구가 포함된 515,000개의 결과 중 80,000개 이상을 얻을 수 있습니다.

따라서 태그 열이 완전히 쓸모없는 것은 아니지만, 유용하게 만들기 위해 약간의 작업이 필요합니다.

호텔 평균 점수

데이터셋과 관련하여 몇 가지 이상하거나 불일치한 점이 있지만, 이를 명확히 하기 위해 여기서 설명합니다. 모델을 구축할 때 이를 인지하고 해결 방법을 찾으면 토론 섹션에서 알려주세요!

데이터셋에는 평균 점수와 리뷰 수와 관련된 다음 열이 포함되어 있습니다:

  1. Hotel_Name
  2. Additional_Number_of_Scoring
  3. Average_Score
  4. Total_Number_of_Reviews
  5. Reviewer_Score

이 데이터셋에서 가장 많은 리뷰를 가진 호텔은 Britannia International Hotel Canary Wharf로, 515,000개 중 4789개의 리뷰를 가지고 있습니다. 그러나 이 호텔의 Total_Number_of_Reviews 값은 9086입니다. 많은 점수가 리뷰 없이 존재한다고 추측할 수 있으므로 Additional_Number_of_Scoring 열 값을 추가해야 할 것 같습니다. 해당 값은 2682이며, 이를 4789에 더하면 7471이 되지만 여전히 Total_Number_of_Reviews 값보다 1615 부족합니다.

Average_Score 열을 보면 데이터셋의 리뷰 평균이라고 추측할 수 있지만, Kaggle 설명에 따르면 "지난 1년 동안의 최신 댓글을 기반으로 계산된 호텔의 평균 점수"라고 합니다. 이는 그다지 유용하지 않아 보이지만, 데이터셋의 리뷰 점수를 기반으로 자체 평균을 계산할 수 있습니다. 동일한 호텔을 예로 들면, 호텔의 평균 점수는 7.1로 제공되지만 데이터셋 내 리뷰어 점수의 계산 평균은 6.8입니다. 이는 근접하지만 동일한 값은 아니며, Additional_Number_of_Scoring 리뷰에서 제공된 점수가 평균을 7.1로 증가시켰다고 추측할 수 있습니다. 그러나 이를 테스트하거나 증명할 방법이 없으므로 Average_Score, Additional_Number_of_Scoring, Total_Number_of_Reviews를 사용할 수 없거나 신뢰하기 어렵습니다.

더 복잡한 점은 리뷰 수가 두 번째로 많은 호텔의 계산 평균 점수가 8.12이고 데이터셋의 Average_Score는 8.1이라는 점입니다. 첫 번째 호텔이 불일치인지, 두 번째 호텔이 올바른 점수인지 우연인지 알 수 없습니다.

이 호텔이 이상치일 가능성이 있으며, 대부분의 값이 일치하지만 일부는 어떤 이유로 일치하지 않을 수 있다고 가정하고, 데이터셋의 값을 탐색하고 올바른 사용법 (또는 사용하지 않는 방법)을 결정하기 위해 다음에 짧은 프로그램을 작성할 것입니다.

🚨 주의 사항

이 데이터셋을 다룰 때, 텍스트를 직접 읽거나 분석하지 않고 텍스트에서 무언가를 계산하는 코드를 작성하게 됩니다. 이것이 바로 NLP의 본질로, 인간이 직접 하지 않아도 의미나 감정을 해석하는 것입니다. 하지만 부정적인 리뷰를 읽게 될 가능성도 있습니다. 저는 여러분이 이를 읽지 않기를 권합니다. 왜냐하면 그럴 필요가 없기 때문입니다. 일부 리뷰는 터무니없거나 관련성이 없는 부정적인 호텔 리뷰일 수 있습니다. 예를 들어, "날씨가 좋지 않았다"는 호텔이나 누구도 통제할 수 없는 문제입니다. 하지만 리뷰에는 어두운 면도 존재합니다. 때로는 부정적인 리뷰가 인종차별적, 성차별적, 혹은 연령차별적일 수 있습니다. 이는 공공 웹사이트에서 수집된 데이터셋에서 예상할 수 있는 불행한 현실입니다. 일부 리뷰어는 불쾌하거나 불편하며 마음을 상하게 할 수 있는 리뷰를 남기기도 합니다. 리뷰를 직접 읽고 마음이 상하기보다는 코드가 감정을 측정하도록 하는 것이 더 나을 것입니다. 그렇다고 해서 이런 리뷰를 작성하는 사람이 다수는 아니지만, 소수라도 존재한다는 사실은 변하지 않습니다.

연습 - 데이터 탐색

데이터 불러오기

이제 데이터를 시각적으로 살펴보는 것은 충분하니, 코드를 작성하여 답을 찾아봅시다! 이 섹션에서는 pandas 라이브러리를 사용합니다. 첫 번째 과제는 CSV 데이터를 불러오고 읽을 수 있는지 확인하는 것입니다. pandas 라이브러리는 빠른 CSV 로더를 제공하며, 결과는 이전 강의에서처럼 데이터프레임에 저장됩니다. 우리가 불러올 CSV 파일은 50만 개 이상의 행과 17개의 열로 구성되어 있습니다. pandas는 데이터프레임과 상호작용할 수 있는 강력한 기능을 많이 제공하며, 각 행에 대해 연산을 수행할 수도 있습니다.

이제부터 이 강의에서는 코드 스니펫과 코드 설명, 그리고 결과에 대한 논의가 포함될 것입니다. 제공된 notebook.ipynb 파일을 사용하여 코드를 작성하세요.

우선 사용할 데이터 파일을 불러오는 것부터 시작해봅시다:

# Load the hotel reviews from CSV
import pandas as pd
import time
# importing time so the start and end time can be used to calculate file loading time
print("Loading data file now, this could take a while depending on file size")
start = time.time()
# df is 'DataFrame' - make sure you downloaded the file to the data folder
df = pd.read_csv('../../data/Hotel_Reviews.csv')
end = time.time()
print("Loading took " + str(round(end - start, 2)) + " seconds")

데이터를 불러왔으니, 이제 몇 가지 연산을 수행할 수 있습니다. 이 코드를 프로그램 상단에 유지하면서 다음 단계를 진행하세요.

데이터 탐색

이번 경우, 데이터는 이미 정리(clean) 되어 있습니다. 즉, 작업할 준비가 되어 있으며, 영어 문자만을 기대하는 알고리즘을 방해할 수 있는 다른 언어의 문자가 포함되어 있지 않습니다.

데이터를 처리하기 전에 형식을 맞추는 초기 처리가 필요한 경우도 있지만, 이번에는 그렇지 않습니다. 만약 비영어 문자를 처리해야 한다면, 어떻게 처리할지 생각해보세요.

데이터를 불러온 후, 코드를 사용하여 데이터를 탐색할 수 있는지 확인하세요. Negative_ReviewPositive_Review 열에 초점을 맞추고 싶을 수 있습니다. 이 열들은 NLP 알고리즘이 처리할 자연어 텍스트로 채워져 있습니다. 하지만 잠깐! NLP와 감정 분석에 뛰어들기 전에, 아래 코드를 따라 데이터셋에 주어진 값이 pandas로 계산한 값과 일치하는지 확인하세요.

데이터프레임 연산

이번 강의의 첫 번째 과제는 데이터프레임을 변경하지 않고 데이터를 확인하는 코드를 작성하여 다음 주장이 맞는지 확인하는 것입니다.

많은 프로그래밍 작업과 마찬가지로, 여러 가지 방법으로 작업을 완료할 수 있습니다. 하지만 가장 간단하고 쉬운 방법으로 작업하는 것이 좋습니다. 특히 나중에 이 코드를 다시 볼 때 이해하기 쉬운 방법이라면 더욱 그렇습니다. 데이터프레임의 경우, 종합적인 API가 제공되므로 원하는 작업을 효율적으로 수행할 방법이 있을 가능성이 높습니다.

다음 질문들을 코딩 과제로 간주하고, 솔루션을 보기 전에 스스로 답을 찾아보세요.

  1. 방금 불러온 데이터프레임의 shape (행과 열의 수)을 출력하세요.
  2. 리뷰어 국적에 대한 빈도수를 계산하세요:
    1. Reviewer_Nationality 열에 몇 가지 고유 값이 있는지, 그리고 그 값들이 무엇인지 확인하세요.
    2. 데이터셋에서 가장 흔한 리뷰어 국적은 무엇인지 (국가와 리뷰 수를 출력) 확인하세요.
    3. 다음으로 많이 등장하는 10개의 국적과 그 빈도수를 확인하세요.
  3. 가장 많이 리뷰된 호텔을 각 상위 10개 리뷰어 국적별로 확인하세요.
  4. 데이터셋에서 호텔별 리뷰 수(호텔의 빈도수)를 계산하세요.
  5. 데이터셋에 각 호텔의 Average_Score 열이 있지만, 각 호텔에 대한 모든 리뷰어 점수의 평균을 계산하여 새로운 열 Calc_Average_Score를 추가하세요.
  6. Average_ScoreCalc_Average_Score가 동일한 호텔이 있는지 확인하세요 (소수점 첫째 자리까지 반올림하여 비교).
    1. Series(행)를 인자로 받아 값을 비교하고, 값이 같지 않을 때 메시지를 출력하는 Python 함수를 작성하세요. 그런 다음 .apply() 메서드를 사용하여 모든 행을 처리하세요.
  7. Negative_Review 열 값이 "No Negative"인 행의 수를 계산하고 출력하세요.
  8. Positive_Review 열 값이 "No Positive"인 행의 수를 계산하고 출력하세요.
  9. Positive_Review 열 값이 "No Positive"이고 Negative_Review 열 값이 "No Negative"인 행의 수를 계산하고 출력하세요.

코드 답안

  1. 방금 불러온 데이터프레임의 shape (행과 열의 수)을 출력하세요.

    print("The shape of the data (rows, cols) is " + str(df.shape))
    > The shape of the data (rows, cols) is (515738, 17)
    
  2. 리뷰어 국적에 대한 빈도수를 계산하세요:

    1. Reviewer_Nationality 열에 몇 가지 고유 값이 있는지, 그리고 그 값들이 무엇인지 확인하세요.
    2. 데이터셋에서 가장 흔한 리뷰어 국적은 무엇인지 (국가와 리뷰 수를 출력) 확인하세요.
    # value_counts() creates a Series object that has index and values in this case, the country and the frequency they occur in reviewer nationality
    nationality_freq = df["Reviewer_Nationality"].value_counts()
    print("There are " + str(nationality_freq.size) + " different nationalities")
    # print first and last rows of the Series. Change to nationality_freq.to_string() to print all of the data
    print(nationality_freq) 
    
    There are 227 different nationalities
     United Kingdom               245246
     United States of America      35437
     Australia                     21686
     Ireland                       14827
     United Arab Emirates          10235
                                   ...  
     Comoros                           1
     Palau                             1
     Northern Mariana Islands          1
     Cape Verde                        1
     Guinea                            1
    Name: Reviewer_Nationality, Length: 227, dtype: int64
    
    1. 다음으로 많이 등장하는 10개의 국적과 그 빈도수를 확인하세요.

      print("The highest frequency reviewer nationality is " + str(nationality_freq.index[0]).strip() + " with " + str(nationality_freq[0]) + " reviews.")
      # Notice there is a leading space on the values, strip() removes that for printing
      # What is the top 10 most common nationalities and their frequencies?
      print("The next 10 highest frequency reviewer nationalities are:")
      print(nationality_freq[1:11].to_string())
      
      The highest frequency reviewer nationality is United Kingdom with 245246 reviews.
      The next 10 highest frequency reviewer nationalities are:
       United States of America     35437
       Australia                    21686
       Ireland                      14827
       United Arab Emirates         10235
       Saudi Arabia                  8951
       Netherlands                   8772
       Switzerland                   8678
       Germany                       7941
       Canada                        7894
       France                        7296
      
  3. 가장 많이 리뷰된 호텔을 각 상위 10개 리뷰어 국적별로 확인하세요.

    # What was the most frequently reviewed hotel for the top 10 nationalities
    # Normally with pandas you will avoid an explicit loop, but wanted to show creating a new dataframe using criteria (don't do this with large amounts of data because it could be very slow)
    for nat in nationality_freq[:10].index:
       # First, extract all the rows that match the criteria into a new dataframe
       nat_df = df[df["Reviewer_Nationality"] == nat]   
       # Now get the hotel freq
       freq = nat_df["Hotel_Name"].value_counts()
       print("The most reviewed hotel for " + str(nat).strip() + " was " + str(freq.index[0]) + " with " + str(freq[0]) + " reviews.") 
    
    The most reviewed hotel for United Kingdom was Britannia International Hotel Canary Wharf with 3833 reviews.
    The most reviewed hotel for United States of America was Hotel Esther a with 423 reviews.
    The most reviewed hotel for Australia was Park Plaza Westminster Bridge London with 167 reviews.
    The most reviewed hotel for Ireland was Copthorne Tara Hotel London Kensington with 239 reviews.
    The most reviewed hotel for United Arab Emirates was Millennium Hotel London Knightsbridge with 129 reviews.
    The most reviewed hotel for Saudi Arabia was The Cumberland A Guoman Hotel with 142 reviews.
    The most reviewed hotel for Netherlands was Jaz Amsterdam with 97 reviews.
    The most reviewed hotel for Switzerland was Hotel Da Vinci with 97 reviews.
    The most reviewed hotel for Germany was Hotel Da Vinci with 86 reviews.
    The most reviewed hotel for Canada was St James Court A Taj Hotel London with 61 reviews.
    
  4. 데이터셋에서 호텔별 리뷰 수(호텔의 빈도수)를 계산하세요.

    # First create a new dataframe based on the old one, removing the uneeded columns
    hotel_freq_df = df.drop(["Hotel_Address", "Additional_Number_of_Scoring", "Review_Date", "Average_Score", "Reviewer_Nationality", "Negative_Review", "Review_Total_Negative_Word_Counts", "Positive_Review", "Review_Total_Positive_Word_Counts", "Total_Number_of_Reviews_Reviewer_Has_Given", "Reviewer_Score", "Tags", "days_since_review", "lat", "lng"], axis = 1)
    
    # Group the rows by Hotel_Name, count them and put the result in a new column Total_Reviews_Found
    hotel_freq_df['Total_Reviews_Found'] = hotel_freq_df.groupby('Hotel_Name').transform('count')
    
    # Get rid of all the duplicated rows
    hotel_freq_df = hotel_freq_df.drop_duplicates(subset = ["Hotel_Name"])
    display(hotel_freq_df) 
    
    Hotel_Name Total_Number_of_Reviews Total_Reviews_Found
    Britannia International Hotel Canary Wharf 9086 4789
    Park Plaza Westminster Bridge London 12158 4169
    Copthorne Tara Hotel London Kensington 7105 3578
    ... ... ...
    Mercure Paris Porte d Orleans 110 10
    Hotel Wagner 135 10
    Hotel Gallitzinberg 173 8

    데이터셋에서 계산된 결과와 Total_Number_of_Reviews 값이 일치하지 않는 것을 알 수 있습니다. 이 값이 호텔의 총 리뷰 수를 나타내지만, 모든 리뷰가 스크랩되지 않았거나 다른 계산이 적용된 것일 수 있습니다. 이러한 불확실성 때문에 Total_Number_of_Reviews는 모델에서 사용되지 않습니다.

  5. 데이터셋에 각 호텔의 Average_Score 열이 있지만, 각 호텔에 대한 모든 리뷰어 점수의 평균을 계산하여 새로운 열 Calc_Average_Score를 추가하세요. Hotel_Name, Average_Score, Calc_Average_Score 열을 출력하세요.

    # define a function that takes a row and performs some calculation with it
    def get_difference_review_avg(row):
      return row["Average_Score"] - row["Calc_Average_Score"]
    
    # 'mean' is mathematical word for 'average'
    df['Calc_Average_Score'] = round(df.groupby('Hotel_Name').Reviewer_Score.transform('mean'), 1)
    
    # Add a new column with the difference between the two average scores
    df["Average_Score_Difference"] = df.apply(get_difference_review_avg, axis = 1)
    
    # Create a df without all the duplicates of Hotel_Name (so only 1 row per hotel)
    review_scores_df = df.drop_duplicates(subset = ["Hotel_Name"])
    
    # Sort the dataframe to find the lowest and highest average score difference
    review_scores_df = review_scores_df.sort_values(by=["Average_Score_Difference"])
    
    display(review_scores_df[["Average_Score_Difference", "Average_Score", "Calc_Average_Score", "Hotel_Name"]])
    

    데이터셋 평균과 계산된 평균이 다른 이유가 궁금할 수 있습니다. 일부 값이 일치하지만, 다른 값은 차이가 있는 이유를 알 수 없으므로, 이 경우 우리가 가진 리뷰 점수를 사용하여 평균을 직접 계산하는 것이 가장 안전합니다. 차이가 매우 작기 때문에, 계산된 평균 점수를 사용하는 것이 적절합니다.

  6. Negative_Review 열 값이 "No Negative"인 행의 수를 계산하고 출력하세요.

  7. Positive_Review 열 값이 "No Positive"인 행의 수를 계산하고 출력하세요.

  8. Positive_Review 열 값이 "No Positive"이고 Negative_Review 열 값이 "No Negative"인 행의 수를 계산하고 출력하세요.

    # with lambdas:
    start = time.time()
    no_negative_reviews = df.apply(lambda x: True if x['Negative_Review'] == "No Negative" else False , axis=1)
    print("Number of No Negative reviews: " + str(len(no_negative_reviews[no_negative_reviews == True].index)))
    
    no_positive_reviews = df.apply(lambda x: True if x['Positive_Review'] == "No Positive" else False , axis=1)
    print("Number of No Positive reviews: " + str(len(no_positive_reviews[no_positive_reviews == True].index)))
    
    both_no_reviews = df.apply(lambda x: True if x['Negative_Review'] == "No Negative" and x['Positive_Review'] == "No Positive" else False , axis=1)
    print("Number of both No Negative and No Positive reviews: " + str(len(both_no_reviews[both_no_reviews == True].index)))
    end = time.time()
    print("Lambdas took " + str(round(end - start, 2)) + " seconds")
    
    Number of No Negative reviews: 127890
    Number of No Positive reviews: 35946
    Number of both No Negative and No Positive reviews: 127
    Lambdas took 9.64 seconds
    

또 다른 방법

람다를 사용하지 않고 항목을 세는 또 다른 방법은 sum을 사용하는 것입니다:

# without lambdas (using a mixture of notations to show you can use both)
start = time.time()
no_negative_reviews = sum(df.Negative_Review == "No Negative")
print("Number of No Negative reviews: " + str(no_negative_reviews))

no_positive_reviews = sum(df["Positive_Review"] == "No Positive")
print("Number of No Positive reviews: " + str(no_positive_reviews))

both_no_reviews = sum((df.Negative_Review == "No Negative") & (df.Positive_Review == "No Positive"))
print("Number of both No Negative and No Positive reviews: " + str(both_no_reviews))

end = time.time()
print("Sum took " + str(round(end - start, 2)) + " seconds")

Number of No Negative reviews: 127890
Number of No Positive reviews: 35946
Number of both No Negative and No Positive reviews: 127
Sum took 0.19 seconds

Negative_ReviewPositive_Review 열 값이 각각 "No Negative"와 "No Positive"인 행이 127개 있다는 것을 알 수 있습니다. 이는 리뷰어가 호텔에 점수를 부여했지만, 긍정적이거나 부정적인 리뷰를 작성하지 않았다는 것을 의미합니다. 다행히도 이러한 행은 515,738개 중 127개(0.02%)로 매우 적기 때문에, 모델이나 결과에 큰 영향을 미치지 않을 것입니다. 하지만 리뷰 데이터셋에 리뷰가 없는 행이 포함되어 있다는 점은 예상치 못했을 수 있으므로, 데이터를 탐색하여 이러한 행을 발견하는 것이 중요합니다.

이제 데이터셋을 탐색했으니, 다음 강의에서는 데이터를 필터링하고 감정 분석을 추가할 것입니다.


🚀도전 과제

이번 강의는 이전 강의에서 본 것처럼, 데이터를 이해하고 그 특성을 파악하는 것이 얼마나 중요한지 보여줍니다. 특히 텍스트 기반 데이터는 신중히 검토해야 합니다. 다양한 텍스트 중심 데이터셋을 탐색하며, 모델에 편향이나 왜곡된 감정을 도입할 수 있는 영역을 발견해보세요.

강의 후 퀴즈

복습 및 자기 학습

NLP 학습 경로를 통해 음성 및 텍스트 중심 모델을 구축할 때 사용할 수 있는 도구를 알아보세요.

과제

NLTK


면책 조항:
이 문서는 AI 번역 서비스 Co-op Translator를 사용하여 번역되었습니다. 정확성을 위해 최선을 다하고 있으나, 자동 번역에는 오류나 부정확성이 포함될 수 있습니다. 원본 문서를 해당 언어로 작성된 상태에서 권위 있는 자료로 간주해야 합니다. 중요한 정보의 경우, 전문적인 인간 번역을 권장합니다. 이 번역 사용으로 인해 발생하는 오해나 잘못된 해석에 대해 당사는 책임을 지지 않습니다.