In this project, we will build a recommendation system based on TripAdvisor reviews. Our goal is to implement a BM25 baseline and a custom recommendation model that can outperform BM25 using user reviews only, without access to explicit ratings during the recommendation phase.
!pip install rank_bm25
Requirement already satisfied: rank_bm25 in c:\users\joyce\anaconda3\envs\ml-nlp\lib\site-packages (0.2.2) Requirement already satisfied: numpy in c:\users\joyce\anaconda3\envs\ml-nlp\lib\site-packages (from rank_bm25) (1.26.4)
import pandas as pd # For data management
import json # For manipulating JSON-like formatted strings/documents
import numpy as np # To use "argsort" function
from rank_bm25 import BM25Okapi # For BM25 implementation
from collections import Counter # For counting occurrences of elements, used here for word frequency analysis
import matplotlib.pyplot as plt
from sentence_transformers import SentenceTransformer
# Display progress bar
from tqdm import tqdm
# ==== scikit-learn ====
from sklearn.metrics import root_mean_squared_error, ndcg_score
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
# ==== NLTK for NLP ====
import nltk
# For tokenizing text based on a regular expression pattern
nltk.download('punkt')
from nltk.tokenize import regexp_tokenize
# For accessing stopwords, which are commonly removed from text data
nltk.download('stopwords')
from nltk.corpus import stopwords
stop_words = set(stopwords.words('english'))
# For converting words to their base form (lemmatization)
nltk.download("wordnet") # lemmatizer
from nltk.stem import WordNetLemmatizer
c:\Users\Joyce\anaconda3\envs\ml-nlp\lib\site-packages\sentence_transformers\cross_encoder\CrossEncoder.py:13: TqdmExperimentalWarning: Using `tqdm.autonotebook.tqdm` in notebook mode. Use `tqdm.tqdm` instead to force console mode (e.g. in jupyter console) from tqdm.autonotebook import tqdm, trange [nltk_data] Downloading package punkt to [nltk_data] C:\Users\Joyce\AppData\Roaming\nltk_data... [nltk_data] Package punkt is already up-to-date! [nltk_data] Downloading package stopwords to [nltk_data] C:\Users\Joyce\AppData\Roaming\nltk_data... [nltk_data] Package stopwords is already up-to-date! [nltk_data] Downloading package wordnet to [nltk_data] C:\Users\Joyce\AppData\Roaming\nltk_data... [nltk_data] Package wordnet is already up-to-date!
# PROJECT_PATH = "/content/drive/MyDrive/Ecole/ESILV/A5/Machine Learning for NLP/Project/"
PROJECT_PATH = ""
We will load the TripAdvisor dataset (downloadable from Kaggle), filter it based on specified aspects, and preprocess by concatenating reviews by place (offering_id
).
# Load dataset
df = pd.read_csv(PROJECT_PATH + 'data/reviews.csv')
df.head()
ratings | title | text | author | date_stayed | offering_id | num_helpful_votes | date | id | via_mobile | |
---|---|---|---|---|---|---|---|---|---|---|
0 | {'service': 5.0, 'cleanliness': 5.0, 'overall'... | “Truly is "Jewel of the Upper Wets Side"” | Stayed in a king suite for 11 nights and yes i... | {'username': 'Papa_Panda', 'num_cities': 22, '... | December 2012 | 93338 | 0 | 2012-12-17 | 147643103 | False |
1 | {'service': 5.0, 'cleanliness': 5.0, 'overall'... | “My home away from home!” | On every visit to NYC, the Hotel Beacon is the... | {'username': 'Maureen V', 'num_reviews': 2, 'n... | December 2012 | 93338 | 0 | 2012-12-17 | 147639004 | False |
2 | {'service': 4.0, 'cleanliness': 5.0, 'overall'... | “Great Stay” | This is a great property in Midtown. We two di... | {'username': 'vuguru', 'num_cities': 12, 'num_... | December 2012 | 1762573 | 0 | 2012-12-18 | 147697954 | False |
3 | {'service': 5.0, 'cleanliness': 5.0, 'overall'... | “Modern Convenience” | The Andaz is a nice hotel in a central locatio... | {'username': 'Hotel-Designer', 'num_cities': 5... | August 2012 | 1762573 | 0 | 2012-12-17 | 147625723 | False |
4 | {'service': 4.0, 'cleanliness': 5.0, 'overall'... | “Its the best of the Andaz Brand in the US....” | I have stayed at each of the US Andaz properti... | {'username': 'JamesE339', 'num_cities': 34, 'n... | December 2012 | 1762573 | 0 | 2012-12-17 | 147612823 | False |
df.shape
(878561, 10)
df.dtypes
ratings object title object text object author object date_stayed object offering_id int64 num_helpful_votes int64 date object id int64 via_mobile bool dtype: object
df.isnull().sum()
ratings 0 title 0 text 0 author 0 date_stayed 67594 offering_id 0 num_helpful_votes 0 date 0 id 0 via_mobile 0 dtype: int64
# Filter reviews with specific aspects
required_aspects = ['service', 'cleanliness', 'overall', 'value', 'location', 'sleep_quality', 'rooms']
# Filter rows where all required aspects are in each 'ratings' entry
df = df[df["ratings"].apply(lambda x: all(aspect in x for aspect in required_aspects))]
print(f"New DataFrame's shape: {df.shape}")
df.head()
New DataFrame's shape: (436391, 10)
ratings | title | text | author | date_stayed | offering_id | num_helpful_votes | date | id | via_mobile | |
---|---|---|---|---|---|---|---|---|---|---|
0 | {'service': 5.0, 'cleanliness': 5.0, 'overall'... | “Truly is "Jewel of the Upper Wets Side"” | Stayed in a king suite for 11 nights and yes i... | {'username': 'Papa_Panda', 'num_cities': 22, '... | December 2012 | 93338 | 0 | 2012-12-17 | 147643103 | False |
1 | {'service': 5.0, 'cleanliness': 5.0, 'overall'... | “My home away from home!” | On every visit to NYC, the Hotel Beacon is the... | {'username': 'Maureen V', 'num_reviews': 2, 'n... | December 2012 | 93338 | 0 | 2012-12-17 | 147639004 | False |
2 | {'service': 4.0, 'cleanliness': 5.0, 'overall'... | “Great Stay” | This is a great property in Midtown. We two di... | {'username': 'vuguru', 'num_cities': 12, 'num_... | December 2012 | 1762573 | 0 | 2012-12-18 | 147697954 | False |
3 | {'service': 5.0, 'cleanliness': 5.0, 'overall'... | “Modern Convenience” | The Andaz is a nice hotel in a central locatio... | {'username': 'Hotel-Designer', 'num_cities': 5... | August 2012 | 1762573 | 0 | 2012-12-17 | 147625723 | False |
4 | {'service': 4.0, 'cleanliness': 5.0, 'overall'... | “Its the best of the Andaz Brand in the US....” | I have stayed at each of the US Andaz properti... | {'username': 'JamesE339', 'num_cities': 34, 'n... | December 2012 | 1762573 | 0 | 2012-12-17 | 147612823 | False |
We went from 878,561 rows to 436,391 rows; so about 450k rows didn't contain all the aspects we need to compare all places accurately.
# Function to calculate average rating for each aspect
def get_avg_rating_aspects(ratings_str):
# Convert each string in the list to a dictionary
ratings_dicts = [json.loads(rating.replace("'", "\"")) for rating in ratings_str]
# Get the number of ratings to calculate the average
nb_ratings = len(ratings_dicts)
# Initialize a dictionary to store average ratings per aspect
avg_ratings = {}
# Iterate over each required aspect
for aspect in required_aspects:
# Initialize the sum for the current aspect
aspect_rating_sum = 0
# Sum up the ratings for the current aspect from all dictionaries
for ratings in ratings_dicts:
aspect_rating_sum += ratings[aspect]
# Calculate the average rating for the aspect, rounded to 1 decimal place
avg_ratings[aspect] = round(aspect_rating_sum / nb_ratings, 1)
# Return the dictionary with average ratings for each aspect
return avg_ratings
# Call custom aggregate function on "ratings" column
df_grouped = df.groupby('offering_id').agg({'text': '\n'.join, 'ratings': get_avg_rating_aspects}).reset_index()
# Rename the 'text' column to be more explicit
df_grouped.rename(columns={"text": "reviews"}, inplace=True)
print(f"Grouped DataFrame's shape: {df_grouped.shape}")
df_grouped.head()
Grouped DataFrame's shape: (3754, 3)
offering_id | reviews | ratings | |
---|---|---|---|
0 | 72572 | I had to make fast visit to seattle and I foun... | {'service': 4.6, 'cleanliness': 4.6, 'overall'... |
1 | 72579 | Great service, rooms were clean, could use som... | {'service': 4.2, 'cleanliness': 4.2, 'overall'... |
2 | 72586 | Beautiful views of the space needle - especial... | {'service': 4.2, 'cleanliness': 4.3, 'overall'... |
3 | 72598 | This hotel is in need of some serious updates.... | {'service': 3.2, 'cleanliness': 3.2, 'overall'... |
4 | 73236 | My experience at this days inn was perfect. th... | {'service': 4.3, 'cleanliness': 3.1, 'overall'... |
df
¶This step is merely to make the results more readable for us humans, so that instead of an ID we get an actual place name with some info (e.g., stars).
# Load hotels' information
offerings = pd.read_csv(PROJECT_PATH + "data/offerings.csv")
offerings.head()
hotel_class | region_id | url | phone | details | address | type | id | name | |
---|---|---|---|---|---|---|---|---|---|
0 | 4.0 | 60763 | http://www.tripadvisor.com/Hotel_Review-g60763... | NaN | NaN | {'region': 'NY', 'street-address': '147 West 4... | hotel | 113317 | Casablanca Hotel Times Square |
1 | 5.0 | 32655 | http://www.tripadvisor.com/Hotel_Review-g32655... | NaN | NaN | {'region': 'CA', 'street-address': '300 S Dohe... | hotel | 76049 | Four Seasons Hotel Los Angeles at Beverly Hills |
2 | 3.5 | 60763 | http://www.tripadvisor.com/Hotel_Review-g60763... | NaN | NaN | {'region': 'NY', 'street-address': '790 Eighth... | hotel | 99352 | Hilton Garden Inn Times Square |
3 | 4.0 | 60763 | http://www.tripadvisor.com/Hotel_Review-g60763... | NaN | NaN | {'region': 'NY', 'street-address': '152 West 5... | hotel | 93589 | The Michelangelo Hotel |
4 | 4.0 | 60763 | http://www.tripadvisor.com/Hotel_Review-g60763... | NaN | NaN | {'region': 'NY', 'street-address': '130 West 4... | hotel | 217616 | The Muse Hotel New York |
# Drop useless columns
offerings.drop(columns=["region_id", "url", "phone", "details", "address", "type"], inplace=True)
offerings.head(1)
hotel_class | id | name | |
---|---|---|---|
0 | 4.0 | 113317 | Casablanca Hotel Times Square |
Might remove hotel_class
later if it turns out to be useless...
offerings.isnull().sum()
hotel_class 1192 id 0 name 0 dtype: int64
Let's store these null rows to check if the replacement has been done correctly when the time comes.
idx_null_class = offerings[offerings["hotel_class"].isnull()].index
offerings.iloc[idx_null_class]
hotel_class | id | name | |
---|---|---|---|
6 | NaN | 2643161 | The NoMad Hotel |
44 | NaN | 1630591 | Crowne Plaza |
49 | NaN | 585164 | Residence Inn Houston West/Energy Corridor |
52 | NaN | 258634 | Scottish Inn & Suites Reliant Park/Six Flags |
70 | NaN | 815515 | Scottish Inns & Suites - Willowbrook |
... | ... | ... | ... |
4253 | NaN | 1204691 | Quality Inn & Suites Laurel |
4259 | NaN | 1218625 | Wyndham |
4261 | NaN | 1515599 | Executive Apartments |
4262 | NaN | 84068 | Harrington Hotel |
4282 | NaN | 120566 | The Mansion on O Street |
1192 rows × 3 columns
A hotel with a missing value in regards to its class basically means that the hotel has 0 stars, so we can replace these NaN
values with 0
.
offerings["hotel_class"] = offerings["hotel_class"].fillna(0)
offerings.iloc[idx_null_class]
hotel_class | id | name | |
---|---|---|---|
6 | 0.0 | 2643161 | The NoMad Hotel |
44 | 0.0 | 1630591 | Crowne Plaza |
49 | 0.0 | 585164 | Residence Inn Houston West/Energy Corridor |
52 | 0.0 | 258634 | Scottish Inn & Suites Reliant Park/Six Flags |
70 | 0.0 | 815515 | Scottish Inns & Suites - Willowbrook |
... | ... | ... | ... |
4253 | 0.0 | 1204691 | Quality Inn & Suites Laurel |
4259 | 0.0 | 1218625 | Wyndham |
4261 | 0.0 | 1515599 | Executive Apartments |
4262 | 0.0 | 84068 | Harrington Hotel |
4282 | 0.0 | 120566 | The Mansion on O Street |
1192 rows × 3 columns
The replacement has been done successfully; so now we can merge both of the DataFrames.
# Rename "id" column for the merge to go through
offerings.rename(columns={"id": "offering_id"}, inplace=True)
# Merge both DataFrames on "offering_id" column
final_df = df_grouped.merge(offerings, on="offering_id")
# Re-order the columns in a more logical order
final_df = final_df.iloc[:, [0, 4, 3, 2, 1]]
final_df
offering_id | name | hotel_class | ratings | reviews | |
---|---|---|---|---|---|
0 | 72572 | BEST WESTERN PLUS Pioneer Square Hotel | 3.5 | {'service': 4.6, 'cleanliness': 4.6, 'overall'... | I had to make fast visit to seattle and I foun... |
1 | 72579 | BEST WESTERN Loyal Inn | 2.0 | {'service': 4.2, 'cleanliness': 4.2, 'overall'... | Great service, rooms were clean, could use som... |
2 | 72586 | BEST WESTERN PLUS Executive Inn | 3.0 | {'service': 4.2, 'cleanliness': 4.3, 'overall'... | Beautiful views of the space needle - especial... |
3 | 72598 | Comfort Inn & Suites Seattle | 2.5 | {'service': 3.2, 'cleanliness': 3.2, 'overall'... | This hotel is in need of some serious updates.... |
4 | 73236 | Days Inn San Antonio/Near Lackland AFB | 2.0 | {'service': 4.3, 'cleanliness': 3.1, 'overall'... | My experience at this days inn was perfect. th... |
... | ... | ... | ... | ... | ... |
3749 | 3523356 | Hampton Inn & Suites Austin @ The University/C... | 2.5 | {'service': 4.9, 'cleanliness': 4.9, 'overall'... | I've stayed at plenty of Hampton Inns during m... |
3750 | 3541823 | New York Budget Inn | 0.0 | {'service': 4.3, 'cleanliness': 4.5, 'overall'... | Inn staff absolutely wonderful, helpful, knowl... |
3751 | 3572384 | Hyatt Place Chicago/River North | 0.0 | {'service': 3.0, 'cleanliness': 2.0, 'overall'... | Crowded, noisy, dirty. Service is poor, food i... |
3752 | 3572583 | Holiday Inn Express New York - Manhattan West ... | 3.0 | {'service': 1.0, 'cleanliness': 1.0, 'overall'... | El hotel estaba en medio de una remodelación. ... |
3753 | 3574675 | Days Inn Columbus Airport | 3.0 | {'service': 3.0, 'cleanliness': 2.8, 'overall'... | We were looking for a place to stay close to t... |
3754 rows × 5 columns
# Preprocess function to clean and prepare text
def preprocess(text, count=False):
stop_words = set(stopwords.words("english"))
# Tokenization
tokens = regexp_tokenize(text.lower(), r"\w+")
tokens = [token for token in tokens if token.isalpha()] # Remove non-alphabetic tokens
tokens = [token for token in tokens if token not in stop_words] # Remove stopwords
# Lemmatization
lemmatizer = WordNetLemmatizer()
tokens = [lemmatizer.lemmatize(token) for token in tokens]
return Counter(tokens) if count else tokens # Returning tokens directly for use in BM25
preprocess(final_df["reviews"][2], True)
Counter({'hotel': 267, 'room': 230, 'needle': 129, 'seattle': 125, 'space': 124, 'staff': 123, 'great': 104, 'breakfast': 88, 'location': 86, 'clean': 78, 'good': 77, 'stay': 77, 'night': 74, 'u': 70, 'best': 69, 'view': 66, 'nice': 61, 'monorail': 61, 'would': 59, 'western': 55, 'one': 55, 'place': 54, 'parking': 53, 'walk': 53, 'downtown': 51, 'service': 50, 'desk': 48, 'friendly': 48, 'time': 46, 'restaurant': 46, 'center': 45, 'stayed': 45, 'price': 45, 'day': 44, 'bed': 44, 'also': 44, 'front': 43, 'helpful': 43, 'well': 38, 'like': 36, 'buffet': 36, 'block': 34, 'area': 34, 'free': 33, 'get': 33, 'way': 33, 'excellent': 32, 'could': 31, 'close': 31, 'even': 31, 'minute': 31, 'next': 30, 'two': 30, 'away': 30, 'comfortable': 30, 'need': 30, 'little': 30, 'really': 29, 'walking': 27, 'plus': 24, 'got': 24, 'everything': 24, 'back': 24, 'inn': 23, 'easy': 23, 'pike': 23, 'right': 23, 'see': 22, 'recommend': 22, 'executive': 22, 'check': 22, 'market': 22, 'go': 21, 'thing': 21, 'around': 21, 'food': 21, 'noise': 21, 'near': 21, 'tv': 20, 'much': 19, 'window': 19, 'street': 19, 'extra': 19, 'da': 19, 'lot': 18, 'make': 18, 'morning': 18, 'car': 18, 'big': 18, 'first': 18, 'asked': 18, 'cruise': 18, 'guest': 17, 'bit': 17, 'people': 17, 'distance': 17, 'find': 16, 'went': 16, 'better': 16, 'package': 16, 'take': 16, 'attraction': 16, 'perfect': 16, 'always': 16, 'lobby': 16, 'although': 16, 'wanted': 16, 'bathroom': 16, 'etc': 16, 'family': 16, 'trip': 16, 'outside': 16, 'feel': 15, 'going': 15, 'shower': 15, 'choice': 15, 'took': 15, 'every': 15, 'value': 15, 'paid': 15, 'spacious': 15, 'used': 15, 'und': 15, 'want': 14, 'many': 14, 'building': 14, 'review': 14, 'bw': 14, 'within': 14, 'museum': 14, 'pretty': 14, 'side': 14, 'bad': 14, 'customer': 14, 'ok': 14, 'town': 14, 'city': 14, 'bus': 14, 'booked': 14, 'visit': 14, 'door': 13, 'came': 13, 'made': 13, 'arrived': 13, 'fantastic': 13, 'pay': 13, 'overall': 13, 'rate': 13, 'travel': 13, 'reservation': 13, 'help': 13, 'person': 12, 'short': 12, 'nothing': 12, 'included': 12, 'cost': 12, 'however': 12, 'small': 12, 'look': 12, 'say': 12, 'nearby': 12, 'microwave': 12, 'across': 12, 'needed': 12, 'last': 12, 'call': 11, 'internet': 11, 'science': 11, 'enough': 11, 'worked': 11, 'quiet': 11, 'experience': 11, 'wonderful': 11, 'part': 11, 'fine': 11, 'said': 11, 'kind': 11, 'phone': 11, 'taking': 11, 'kid': 11, 'use': 11, 'emp': 11, 'extremely': 11, 'war': 11, 'called': 10, 'loud': 10, 'happy': 10, 'light': 10, 'since': 10, 'key': 10, 'floor': 10, 'water': 10, 'though': 10, 'fridge': 10, 'felt': 10, 'looked': 10, 'walked': 10, 'problem': 10, 'expensive': 10, 'park': 10, 'work': 10, 'deal': 10, 'new': 10, 'centre': 10, 'airport': 10, 'die': 10, 'issue': 9, 'king': 9, 'group': 9, 'home': 9, 'decent': 9, 'another': 9, 'full': 9, 'husband': 9, 'queen': 9, 'told': 9, 'eat': 9, 'manager': 9, 'staying': 9, 'put': 9, 'definitely': 9, 'reasonable': 9, 'management': 9, 'provided': 9, 'everyone': 9, 'ride': 9, 'access': 9, 'computer': 9, 'party': 9, 'woman': 9, 'far': 9, 'charge': 9, 'huge': 9, 'coffee': 9, 'found': 9, 'courteous': 9, 'secure': 8, 'inside': 8, 'hallway': 8, 'may': 8, 'evening': 8, 'traffic': 8, 'sure': 8, 'old': 8, 'available': 8, 'never': 8, 'star': 8, 'convenient': 8, 'high': 8, 'name': 8, 'quality': 8, 'screen': 8, 'still': 8, 'pier': 8, 'green': 8, 'able': 8, 'vancouver': 8, 'lounge': 8, 'business': 8, 'zimmer': 8, 'der': 8, 'man': 7, 'seemed': 7, 'safe': 7, 'pleased': 7, 'top': 7, 'hot': 7, 'left': 7, 'end': 7, 'offer': 7, 'plan': 7, 'hour': 7, 'wall': 7, 'thanks': 7, 'wifi': 7, 'arena': 7, 'elevator': 7, 'least': 7, 'bar': 7, 'checked': 7, 'stop': 7, 'note': 7, 'super': 7, 'enjoyed': 7, 'without': 7, 'closed': 7, 'transportation': 7, 'half': 7, 'fee': 7, 'chose': 7, 'event': 7, 'waterfront': 7, 'question': 7, 'probably': 7, 'money': 7, 'sleep': 7, 'discount': 7, 'fun': 7, 'long': 7, 'facility': 7, 'fresh': 7, 'negative': 7, 'outstanding': 7, 'amazing': 7, 'liked': 7, 'per': 7, 'friend': 7, 'hear': 7, 'ist': 7, 'wir': 7, 'im': 7, 'especially': 6, 'ask': 6, 'conference': 6, 'pacific': 6, 'getting': 6, 'older': 6, 'think': 6, 'egg': 6, 'spot': 6, 'glass': 6, 'year': 6, 'thin': 6, 'turn': 6, 'awesome': 6, 'delivered': 6, 'noisy': 6, 'pressure': 6, 'plenty': 6, 'child': 6, 'rather': 6, 'waiting': 6, 'impressed': 6, 'open': 6, 'motel': 6, 'try': 6, 'know': 6, 'variety': 6, 'air': 6, 'moment': 6, 'highly': 6, 'drive': 6, 'hall': 6, 'slept': 6, 'card': 6, 'shuttle': 6, 'pick': 6, 'thank': 6, 'clearly': 6, 'duck': 6, 'dated': 6, 'including': 6, 'shopping': 6, 'worth': 6, 'lake': 6, 'point': 6, 'machine': 6, 'flat': 6, 'allowed': 6, 'convention': 6, 'wife': 6, 'couple': 6, 'wait': 6, 'low': 6, 'fast': 6, 'dispenser': 6, 'shampoo': 6, 'actually': 6, 'book': 6, 'certainly': 6, 'provide': 6, 'looking': 6, 'spent': 6, 'garage': 6, 'visiting': 6, 'dinner': 6, 'large': 6, 'head': 6, 'parent': 6, 'sehr': 6, 'für': 6, 'mit': 6, 'beautiful': 5, 'local': 5, 'come': 5, 'line': 5, 'due': 5, 'underground': 5, 'waffle': 5, 'member': 5, 'driving': 5, 'limited': 5, 'anything': 5, 'quite': 5, 'july': 5, 'direction': 5, 'property': 5, 'son': 5, 'ever': 5, 'pillow': 5, 'yes': 5, 'working': 5, 'request': 5, 'ate': 5, 'special': 5, 'selection': 5, 'online': 5, 'gave': 5, 'construction': 5, 'thought': 5, 'surprised': 5, 'three': 5, 'recommended': 5, 'return': 5, 'hard': 5, 'beyond': 5, 'helped': 5, 'oh': 5, 'afternoon': 5, 'complaint': 5, 'e': 5, 'almost': 5, 'carpet': 5, 'game': 5, 'number': 5, 'taxi': 5, 'voucher': 5, 'station': 5, 'dining': 5, 'loved': 5, 'enjoy': 5, 'pool': 5, 'homeless': 5, 'early': 5, 'hold': 5, 'luggage': 5, 'standard': 5, 'five': 5, 'located': 5, 'expectation': 5, 'addition': 5, 'given': 5, 'accommodating': 5, 'upon': 5, 'run': 5, 'central': 5, 'pizza': 5, 'meal': 5, 'quick': 5, 'despite': 5, 'comfy': 5, 'daughter': 5, 'ken': 5, 'believe': 5, 'decor': 5, 'sky': 5, 'four': 5, 'cozy': 5, 'wireless': 5, 'christmas': 5, 'employee': 5, 'soap': 5, 'terminal': 5, 'wi': 4, 'fi': 4, 'dressed': 4, 'keep': 4, 'ticket': 4, 'proximity': 4, 'kept': 4, 'furniture': 4, 'brella': 4, 'sorry': 4, 'offering': 4, 'different': 4, 'weather': 4, 'surprise': 4, 'garden': 4, 'accommodation': 4, 'credit': 4, 'concert': 4, 'handy': 4, 'set': 4, 'lower': 4, 'someone': 4, 'talking': 4, 'polite': 4, 'suggestion': 4, 'option': 4, 'adequate': 4, 'aware': 4, 'fault': 4, 'refrigerator': 4, 'sign': 4, 'leave': 4, 'let': 4, 'bacon': 4, 'conditioning': 4, 'safeco': 4, 'drop': 4, 'company': 4, 'reached': 4, 'truly': 4, 'com': 4, 'completely': 4, 'job': 4, 'menu': 4, 'twice': 4, 'making': 4, 'fancy': 4, 'yummy': 4, 'cooky': 4, 'whole': 4, 'pleasant': 4, 'site': 4, 'connectivity': 4, 'neighborhood': 4, 'higher': 4, 'expected': 4, 'mcdonald': 4, 'less': 4, 'expect': 4, 'cheap': 4, 'sink': 4, 'positive': 4, 'union': 4, 'checking': 4, 'answer': 4, 'important': 4, 'direct': 4, 'email': 4, 'tax': 4, 'level': 4, 'normally': 4, 'start': 4, 'using': 4, 'meeting': 4, 'requested': 4, 'attendee': 4, 'clerk': 4, 'deserves': 4, 'tom': 4, 'dana': 4, 'age': 4, 'previous': 4, 'sightseeing': 4, 'saved': 4, 'rail': 4, 'fitness': 4, 'anyone': 4, 'travelling': 4, 'spectacular': 4, 'music': 4, 'reception': 4, 'considering': 4, 'chair': 4, 'information': 4, 'catering': 4, 'prepared': 4, 'easily': 4, 'several': 4, 'road': 4, 'disappointed': 4, 'major': 4, 'picked': 4, 'idea': 4, 'decorated': 4, 'towel': 4, 'ten': 4, 'care': 4, 'min': 4, 'amenity': 4, 'choose': 4, 'step': 4, 'speed': 4, 'frühstück': 4, 'einen': 4, 'zu': 4, 'nicht': 4, 'den': 4, 'ein': 4, 'var': 4, 'duty': 3, 'give': 3, 'tried': 3, 'downstairs': 3, 'decided': 3, 'updated': 3, 'sound': 3, 'efficient': 3, 'paying': 3, 'added': 3, 'saw': 3, 'dark': 3, 'otherwise': 3, 'suggested': 3, 'sleeping': 3, 'blanket': 3, 'saturday': 3, 'others': 3, 'relaxing': 3, 'definately': 3, 'traveling': 3, 'favorite': 3, 'giving': 3, 'average': 3, 'complain': 3, 'either': 3, 'coming': 3, 'finding': 3, 'understand': 3, 'connecting': 3, 'future': 3, 'cleaned': 3, 'wash': 3, 'whether': 3, 'includes': 3, 'tut': 3, 'parked': 3, 'spend': 3, 'non': 3, 'second': 3, 'tiny': 3, 'toilet': 3, 'maid': 3, 'respect': 3, 'trying': 3, 'goodness': 3, 'replaced': 3, 'spring': 3, 'response': 3, 'field': 3, 'mariner': 3, 'answered': 3, 'driver': 3, 'apparently': 3, 'julian': 3, 'accomodations': 3, 'tip': 3, 'item': 3, 'table': 3, 'fabulous': 3, 'patricia': 3, 'decision': 3, 'corner': 3, 'swimming': 3, 'spa': 3, 'dont': 3, 'police': 3, 'matter': 3, 'already': 3, 'mentioned': 3, 'seems': 3, 'love': 3, 'basic': 3, 'snack': 3, 'cut': 3, 'week': 3, 'flight': 3, 'real': 3, 'slow': 3, 'relatively': 3, 'store': 3, 'district': 3, 'managed': 3, 'onto': 3, 'reason': 3, 'might': 3, 'save': 3, 'size': 3, 'updating': 3, 'fan': 3, 'lotion': 3, 'weak': 3, 'turned': 3, 'touch': 3, 'recently': 3, 'tourism': 3, 'maybe': 3, 'tourist': 3, 'frustrating': 3, 'checkout': 3, 'mattress': 3, 'alternative': 3, 'cereal': 3, 'juice': 3, 'p': 3, 'bonus': 3, 'ton': 3, 'complimentary': 3, 'equipped': 3, 'presentation': 3, 'factor': 3, 'budget': 3, 'late': 3, 'busy': 3, 'happen': 3, 'sat': 3, 'justin': 3, 'ago': 3, 'supposed': 3, 'conditioner': 3, 'c': 3, 'encountered': 3, 'tour': 3, 'show': 3, 'sufficient': 3, 'mini': 3, 'attractive': 3, 'continental': 3, 'additional': 3, 'offered': 3, 'strength': 3, 'throughout': 3, 'rental': 3, 'worry': 3, 'bartender': 3, 'cheryl': 3, 'judge': 3, 'cover': 3, 'appreciated': 3, 'josh': 3, 'true': 3, 'incredibly': 3, 'ideal': 3, 'lovely': 3, 'treat': 3, 'effort': 3, 'met': 3, 'warm': 3, 'heart': 3, 'adjacent': 3, 'entertainment': 3, 'affordable': 3, 'column': 3, 'lunch': 3, 'quickly': 3, 'must': 3, 'pas': 3, 'fireplace': 3, 'exterior': 3, 'curtain': 3, 'treated': 3, 'nicely': 3, 'greeted': 3, 'purpose': 3, 'hop': 3, 'held': 3, 'vacation': 3, 'choosing': 3, 'beat': 3, 'neighbor': 3, 'handicapped': 3, 'men': 3, 'ended': 3, 'ready': 3, 'ice': 3, 'promised': 3, 'bottle': 3, 'westlake': 3, 'personal': 3, 'von': 3, 'entfernt': 3, 'dem': 3, 'auch': 3, 'nur': 3, 'unser': 3, 'usd': 3, 'nach': 3, 'aber': 3, 'hotellet': 3, 'av': 3, 'password': 2, 'policy': 2, 'ridiculous': 2, 'anyway': 2, 'spoke': 2, 'shocked': 2, 'leaf': 2, 'vip': 2, 'specific': 2, 'opted': 2, 'dissapointed': 2, 'wise': 2, 'adjoining': 2, 'sausage': 2, 'slimy': 2, 'chihuly': 2, 'exhibit': 2, 'experienced': 2, 'v': 2, 'compared': 2, 'lodging': 2, 'counter': 2, 'unless': 2, 'stocked': 2, 'marketing': 2, 'reserved': 2, 'adult': 2, 'housekeeper': 2, 'bring': 2, 'setting': 2, 'heard': 2, 'main': 2, 'seen': 2, 'comment': 2, 'disposable': 2, 'advising': 2, 'particularly': 2, 'locally': 2, 'tap': 2, 'advantage': 2, 'literally': 2, 'entire': 2, 'watch': 2, 'earlier': 2, 'garbage': 2, 'truck': 2, 'sit': 2, 'privacy': 2, 'telling': 2, 'serviced': 2, 'cleanliness': 2, 'comfort': 2, 'nite': 2, 'lucky': 2, 'uncomfortable': 2, 'broken': 2, 'change': 2, 'worried': 2, 'portland': 2, 'ferry': 2, 'stain': 2, 'missing': 2, 'informed': 2, 'jerk': 2, 'indeed': 2, 'ticked': 2, 'lodge': 2, 'sending': 2, 'letter': 2, 'showed': 2, 'confirmation': 2, 'solve': 2, 'fully': 2, 'worse': 2, 'collection': 2, 'beside': 2, 'priced': 2, 'following': 2, 'mcdonalds': 2, 'round': 2, 'something': 2, 'ive': 2, 'rating': 2, 'bothered': 2, 'stone': 2, 'throw': 2, 'milk': 2, 'later': 2, 'solid': 2, 'mile': 2, 'abit': 2, 'bath': 2, 'attend': 2, 'definite': 2, 'attending': 2, 'responsive': 2, 'month': 2, 'accomodating': 2, 'particular': 2, 'enjoyable': 2, 'perfectly': 2, 'honest': 2, 'spray': 2, 'covering': 2, 'advertising': 2, 'stocking': 2, 'possible': 2, 'regular': 2, 'yakima': 2, 'condition': 2, 'amount': 2, 'poor': 2, 'notice': 2, 'brought': 2, 'attention': 2, 'rough': 2, 'term': 2, 'outdated': 2, 'worst': 2, 'system': 2, 'cool': 2, 'disappointing': 2, 'extensive': 2, 'bright': 2, 'denny': 2, 'anne': 2, 'alaskan': 2, 'checkin': 2, 'industry': 2, 'conversation': 2, 'stuff': 2, 'knowledge': 2, 'map': 2, 'training': 2, 'confirm': 2, 'happened': 2, 'calling': 2, 'simply': 2, 'cheese': 2, 'maker': 2, 'fruit': 2, 'potato': 2, 'clown': 2, 'sleeper': 2, 'banquet': 2, 'west': 2, 'separation': 2, 'stair': 2, 'solved': 2, 'speaker': 2, 'minor': 2, 'play': 2, 'delicious': 2, 'wide': 2, 'host': 2, 'respond': 2, 'hesitate': 2, 'emergency': 2, 'gentleman': 2, 'concerned': 2, 'attentive': 2, 'unhelpful': 2, 'sour': 2, 'smile': 2, 'fifteenth': 2, 'seated': 2, 'waitress': 2, 'young': 2, 'assume': 2, 'chain': 2, 'bin': 2, 'rug': 2, 'hidden': 2, 'housekeeping': 2, 'stuck': 2, 'surroundings': 2, 'feature': 2, 'changed': 2, 'proved': 2, 'ship': 2, 'sized': 2, 'ground': 2, 'coupon': 2, 'wake': 2, 'rode': 2, 'unsafe': 2, 'talk': 2, 'fire': 2, 'victoria': 2, 'funky': 2, 'dropped': 2, 'newer': 2, 'lived': 2, 'cold': 2, 'virtually': 2, 'maintained': 2, 'linen': 2, 'freeway': 2, 'tasty': 2, 'wish': 2, 'hawaii': 2, 'remember': 2, 'rest': 2, 'opinion': 2, 'smell': 2, 'inviting': 2, 'attended': 2, 'patient': 2, 'concern': 2, 'firm': 2, 'demolition': 2, 'empty': 2, 'arrangement': 2, 'middle': 2, 'behind': 2, 'poster': 2, 'drink': 2, 'complimented': 2, 'kitchen': 2, 'hub': 2, 'reachable': 2, 'efficiency': 2, 'past': 2, 'self': 2, 'actual': 2, 'downside': 2, 'exceptional': 2, 'advisor': 2, ...})
preprocess(final_df["reviews"][2])
['beautiful', 'view', 'space', 'needle', 'especially', 'night', 'like', 'photography', 'ask', 'room', 'view', 'staff', 'great', 'local', 'restuarant', 'excellent', 'secure', 'parking', 'plus', 'free', 'wi', 'fi', 'issue', 'waking', 'conference', 'call', 'could', 'find', 'internet', 'password', 'called', 'front', 'desk', 'man', 'duty', 'would', 'give', 'insisited', 'come', 'get', 'person', 'tried', 'convince', 'dressed', 'claimed', 'policy', 'guest', 'come', 'collect', 'password', 'desk', 'got', 'dressed', 'went', 'downstairs', 'get', 'ridiculous', 'seriously', 'irritated', 'anyway', 'spoke', 'day', 'staff', 'seemed', 'shocked', 'hotel', 'policy', 'keep', 'code', 'safe', 'intending', 'see', 'king', 'tutankhamen', 'treasure', 'pacific', 'science', 'center', 'leaf', 'january', 'time', 'getting', 'short', 'decided', 'better', 'purchase', 'vip', 'ticket', 'go', 'specific', 'time', 'stand', 'line', 'opted', 'hotel', 'due', 'proximity', 'seattle', 'center', 'dissapointed', 'secure', 'underground', 'parking', 'space', 'needle', 'view', 'king', 'room', 'pleased', 'hotel', 'bit', 'older', 'well', 'kept', 'updated', 'furniture', 'wise', 'well', 'room', 'adjoining', 'room', 'group', 'next', 'door', 'bit', 'loud', 'think', 'door', 'thick', 'enough', 'sound', 'proof', 'enough', 'two', 'room', 'hotel', 'staff', 'efficient', 'helpful', 'package', 'came', 'free', 'breakfast', 'brella', 'restaurant', 'inside', 'hotel', 'passed', 'breakfast', 'nothing', 'write', 'home', 'much', 'better', 'breakfast', 'hotel', 'included', 'cost', 'room', 'feel', 'sorry', 'people', 'paying', 'breakfast', 'top', 'cost', 'room', 'offering', 'much', 'different', 'hotel', 'good', 'sausage', 'slimy', 'egg', 'stiff', 'dry', 'hash', 'brown', 'slimy', 'good', 'thing', 'waffle', 'made', 'hot', 'spot', 'blessed', 'decent', 'weather', 'another', 'surprise', 'seattle', 'center', 'dale', 'chihuly', 'garden', 'glass', 'exhibit', 'added', 'year', 'arrived', 'saw', 'garden', 'bit', 'sunlight', 'left', 'experienced', 'dark', 'fantastic', 'hotel', 'excellent', 'location', 'would', 'recommend', 'space', 'needle', 'view', 'however', 'end', 'hallway', 'get', 'small', 'window', 'offer', 'free', 'breakfast', 'buffet', 'best', 'western', 'member', 'otherwise', 'pay', 'good', 'buffet', 'excellent', 'seating', 'v', 'best', 'western', 'room', 'nice', 'pay', 'resonable', 'compared', 'lodging', 'closer', 'downtown', 'walking', 'distant', 'monorail', 'take', 'downtown', 'however', 'plan', 'driving', 'around', 'may', 'want', 'look', 'another', 'location', 'parking', 'limited', 'anything', 'going', 'seattle', 'may', 'find', 'street', 'parking', 'block', 'away', 'left', 'one', 'night', 'parking', 'full', 'counter', 'personnel', 'suggested', 'lot', 'two', 'block', 'charged', 'hour', 'happy', 'camper', 'walking', 'issue', 'defiantly', 'would', 'worked', 'well', 'accommodation', 'wall', 'thin', 'unless', 'turn', 'heater', 'feel', 'like', 'sleeping', 'sheet', 'light', 'blanket', 'pull', 'closet', 'suggest', 'hotel', 'restaurant', 'front', 'desk', 'steered', 'u', 'better', 'food', 'husband', 'stayed', 'saturday', 'would', 'recommend', 'others', 'staff', 'friendly', 'quiet', 'relaxing', 'room', 'clean', 'bed', 'comfortable', 'good', 'price', 'close', 'space', 'needle', 'would', 'definately', 'stay', 'next', 'time', 'go', 'seattle', 'overall', 'great', 'hotel', 'dong', 'quite', 'bit', 'traveling', 'since', 'retired', 'end', 'july', 'best', 'wester', 'plus', 'executive', 'inn', 'one', 'favorite', 'staff', 'attitude', 'make', 'stay', 'great', 'experience', 'wonderful', 'time', 'thanks', 'helpful', 'staff', 'te', 'great', 'giving', 'u', 'direction', 'advise', 'go', 'get', 'seattle', 'awesome', 'location', 'great', 'view', 'room', 'clean', 'well', 'stocked', 'wifi', 'flawless', 'short', 'one', 'night', 'stay', 'average', 'nothing', 'complain', 'nothing', 'brag', 'either', 'feel', 'plus', 'status', 'hotel', 'marketing', 'stretch', 'give', 'credit', 'property', 'location', 'location', 'location', 'easy', 'walk', 'many', 'seattle', 'attraction', 'around', 'space', 'needle', 'reserved', 'july', 'occupancy', 'room', 'queen', 'bed', 'traveling', 'adult', 'son', 'november', 'concert', 'key', 'arena', 'good', 'thing', 'say', 'close', 'handy', 'concert', 'arrived', 'check', 'told', 'room', 'bed', 'roll', 'away', 'sent', 'saddest', 'bed', 'ever', 'saw', 'delivered', 'rude', 'housekeeper', 'acted', 'mad', 'bring', 'u', 'bed', 'extra', 'blanket', 'pillow', 'even', 'offer', 'set', 'bed', 'room', 'floor', 'elevator', 'noisy', 'setting', 'heard', 'guest', 'housekeeper', 'coming', 'going', 'view', 'roof', 'top', 'neighboring', 'building', 'lower', 'parking', 'area', 'good', 'place', 'nearby', 'eat', 'nice', 'shower', 'lot', 'water', 'pressure', 'though', 'tub', 'drain', 'stayed', 'night', 'went', 'rush', 'concert', 'key', 'arena', 'excellent', 'concert', 'way', 'location', 'perfect', 'contrary', 'review', 'trouble', 'finding', 'excellent', 'view', 'space', 'needle', 'floor', 'room', 'yes', 'older', 'hotel', 'need', 'reno', 'understand', 'working', 'room', 'plenty', 'space', 'everything', 'worked', 'well', 'main', 'issue', 'noise', 'coming', 'guest', 'next', 'door', 'one', 'night', 'child', 'loud', 'next', 'someone', 'talking', 'loud', 'morning', 'may', 'adjoining', 'room', 'next', 'time', 'would', 'request', 'room', 'connecting', 'door', 'lesson', 'learned', 'breakfast', 'better', 'many', 'get', 'best', 'western', 'plenty', 'choice', 'get', 'bored', 'day', 'stay', 'food', 'restaurant', 'evening', 'rather', 'bland', 'ate', 'nice', 'fridge', 'microwave', 'room', 'always', 'ask', 'fridge', 'least', 'staff', 'hotel', 'always', 'polite', 'friendly', 'even', 'line', 'guest', 'waiting', 'seen', 'also', 'impressed', 'manager', 'see', 'responds', 'review', 'doubt', 'comment', 'suggestion', 'future', 'bw', 'plus', 'proper', 'glass', 'mug', 'well', 'disposable', 'option', 'seen', 'report', 'cleaned', 'place', 'guest', 'wash', 'also', 'think', 'advising', 'guest', 'room', 'connecting', 'door', 'next', 'room', 'decide', 'whether', 'stay', 'room', 'hotel', 'great', 'location', 'view', 'space', 'needle', 'within', 'easy', 'walking', 'distance', 'monorail', 'downtown', 'service', 'patchy', 'however', 'lobby', 'room', 'little', 'dingy', 'need', 'modernization', 'particularly', 'view', 'price', 'parking', 'extra', 'also', 'get', 'rate', 'includes', 'breakfast', 'although', 'breakfast', 'nothing', 'special', 'bar', 'nice', 'selection', 'locally', 'brewed', 'ale', 'tap', 'wanted', 'place', 'close', 'museum', 'attraction', 'near', 'space', 'needle', 'took', 'advantage', 'hotel', 'king', 'tut', 'package', 'hotel', 'literally', 'two', 'block', 'everything', 'price', 'better', 'others', 'checked', 'online', 'parked', 'car', 'hotel', 'move', 'entire', 'time', 'night', 'one', 'big', 'advantage', 'staying', 'king', 'tut', 'package', 'gave', 'u', 'vip', 'ticket', 'meant', 'could', 'go', 'see', 'exhibit', 'time', 'open', 'rather', 'date', 'time', 'specific', 'ticket', 'motel', 'room', 'clean', 'adequate', 'spend', 'much', 'time', 'view', 'room', 'pretty', 'blah', 'overlooking', 'parking', 'lot', 'except', 'get', 'watch', 'one', 'really', 'big', 'building', 'crane', 'operation', 'aware', 'least', 'part', 'seattle', 'seemed', 'construction', 'mode', 'hotel', 'fault', 'awakened', 'one', 'morning', 'non', 'stop', 'jack', 'hammering', 'street', 'even', 'earlier', 'second', 'morning', 'arrival', 'garbage', 'truck', 'plus', 'side', 'room', 'refrigerator', 'microwave', 'arm', 'chairm', 'bathroom', 'tiny', 'try', 'sit', 'toilet', 'close', 'door', 'time', 'comment', 'maid', 'service', 'say', 'respect', 'privacy', 'clean', 'room', 'since', 'put', 'disturb', 'sign', 'leave', 'u', 'note', 'day', 'telling', 'u', 'want', 'anything', 'serviced', 'let', 'front', 'desk', 'know', 'thought', 'nice', 'way', 'handle', 'breakfast', 'hotel', 'restaurant', 'morning', 'convenience', 'first', 'day', 'part', 'package', 'good', 'variety', 'make', 'breakfast', 'burrito', 'waffle', 'oatmeal', 'bacon', 'etc', 'although', 'exact', 'choice', 'day', 'got', 'little', 'boring', 'third', 'morning', 'breakfast', 'family', 'stay', 'another', 'hotel', 'area', 'earlier', 'year', 'surprised', 'air', 'conditioning', 'hotel', 'air', 'conditioning', 'worked', 'fine', 'definitely', 'adequate', 'place', 'reasonable', 'price', 'seattle', 'super', 'location', 'stayed', 'three', 'night', 'enjoyed', 'every', 'moment', 'room', 'location', 'helpful', 'staff', 'cleanliness', 'value', 'comfort', 'everything', 'spot', 'staff', 'friendly', 'helpful', 'highly', 'recommended', 'return', 'wanted', 'hotel', 'near', 'space', 'needle', 'knew', 'traffic', 'would', 'nite', 'mare', 'trying', 'find', 'place', 'hard', 'check', 'horrific', 'person', 'come', 'really', 'took', 'minute', 'hour', 'drive', 'beyond', 'comprehension', 'got', 'lucky', 'got', 'room', 'view', 'without', 'pay', 'extra', 'night', 'helped', 'little', 'bit', 'hall', 'room', 'dirty', 'bed', 'oh', 'goodness', 'horrible', 'uncomfortable', 'son', 'said', 'felt', 'like', 'really', 'big', 'person', 'slept', 'need', 'replaced', 'spring', 'totally', 'broken', 'pleased', 'breakfast', 'day', 'paid', 'day', 'change', 'closed', 'exactly', 'exception', 'mon', 'afternoon', 'thurs', 'put', 'complaint', 'card', 'got', 'e', 'mail', 'response', 'replied', 'back', 'nothing', 'sure', 'management', 'anything', 'night', 'almost', 'mortgage', 'payment', 'thought', 'would', 'better', 'room', 'ever', 'worried', 'next', 'night', 'best', 'western', 'portland', 'let', 'see', 'checked', 'best', 'western', 'executive', 'part', 'blackball', 'ferry', 'package', 'hotel', ...]
Now we can apply the preprocessing to all the reviews to make our corpus.
# Prepare corpus
corpus = [preprocess(doc) for doc in final_df['reviews']]
# Show five first elements of corpus
corpus[:5]
[['make', 'fast', 'visit', 'seattle', 'found', 'pioneer', 'regret', 'hotel', 'comfortable', 'clean', 'else', 'mm', 'nice', 'area', 'everything', 'walking', 'distance', 'guess', 'breakfast', 'something', 'else', 'bread', 'waffle', 'fourth', 'fifth', 'time', 'staying', 'best', 'western', 'pioneer', 'square', 'like', 'location', 'within', 'walking', 'distance', 'downtown', 'waterfront', 'ball', 'field', 'get', 'town', 'park', 'available', 'garage', 'rest', 'trip', 'foot', 'minute', 'walk', 'action', 'downtown', 'pike', 'street', 'shopping', 'etc', 'may', 'far', 'walk', 'like', 'dealing', 'driving', 'parking', 'downtown', 'place', 'nothing', 'fancy', 'hotel', 'room', 'nice', 'clean', 'staff', 'helpful', 'friendly', 'view', 'room', 'also', 'leave', 'much', 'desired', 'fact', 'better', 'worrying', 'gazing', 'window', 'place', 'location', 'atmosphere', 'old', 'seattle', 'continental', 'breakfast', 'taken', 'advantage', 'previous', 'visit', 'fine', 'want', 'quick', 'bite', 'morning', 'make', 'unplanned', 'visit', 'seattle', 'due', 'lost', 'passport', 'chose', 'least', 'expensive', 'hotel', 'near', 'passport', 'office', 'expecting', 'boring', 'chain', 'hotel', 'delightful', 'surprise', 'best', 'western', 'like', 'boutique', 'hotel', 'lobby', 'lovely', 'comfortable', 'staff', 'warm', 'helpful', 'room', 'service', 'food', 'wonderful', 'italian', 'restaurant', 'next', 'door', 'definitely', 'back', 'say', 'rate', 'seem', 'fluctuate', 'quite', 'lot', 'lowest', 'best', 'deal', 'excluding', 'priceline', 'hotwire', 'thing', 'seattle', 'going', 'stayed', 'many', 'time', 'every', 'single', 'stay', 'fantastic', 'value', 'love', 'building', 'historic', 'building', 'really', 'like', 'big', 'old', 'stairway', 'use', 'rather', 'small', 'elevator', 'crammed', 'building', 'later', 'date', 'place', 'kept', 'clean', 'room', 'range', 'fairly', 'small', 'pretty', 'big', 'bed', 'good', 'bathroom', 'good', 'small', 'maintenance', 'property', 'seems', 'excellent', 'location', 'spectacular', 'link', 'light', 'rail', 'seattle', 'fantastic', 'rail', 'system', 'seatac', 'westlake', 'short', 'walk', 'hotel', 'station', 'name', 'wait', 'pioneer', 'square', 'kind', 'easy', 'remember', 'given', 'name', 'hotel', 'huh', 'easy', 'walking', 'riding', 'public', 'transport', 'downtown', 'staff', 'nice', 'always', 'greet', 'kindly', 'gentleman', 'checking', 'time', 'even', 'apologized', 'noticed', 'multiple', 'time', 'know', 'name', 'checking', 'early', 'asked', 'day', 'plan', 'learning', 'leaving', 'late', 'flight', 'promptly', 'offered', 'check', 'bag', 'need', 'great', 'staff', 'try', 'anticipate', 'need', 'well', 'managed', 'location', 'free', 'breakfast', 'typical', 'hotel', 'fare', 'reasonable', 'quality', 'lot', 'restaurant', 'around', 'want', 'grab', 'bite', 'eat', 'grab', 'take', 'away', 'room', 'really', 'like', 'inexpensive', 'friendly', 'asian', 'restaurant', 'right', 'next', 'door', 'east', 'side', 'front', 'building', 'recall', 'name', 'would', 'review', 'highly', 'recommend', 'hotel', 'particularly', 'pay', 'one', 'low', 'rate', 'absolutely', 'excellent', 'value', 'kudos', 'management', 'staff', 'get', 'know', 'area', 'get', 'info', 'staff', 'take', 'time', 'enjoy', 'seattle', 'waterfront', 'perhaps', 'ride', 'ferry', 'boat', 'two', 'across', 'sound', 'ready', 'ever', 'changing', 'weather', 'part', 'seattle', 'charm', 'time', 'slowly', 'walk', 'around', 'give', 'depth', 'picture', 'seattle', 'water', 'front', 'activity', 'also', 'always', 'something', 'stimulate', 'everyones', 'attention', 'perfectly', 'renovated', 'historical', 'hotel', 'immaculate', 'room', 'comfortable', 'hotel', 'staff', 'courteous', 'knowledgeable', 'location', 'less', 'block', 'waterfront', 'ferry', 'pier', 'two', 'block', 'light', 'rail', 'station', 'fare', 'seatac', 'step', 'back', 'greeted', 'historic', 'ambiance', 'rich', 'dark', 'wood', 'welcoming', 'fireplace', 'sitting', 'area', 'original', 'grand', 'staircase', 'period', 'furnishing', 'floor', 'landing', 'quiet', 'room', 'beautifully', 'decorated', 'heavy', 'brocade', 'drapery', 'tapestry', 'highback', 'sitting', 'chair', 'loveseat', 'setee', 'besides', 'two', 'comfortable', 'bed', 'flat', 'screen', 'tv', 'keurig', 'coffeemaker', 'paul', 'newman', 'coffee', 'product', 'writing', 'desk', 'chair', 'plush', 'bathroom', 'towel', 'sister', 'sky', 'toiletry', 'expanded', 'continental', 'breakfast', 'offered', 'array', 'cold', 'hot', 'cereal', 'fresh', 'fruit', 'hot', 'bacon', 'egg', 'cheese', 'wrap', 'juice', 'hot', 'beverage', 'fresh', 'belgian', 'waffle', 'pastry', 'muffin', 'bagel', 'actual', 'bagel', 'slicer', 'highly', 'recommend', 'room', 'balcony', 'step', 'experience', 'ambiance', 'area', 'seattle', 'transportation', 'system', 'convenient', 'taxi', 'reasonable', 'otherwise', 'parking', 'hard', 'find', 'expensive', 'plan', 'make', 'trip', 'seattle', 'great', 'place', 'stay', 'convenient', 'transportation', 'stayed', 'nice', 'hotel', 'recently', 'night', 'great', 'location', 'walking', 'distance', 'football', 'stadium', 'football', 'game', 'shop', 'restaurant', 'plus', 'pier', 'pike', 'market', 'took', 'light', 'rail', 'airport', 'get', 'hotel', 'get', 'pioneer', 'square', 'stop', 'walk', 'block', 'hotel', 'lot', 'luggage', 'may', 'easy', 'customer', 'service', 'hotel', 'excellent', 'staff', 'encountered', 'friendly', 'helpful', 'room', 'clean', 'comfortable', 'everything', 'needed', 'used', 'city', 'noise', 'might', 'like', 'location', 'little', 'noisy', 'street', 'surrounding', 'hotel', 'calm', 'overnight', 'bothered', 'noise', 'good', 'night', 'sleep', 'every', 'night', 'morning', 'breakfast', 'good', 'nothing', 'fancy', 'good', 'selection', 'pleasant', 'stay', 'stay', 'next', 'trip', 'seattle', 'train', 'got', 'u', 'seattle', 'morning', 'hotel', 'convenient', 'station', 'room', 'ready', 'u', 'beautiful', 'room', 'great', 'furnishing', 'cooky', 'milk', 'delivered', 'room', 'check', 'later', 'checked', 'see', 'needed', 'towel', 'great', 'staff', 'great', 'place', 'liked', 'way', 'room', 'set', 'customer', 'service', 'excellent', 'enjoyed', 'close', 'train', 'station', 'attraction', 'saw', 'breakfast', 'great', 'everyone', 'lively', 'friendly', 'enjoyed', 'stay', 'thank', 'train', 'travel', 'consultant', 'ted', 'sylvia', 'blishak', 'landing', 'fine', 'little', 'hotel', 'one', 'best', 'seen', 'u', 'convenient', 'train', 'station', 'two', 'night', 'comfortable', 'really', 'helped', 'u', 'prepare', 'canadian', 'transcontinental', 'train', 'would', 'board', 'day', 'ahead', 'hotel', 'almost', 'tucked', 'away', 'side', 'street', 'cabbie', 'bit', 'challenge', 'finding', 'check', 'flawless', 'received', 'large', 'well', 'appointed', 'room', 'top', 'floor', 'best', 'western', 'frequent', 'guest', 'card', 'helped', 'upgrade', 'although', 'considerable', 'construction', 'noise', 'underground', 'tunneling', 'operation', 'shut', 'promptly', 'sleepless', 'seattle', 'best', 'western', 'morning', 'breakfast', 'offering', 'good', 'providing', 'enough', 'tasty', 'sustenance', 'make', 'lunch', 'hand', 'many', 'trendy', 'restaurant', 'abound', 'within', 'neighboring', 'block', 'historic', 'district', 'choice', 'hotel', 'also', 'relatively', 'close', 'sport', 'stadium', 'downtown', 'shopping', 'pike', 'place', 'market', 'mile', 'hike', 'away', 'caught', 'vancouver', 'bc', 'train', 'second', 'morning', 'advise', 'allowing', 'extra', 'time', 'get', 'station', 'due', 'construction', 'impediment', 'drawback', 'people', 'coming', 'car', 'site', 'parking', 'inconvenient', 'complicated', 'expensive', 'bottom', 'line', 'definitely', 'best', 'destination', 'folk', 'arriving', 'rail', 'also', 'likely', 'one', 'best', 'kept', 'lodging', 'secret', 'seattle', 'coming', 'car', 'parking', 'situation', 'causing', 'nevertheless', 'highly', 'recommend', 'pioneer', 'square', 'best', 'western', 'next', 'visit', 'seattle', 'stayed', 'june', 'clean', 'comfortable', 'room', 'great', 'rate', 'breakfast', 'basic', 'included', 'best', 'thing', 'hotel', 'service', 'guest', 'service', 'associate', 'incredibly', 'helpful', 'went', 'way', 'make', 'sure', 'accommodation', 'suitable', 'exceeded', 'suitable', 'great', 'location', 'city', 'picked', 'hotel', 'simply', 'location', 'daughter', 'apartment', 'downtown', 'would', 'stay', 'even', 'live', 'close', 'people', 'friendly', 'even', 'arrived', 'midnight', 'first', 'thing', 'morning', 'room', 'clean', 'picky', 'everyday', 'returned', 'breakfast', 'norm', 'dining', 'area', 'staffed', 'sightseeing', 'would', 'say', 'location', 'excellent', 'well', 'back', 'sure', 'loved', 'location', 'public', 'transportation', 'good', 'need', 'car', 'hotel', 'lovely', 'room', 'quiet', 'clean', 'bathroom', 'sparkled', 'great', 'shower', 'king', 'size', 'bed', 'comfortable', 'ate', 'complimentary', 'breakfast', 'every', 'morning', 'stay', 'lot', 'healthy', 'choice', 'fresh', 'fruit', 'liked', 'staff', 'friendly', 'reccomended', 'great', 'restaurant', 'ever', 'wonder', 'comment', 'submit', 'make', 'hotel', 'reservation', 'read', 'well', 'hotel', 'hotel', 'great', 'location', 'walk', 'everything', 'along', 'waterfront', 'pike', 'place', 'market', 'football', 'baseball', 'stadium', 'many', 'great', 'place', 'eat', 'club', 'go', 'far', 'time', 'room', 'lovely', 'paid', 'city', 'view', 'glad', 'french', 'door', 'opened', 'onto', 'balcony', 'wide', 'ledge', 'window', 'view', 'puget', 'sound', 'ferry', 'coming', 'going', 'king', 'bed', 'comfy', 'quiet', 'high', 'ceiling', 'staff', 'helpful', 'parking', 'ask', 'stay', 'great', 'clean', 'room', 'frig', 'close', 'eveything', 'downtown', 'area', 'came', 'new', 'car', 'show', 'quest', 'feild', 'ansd', 'able', 'walk', 'every', 'weekend', 'great', 'restaurant', 'bar', 'also', 'within', 'walking', 'distance', 'come', 'city', 'seattle', 'time', 'year', 'stay', 'location', 'great', 'bed', 'good', 'everything', 'else', 'alright', 'could', 'hear', 'people', 'room', 'u', 'fail', 'minimally', 'helpful', 'staff', ...], ['great', 'service', 'room', 'clean', 'could', 'use', 'queen', 'bed', 'two', 'bed', 'room', 'otherwise', 'great', 'great', 'price', 'location', 'would', 'definitely', 'go', 'back', 'make', 'sure', 'try', 'zeets', 'pizza', 'amazing', 'give', 'kid', 'pizza', 'dough', 'play', 'wait', 'room', 'clean', 'hotel', 'conveniently', 'located', 'close', 'restaurant', 'shop', 'close', 'downtown', 'service', 'good', 'room', 'rate', 'good', 'recommend', 'friend', 'breakfast', 'alright', 'nice', 'location', 'visiting', 'seattle', 'center', 'downtown', 'good', 'breakfast', 'nice', 'staff', 'room', 'little', 'small', 'u', 'clean', 'cozy', 'nice', 'workout', 'room', 'whirlpool', 'hot', 'tub', 'available', 'completed', 'stay', 'best', 'western', 'loyal', 'inn', 'within', 'seattle', 'washington', 'disappointeed', 'due', 'number', 'factor', 'majority', 'began', 'day', 'first', 'disclaimer', 'staff', 'hotel', 'offer', 'correct', 'issue', 'discus', 'fact', 'occurred', 'first', 'place', 'present', 'demonstrated', 'paying', 'attention', 'room', 'upkeep', 'best', 'western', 'may', 'better', 'condition', 'one', 'certainly', 'lacking', 'price', 'key', 'selecting', 'hotel', 'well', 'brand', 'name', 'make', 'difference', 'found', 'year', 'travel', 'upon', 'arrival', 'told', 'check', 'pm', 'also', 'told', 'reserved', 'room', 'paid', 'would', 'ready', 'time', 'common', 'excuse', 'took', 'staff', 'day', 'prepare', 'various', 'room', 'room', 'unavailable', 'late', 'day', 'becoming', 'serious', 'concern', 'many', 'hotel', 'pm', 'mean', 'lost', 'day', 'without', 'place', 'stay', 'even', 'though', 'paying', 'day', 'latest', 'hour', 'ever', 'advised', 'stayed', 'countless', 'hotel', 'year', 'road', 'expressing', 'thought', 'desk', 'switched', 'different', 'room', 'ready', 'checked', 'bed', 'layout', 'originally', 'reserved', 'heat', 'froze', 'night', 'got', 'turned', 'heater', 'first', 'rattled', 'loudly', 'proceeded', 'blow', 'nothing', 'cold', 'air', 'regardless', 'dial', 'setting', 'stripped', 'bed', 'cover', 'keep', 'warm', 'night', 'obtained', 'blanket', 'desk', 'next', 'day', 'bedding', 'consisted', 'clean', 'sheet', 'thin', 'pink', 'blanket', 'would', 'keep', 'corpse', 'warm', 'sink', 'stopped', 'day', 'sink', 'failed', 'drain', 'fill', 'water', 'would', 'wait', 'minute', 'empty', 'finishing', 'washing', 'staff', 'notified', 'wanted', 'send', 'repair', 'people', 'room', 'gone', 'declined', 'offer', 'stated', 'staff', 'try', 'make', 'thing', 'right', 'changing', 'room', 'stopping', 'schedule', 'multiple', 'issue', 'repaired', 'something', 'would', 'like', 'addressed', 'arrival', 'leave', 'hour', 'paying', 'siren', 'siren', 'vehicle', 'constant', 'least', 'passing', 'window', 'hour', 'night', 'back', 'hotel', 'night', 'better', 'siren', 'night', 'thru', 'transient', 'kid', 'alley', 'rear', 'hotel', 'several', 'transient', 'young', 'people', 'yelling', 'pm', 'unknown', 'reason', 'perhaps', 'anger', 'resident', 'hotel', 'good', 'job', 'night', 'showed', 'improvement', 'raining', 'one', 'guy', 'time', 'singing', 'loud', 'directly', 'n', 'w', 'breakfast', 'let', 'see', 'egg', 'fried', 'hard', 'perfect', 'circle', 'placed', 'metal', 'container', 'clear', 'plastic', 'lid', 'cold', 'placed', 'inside', 'microwave', 'heat', 'meat', 'sad', 'stack', 'packaged', 'ham', 'chunk', 'pressed', 'meat', 'inside', 'container', 'clear', 'plastic', 'lid', 'type', 'meat', 'present', 'pressed', 'ham', 'bit', 'made', 'rectangular', 'slice', 'cereal', 'dispenser', 'mounted', 'vertically', 'bagel', 'good', 'white', 'bread', 'loaf', 'bag', 'milk', 'cold', 'tasty', 'staff', 'cleaning', 'woman', 'present', 'kind', 'helpful', 'gave', 'cash', 'tip', 'later', 'left', 'one', 'room', 'cleaning', 'staff', 'well', 'issue', 'discussed', 'fault', 'left', 'breakfast', 'room', 'reflected', 'bacon', 'fresh', 'egg', 'everything', 'pre', 'cooked', 'dumped', 'container', 'various', 'cheese', 'cold', 'cut', 'meat', 'described', 'bare', 'basic', 'food', 'found', 'motel', 'sigh', 'room', 'clean', 'enough', 'issue', 'modern', 'date', 'given', 'price', 'good', 'condition', 'clean', 'towel', 'shower', 'fine', 'adjusted', 'water', 'hot', 'wi', 'fi', 'job', 'day', 'open', 'parking', 'lot', 'alley', 'street', 'fencing', 'security', 'system', 'secured', 'parking', 'structure', 'lesson', 'learned', 'get', 'pay', 'used', 'airline', 'mile', 'location', 'night', 'stayed', 'hampton', 'inn', 'hilton', 'usually', 'even', 'airline', 'mile', 'time', 'around', 'tried', 'cut', 'budget', 'since', 'seattle', 'paid', 'price', 'happen', 'best', 'western', 'jm', 'oregon', 'family', 'stayed', 'two', 'night', 'liked', 'central', 'location', 'walked', 'downtown', 'next', 'morning', 'took', 'cab', 'ride', 'pike', 'place', 'actually', 'cheaper', 'took', 'bus', 'staff', 'friendly', 'helpfull', 'especially', 'young', 'man', 'checked', 'u', 'thursday', 'evening', 'loved', 'continental', 'buffet', 'breakfast', 'included', 'stay', 'offer', 'huge', 'varriety', 'choice', 'fresh', 'waffle', 'fruit', 'yogurt', 'egg', 'ham', 'wife', 'find', 'convienant', 'child', 'love', 'choice', 'ok', 'kind', 'know', 'getting', 'pay', 'little', 'hotel', 'location', 'hotel', 'central', 'action', 'best', 'part', 'hotel', 'location', 'walked', 'pioneer', 'square', 'lake', 'union', 'westlake', 'center', 'freemont', 'quite', 'hike', 'nice', 'walk', 'along', 'lake', 'along', 'point', 'reach', 'seattle', 'downtown', 'hot', 'spot', 'easily', 'love', 'public', 'transportation', 'seattle', 'particularly', 'light', 'rail', 'airport', 'downtown', 'hotel', 'take', 'light', 'rail', 'sea', 'last', 'stop', 'westlake', 'still', 'mile', 'walk', 'lot', 'baggage', 'biggest', 'drawback', 'location', 'three', 'option', 'westlake', 'used', 'light', 'rail', 'get', 'take', 'taxi', 'expensive', 'since', 'short', 'hop', 'may', 'best', 'lot', 'bag', 'hop', 'south', 'lake', 'union', 'transit', 'street', 'car', 'south', 'westlake', 'get', 'walk', 'short', 'way', 'street', 'hotel', 'pack', 'light', 'walk', 'westlake', 'next', 'best', 'thing', 'people', 'staff', 'nice', 'attentive', 'toilet', 'broke', 'day', 'seven', 'day', 'stay', 'fixed', 'quickly', 'room', 'seemed', 'cleaned', 'reasonably', 'well', 'breakfast', 'bar', 'adequate', 'typical', 'free', 'breakfast', 'food', 'open', 'exactly', 'time', 'one', 'minute', 'early', 'head', 'bit', 'early', 'get', 'jump', 'thing', 'hallway', 'floor', 'stank', 'idea', 'stench', 'first', 'arrived', 'concerned', 'room', 'smelling', 'like', 'room', 'smell', 'hallway', 'held', 'breath', 'went', 'problem', 'solved', 'room', 'noise', 'fairly', 'high', 'needed', 'use', 'earplug', 'wall', 'seem', 'thin', 'outside', 'room', 'lot', 'siren', 'area', 'night', 'long', 'know', 'group', 'young', 'kid', 'arrived', 'partway', 'week', 'antic', 'also', 'added', 'ambient', 'noise', 'inside', 'temperature', 'control', 'room', 'cooler', 'heater', 'seem', 'hold', 'steady', 'temp', 'wake', 'night', 'either', 'roasting', 'freezing', 'setting', 'light', 'invasion', 'hallway', 'high', 'door', 'fit', 'tightly', 'frame', 'allowed', 'lot', 'hallway', 'light', 'room', 'thumb', 'squarely', 'middle', 'know', 'getting', 'accept', 'downside', 'cheap', 'downtown', 'seattle', 'room', 'place', 'good', 'value', 'set', 'expectation', 'appropriately', 'hotel', 'close', 'seattle', 'space', 'needle', 'walking', 'distance', 'many', 'downtown', 'seattle', 'attraction', 'offer', 'free', 'wifi', 'breakfast', 'make', 'great', 'deal', 'breakfast', 'better', 'expected', 'assortment', 'cereal', 'oatmeal', 'waffle', 'fruit', 'various', 'item', 'however', 'room', 'less', 'expected', 'first', 'room', 'third', 'floor', 'horrible', 'experience', 'taking', 'shower', 'heat', 'triggered', 'smoke', 'detector', 'start', 'ringing', 'run', 'shower', 'throw', 'clothes', 'go', 'front', 'desk', 'get', 'new', 'room', 'oh', 'soap', 'shampoo', 'conditioner', 'come', 'standard', 'small', 'bottle', 'see', 'hotel', 'big', 'dispenser', 'attached', 'shower', 'know', 'putting', 'seem', 'sanitary', 'second', 'room', 'worked', 'ok', 'stay', 'seattle', 'would', 'go', 'somewhere', 'else', 'bit', 'nicer', 'pretty', 'full', 'breakfast', 'bar', 'quiet', 'location', 'denny', 'way', 'close', 'jazz', 'alley', 'many', 'good', 'restaurant', 'make', 'hotel', 'great', 'plus', 'three', 'block', 'whole', 'food', 'gallery', 'honeychurch', 'booked', 'night', 'hotel', 'people', 'friend', 'room', 'queen', 'bed', 'room', 'bf', 'queen', 'bed', 'sheet', 'clean', 'bed', 'comfortable', 'room', 'tv', 'c', 'safety', 'box', 'hair', 'dryer', 'bathroom', 'also', 'clean', 'soap', 'shampoo', 'dispenser', 'room', 'spacious', 'getting', 'ready', 'freak', 'night', 'concert', 'seattle', 'mile', 'wamu', 'theater', 'front', 'desk', 'person', 'named', 'chris', 'helpful', 'let', 'u', 'know', 'go', 'breakfast', 'morning', 'seemed', 'nice', 'helpful', 'overall', 'guest', 'coming', 'halloween', 'weekend', 'hotel', 'also', 'offer', 'continental', 'breakfast', 'friend', 'said', 'waffle', 'good', 'parking', 'per', 'car', 'felt', 'safe', 'knowing', 'going', 'get', 'ticket', 'felt', 'like', 'car', 'get', 'broken', 'would', 'recommend', 'staying', 'couple', 'night', 'need', 'something', 'basic', 'expensive', 'clean', 'close', 'restaurant', 'etc', 'also', 'good', 'party', 'spot', 'able', 'get', 'friend', 'take', 'room', 'next', 'lot', 'fun', 'thank', 'best', 'western', 'loyal', 'inn', 'impressed', 'hotel', 'seattle', 'probably', 'look', 'elsewhere', 'return', 'pro', 'parking', 'within', 'walking', 'distance', 'downtown', ...], ['beautiful', 'view', 'space', 'needle', 'especially', 'night', 'like', 'photography', 'ask', 'room', 'view', 'staff', 'great', 'local', 'restuarant', 'excellent', 'secure', 'parking', 'plus', 'free', 'wi', 'fi', 'issue', 'waking', 'conference', 'call', 'could', 'find', 'internet', 'password', 'called', 'front', 'desk', 'man', 'duty', 'would', 'give', 'insisited', 'come', 'get', 'person', 'tried', 'convince', 'dressed', 'claimed', 'policy', 'guest', 'come', 'collect', 'password', 'desk', 'got', 'dressed', 'went', 'downstairs', 'get', 'ridiculous', 'seriously', 'irritated', 'anyway', 'spoke', 'day', 'staff', 'seemed', 'shocked', 'hotel', 'policy', 'keep', 'code', 'safe', 'intending', 'see', 'king', 'tutankhamen', 'treasure', 'pacific', 'science', 'center', 'leaf', 'january', 'time', 'getting', 'short', 'decided', 'better', 'purchase', 'vip', 'ticket', 'go', 'specific', 'time', 'stand', 'line', 'opted', 'hotel', 'due', 'proximity', 'seattle', 'center', 'dissapointed', 'secure', 'underground', 'parking', 'space', 'needle', 'view', 'king', 'room', 'pleased', 'hotel', 'bit', 'older', 'well', 'kept', 'updated', 'furniture', 'wise', 'well', 'room', 'adjoining', 'room', 'group', 'next', 'door', 'bit', 'loud', 'think', 'door', 'thick', 'enough', 'sound', 'proof', 'enough', 'two', 'room', 'hotel', 'staff', 'efficient', 'helpful', 'package', 'came', 'free', 'breakfast', 'brella', 'restaurant', 'inside', 'hotel', 'passed', 'breakfast', 'nothing', 'write', 'home', 'much', 'better', 'breakfast', 'hotel', 'included', 'cost', 'room', 'feel', 'sorry', 'people', 'paying', 'breakfast', 'top', 'cost', 'room', 'offering', 'much', 'different', 'hotel', 'good', 'sausage', 'slimy', 'egg', 'stiff', 'dry', 'hash', 'brown', 'slimy', 'good', 'thing', 'waffle', 'made', 'hot', 'spot', 'blessed', 'decent', 'weather', 'another', 'surprise', 'seattle', 'center', 'dale', 'chihuly', 'garden', 'glass', 'exhibit', 'added', 'year', 'arrived', 'saw', 'garden', 'bit', 'sunlight', 'left', 'experienced', 'dark', 'fantastic', 'hotel', 'excellent', 'location', 'would', 'recommend', 'space', 'needle', 'view', 'however', 'end', 'hallway', 'get', 'small', 'window', 'offer', 'free', 'breakfast', 'buffet', 'best', 'western', 'member', 'otherwise', 'pay', 'good', 'buffet', 'excellent', 'seating', 'v', 'best', 'western', 'room', 'nice', 'pay', 'resonable', 'compared', 'lodging', 'closer', 'downtown', 'walking', 'distant', 'monorail', 'take', 'downtown', 'however', 'plan', 'driving', 'around', 'may', 'want', 'look', 'another', 'location', 'parking', 'limited', 'anything', 'going', 'seattle', 'may', 'find', 'street', 'parking', 'block', 'away', 'left', 'one', 'night', 'parking', 'full', 'counter', 'personnel', 'suggested', 'lot', 'two', 'block', 'charged', 'hour', 'happy', 'camper', 'walking', 'issue', 'defiantly', 'would', 'worked', 'well', 'accommodation', 'wall', 'thin', 'unless', 'turn', 'heater', 'feel', 'like', 'sleeping', 'sheet', 'light', 'blanket', 'pull', 'closet', 'suggest', 'hotel', 'restaurant', 'front', 'desk', 'steered', 'u', 'better', 'food', 'husband', 'stayed', 'saturday', 'would', 'recommend', 'others', 'staff', 'friendly', 'quiet', 'relaxing', 'room', 'clean', 'bed', 'comfortable', 'good', 'price', 'close', 'space', 'needle', 'would', 'definately', 'stay', 'next', 'time', 'go', 'seattle', 'overall', 'great', 'hotel', 'dong', 'quite', 'bit', 'traveling', 'since', 'retired', 'end', 'july', 'best', 'wester', 'plus', 'executive', 'inn', 'one', 'favorite', 'staff', 'attitude', 'make', 'stay', 'great', 'experience', 'wonderful', 'time', 'thanks', 'helpful', 'staff', 'te', 'great', 'giving', 'u', 'direction', 'advise', 'go', 'get', 'seattle', 'awesome', 'location', 'great', 'view', 'room', 'clean', 'well', 'stocked', 'wifi', 'flawless', 'short', 'one', 'night', 'stay', 'average', 'nothing', 'complain', 'nothing', 'brag', 'either', 'feel', 'plus', 'status', 'hotel', 'marketing', 'stretch', 'give', 'credit', 'property', 'location', 'location', 'location', 'easy', 'walk', 'many', 'seattle', 'attraction', 'around', 'space', 'needle', 'reserved', 'july', 'occupancy', 'room', 'queen', 'bed', 'traveling', 'adult', 'son', 'november', 'concert', 'key', 'arena', 'good', 'thing', 'say', 'close', 'handy', 'concert', 'arrived', 'check', 'told', 'room', 'bed', 'roll', 'away', 'sent', 'saddest', 'bed', 'ever', 'saw', 'delivered', 'rude', 'housekeeper', 'acted', 'mad', 'bring', 'u', 'bed', 'extra', 'blanket', 'pillow', 'even', 'offer', 'set', 'bed', 'room', 'floor', 'elevator', 'noisy', 'setting', 'heard', 'guest', 'housekeeper', 'coming', 'going', 'view', 'roof', 'top', 'neighboring', 'building', 'lower', 'parking', 'area', 'good', 'place', 'nearby', 'eat', 'nice', 'shower', 'lot', 'water', 'pressure', 'though', 'tub', 'drain', 'stayed', 'night', 'went', 'rush', 'concert', 'key', 'arena', 'excellent', 'concert', 'way', 'location', 'perfect', 'contrary', 'review', 'trouble', 'finding', 'excellent', 'view', 'space', 'needle', 'floor', 'room', 'yes', 'older', 'hotel', 'need', 'reno', 'understand', 'working', 'room', 'plenty', 'space', 'everything', 'worked', 'well', 'main', 'issue', 'noise', 'coming', 'guest', 'next', 'door', 'one', 'night', 'child', 'loud', 'next', 'someone', 'talking', 'loud', 'morning', 'may', 'adjoining', 'room', 'next', 'time', 'would', 'request', 'room', 'connecting', 'door', 'lesson', 'learned', 'breakfast', 'better', 'many', 'get', 'best', 'western', 'plenty', 'choice', 'get', 'bored', 'day', 'stay', 'food', 'restaurant', 'evening', 'rather', 'bland', 'ate', 'nice', 'fridge', 'microwave', 'room', 'always', 'ask', 'fridge', 'least', 'staff', 'hotel', 'always', 'polite', 'friendly', 'even', 'line', 'guest', 'waiting', 'seen', 'also', 'impressed', 'manager', 'see', 'responds', 'review', 'doubt', 'comment', 'suggestion', 'future', 'bw', 'plus', 'proper', 'glass', 'mug', 'well', 'disposable', 'option', 'seen', 'report', 'cleaned', 'place', 'guest', 'wash', 'also', 'think', 'advising', 'guest', 'room', 'connecting', 'door', 'next', 'room', 'decide', 'whether', 'stay', 'room', 'hotel', 'great', 'location', 'view', 'space', 'needle', 'within', 'easy', 'walking', 'distance', 'monorail', 'downtown', 'service', 'patchy', 'however', 'lobby', 'room', 'little', 'dingy', 'need', 'modernization', 'particularly', 'view', 'price', 'parking', 'extra', 'also', 'get', 'rate', 'includes', 'breakfast', 'although', 'breakfast', 'nothing', 'special', 'bar', 'nice', 'selection', 'locally', 'brewed', 'ale', 'tap', 'wanted', 'place', 'close', 'museum', 'attraction', 'near', 'space', 'needle', 'took', 'advantage', 'hotel', 'king', 'tut', 'package', 'hotel', 'literally', 'two', 'block', 'everything', 'price', 'better', 'others', 'checked', 'online', 'parked', 'car', 'hotel', 'move', 'entire', 'time', 'night', 'one', 'big', 'advantage', 'staying', 'king', 'tut', 'package', 'gave', 'u', 'vip', 'ticket', 'meant', 'could', 'go', 'see', 'exhibit', 'time', 'open', 'rather', 'date', 'time', 'specific', 'ticket', 'motel', 'room', 'clean', 'adequate', 'spend', 'much', 'time', 'view', 'room', 'pretty', 'blah', 'overlooking', 'parking', 'lot', 'except', 'get', 'watch', 'one', 'really', 'big', 'building', 'crane', 'operation', 'aware', 'least', 'part', 'seattle', 'seemed', 'construction', 'mode', 'hotel', 'fault', 'awakened', 'one', 'morning', 'non', 'stop', 'jack', 'hammering', 'street', 'even', 'earlier', 'second', 'morning', 'arrival', 'garbage', 'truck', 'plus', 'side', 'room', 'refrigerator', 'microwave', 'arm', 'chairm', 'bathroom', 'tiny', 'try', 'sit', 'toilet', 'close', 'door', 'time', 'comment', 'maid', 'service', 'say', 'respect', 'privacy', 'clean', 'room', 'since', 'put', 'disturb', 'sign', 'leave', 'u', 'note', 'day', 'telling', 'u', 'want', 'anything', 'serviced', 'let', 'front', 'desk', 'know', 'thought', 'nice', 'way', 'handle', 'breakfast', 'hotel', 'restaurant', 'morning', 'convenience', 'first', 'day', 'part', 'package', 'good', 'variety', 'make', 'breakfast', 'burrito', 'waffle', 'oatmeal', 'bacon', 'etc', 'although', 'exact', 'choice', 'day', 'got', 'little', 'boring', 'third', 'morning', 'breakfast', 'family', 'stay', 'another', 'hotel', 'area', 'earlier', 'year', 'surprised', 'air', 'conditioning', 'hotel', 'air', 'conditioning', 'worked', 'fine', 'definitely', 'adequate', 'place', 'reasonable', 'price', 'seattle', 'super', 'location', 'stayed', 'three', 'night', 'enjoyed', 'every', 'moment', 'room', 'location', 'helpful', 'staff', 'cleanliness', 'value', 'comfort', 'everything', 'spot', 'staff', 'friendly', 'helpful', 'highly', 'recommended', 'return', 'wanted', 'hotel', 'near', 'space', 'needle', 'knew', 'traffic', 'would', 'nite', 'mare', 'trying', 'find', 'place', 'hard', 'check', 'horrific', 'person', 'come', 'really', 'took', 'minute', 'hour', 'drive', 'beyond', 'comprehension', 'got', 'lucky', 'got', 'room', 'view', 'without', 'pay', 'extra', 'night', 'helped', 'little', 'bit', 'hall', 'room', 'dirty', 'bed', 'oh', 'goodness', 'horrible', 'uncomfortable', 'son', 'said', 'felt', 'like', 'really', 'big', 'person', 'slept', 'need', 'replaced', 'spring', 'totally', 'broken', 'pleased', 'breakfast', 'day', 'paid', 'day', 'change', 'closed', 'exactly', 'exception', 'mon', 'afternoon', 'thurs', 'put', 'complaint', 'card', 'got', 'e', 'mail', 'response', 'replied', 'back', 'nothing', 'sure', 'management', 'anything', 'night', 'almost', 'mortgage', 'payment', 'thought', 'would', 'better', 'room', 'ever', 'worried', 'next', 'night', 'best', 'western', 'portland', 'let', 'see', 'checked', 'best', 'western', 'executive', 'part', 'blackball', 'ferry', 'package', 'hotel', ...], ['hotel', 'need', 'serious', 'update', 'room', 'big', 'bed', 'comfortable', 'carpet', 'worn', 'hesitate', 'walk', 'bare', 'foot', 'wall', 'paper', 'peeling', 'black', 'mark', 'wall', 'door', 'disappointing', 'frustrating', 'thing', 'stay', 'poor', 'water', 'pressure', 'lukewarm', 'water', 'driving', 'hr', 'getting', 'late', 'looking', 'forward', 'nice', 'hot', 'shower', 'happen', 'glad', 'staying', 'night', 'leaving', 'morning', 'would', 'checked', 'gone', 'another', 'hotel', 'nosie', 'level', 'pretty', 'high', 'could', 'hear', 'people', 'walking', 'hall', 'waking', 'morning', 'alaska', 'airline', 'provided', 'voucher', 'comfort', 'inn', 'delay', 'caused', 'u', 'miss', 'last', 'leg', 'flight', 'disappointment', 'place', 'poor', 'condition', 'smell', 'bad', 'front', 'lobby', 'hallway', 'guest', 'room', 'contacting', 'let', 'u', 'know', 'needed', 'ride', 'airport', 'even', 'though', 'advertise', 'pick', 'ups', 'every', 'minute', 'still', 'took', 'minute', 'shuttle', 'arrived', 'place', 'less', 'minute', 'airport', 'switch', 'room', 'housekeeping', 'somehow', 'missed', 'bed', 'made', 'looked', 'like', 'pit', 'fruit', 'bed', 'sheet', 'gross', 'good', 'bad', 'thing', 'hotel', 'internet', 'terrible', 'towel', 'good', 'water', 'pressure', 'good', 'room', 'decent', 'size', 'nice', 'dark', 'bed', 'comfortable', 'staff', 'friendly', 'location', 'convenient', 'though', 'neighborhood', 'seem', 'great', 'problem', 'regarding', 'though', 'stayed', 'two', 'night', 'visiting', 'seattle', 'october', 'little', 'worried', 'review', 'mixed', 'pleased', 'found', 'room', 'large', 'immaculate', 'comfortable', 'everything', 'room', 'entire', 'hotel', 'looked', 'like', 'well', 'maintained', 'even', 'recently', 'painted', 'walking', 'corridor', 'room', 'rug', 'bit', 'lint', 'always', 'hate', 'rug', 'clean', 'wall', 'dirty', 'might', 'well', 'stay', 'home', 'case', 'another', 'reviewer', 'mentioned', 'area', 'know', 'expect', 'found', 'area', 'fine', 'busy', 'street', 'heart', 'area', 'seattle', 'lot', 'store', 'shop', 'along', 'avenue', 'find', 'seedy', 'fact', 'needed', 'use', 'room', 'key', 'use', 'elevator', 'felt', 'safe', 'would', 'recommend', 'hotel', 'mixed', 'one', 'night', 'stay', 'comfort', 'inn', 'check', 'clerk', 'friendly', 'although', 'next', 'day', 'clerk', 'much', 'room', 'pretty', 'large', 'relatively', 'clean', 'good', 'internet', 'service', 'breakfast', 'quite', 'offering', 'bad', 'thing', 'location', 'choose', 'hotel', 'visiting', 'business', 'hotel', 'chosen', 'neighborhood', 'sketchy', 'drive', 'several', 'mile', 'nearby', 'shopping', 'mall', 'find', 'restaurant', 'good', 'option', 'people', 'traveling', 'issue', 'cleanliness', 'room', 'mine', 'ok', 'great', 'thing', 'seattle', 'area', 'fast', 'neighborhood', 'change', 'one', 'looking', 'affordable', 'place', 'stay', 'outside', 'spendy', 'area', 'comfort', 'suite', 'work', 'stayed', 'suite', 'less', 'single', 'double', 'bed', 'mile', 'closer', 'space', 'needle', 'work', 'sure', 'drive', 'may', 'leave', 'wondering', 'headed', 'aurora', 'ave', 'rest', 'assured', 'get', 'work', 'nice', 'stay', 'ken', 'arrived', 'midnight', 'greeted', 'friendly', 'welcoming', 'smile', 'although', 'way', 'past', 'normal', 'person', 'bed', 'time', 'gentleman', 'checking', 'u', 'took', 'time', 'help', 'u', 'rate', 'since', 'staying', 'long', 'period', 'time', 'also', 'helpful', 'giving', 'u', 'suggestion', 'really', 'late', 'night', 'bite', 'eat', 'retired', 'night', 'room', 'little', 'small', 'fine', 'husband', 'able', 'hear', 'people', 'u', 'walking', 'around', 'disruptive', 'time', 'parking', 'lot', 'little', 'small', 'well', 'fine', 'full', 'size', 'rental', 'car', 'location', 'good', 'easy', 'access', 'direction', 'short', 'drive', 'away', 'main', 'seattle', 'attraction', 'visited', 'watch', 'cousin', 'play', 'football', 'uw', 'frequented', 'university', 'district', 'close', 'distance', 'well', 'pleasant', 'stay', 'would', 'given', 'excellent', 'rating', 'noise', 'people', 'walking', 'u', 'husband', 'definitely', 'staying', 'future', 'visit', 'seattle', 'looking', 'good', 'hotel', 'without', 'paying', 'arm', 'leg', 'chose', 'comfort', 'inn', 'aurora', 'ave', 'night', 'tax', 'etc', 'easy', 'drive', 'airport', 'route', 'fact', 'took', 'u', 'minute', 'get', 'airport', 'flight', 'left', 'front', 'desk', 'staff', 'great', 'quick', 'check', 'room', 'better', 'average', 'room', 'clean', 'neat', 'time', 'stayed', 'turn', 'booked', 'first', 'last', 'night', 'wa', 'also', 'great', 'breakfast', 'buffet', 'likely', 'return', 'visiting', 'future', 'wife', 'booked', 'hotel', 'online', 'website', 'misleading', 'hotel', 'middle', 'industrial', 'area', 'nowhere', 'near', 'site', 'want', 'see', 'old', 'run', 'place', 'poor', 'condition', 'fit', 'anyone', 'like', 'comfortable', 'area', 'poor', 'seedy', 'want', 'stay', 'couple', 'bring', 'kid', 'way', 'stay', 'away', 'one', 'worth', 'time', 'stayed', 'one', 'night', 'staff', 'reception', 'welcome', 'room', 'less', 'clean', 'breafast', 'guest', 'talking', 'tv', 'loud', 'background', 'music', 'hard', 'chat', 'couple', 'gym', 'closed', 'nothing', 'worked', 'bit', 'dirty', 'complaint', 'hotel', 'check', 'quick', 'courteous', 'paid', 'including', 'tax', 'good', 'sized', 'room', 'comfy', 'king', 'bed', 'nice', 'clean', 'wi', 'fi', 'worked', 'without', 'hitch', 'breakfast', 'better', 'hotel', 'average', 'egg', 'sausage', 'waffle', 'located', 'busy', 'north', 'aurora', 'ave', 'noise', 'problem', 'feel', 'bad', 'area', 'typical', 'busy', 'commercial', 'strip', 'average', 'looking', 'residential', 'area', 'starting', 'one', 'block', 'east', 'west', 'aurora', 'wife', 'walk', 'three', 'mile', 'day', 'exercise', 'walked', 'along', 'street', 'paralleling', 'aurora', 'roughly', 'concern', 'glitzy', 'hotel', 'served', 'purpose', 'would', 'return', 'wow', 'start', 'hotel', 'stayed', 'two', 'night', 'ago', 'firstly', 'area', 'little', 'rundown', 'super', 'unsafe', 'per', 'se', 'prefer', 'stay', 'thing', 'around', 'though', 'review', 'would', 'think', 'check', 'fine', 'super', 'friendly', 'fine', 'except', 'two', 'car', 'asking', 'another', 'parking', 'pas', 'saying', 'lot', 'get', 'full', 'check', 'gentleman', 'basically', 'ignored', 'request', 'second', 'parking', 'pas', 'like', 'social', 'skill', 'deal', 'saying', 'odd', 'get', 'room', 'huge', 'way', 'probably', 'good', 'thing', 'say', 'hotel', 'pubic', 'head', 'hair', 'bathroom', 'tub', 'behind', 'bathroom', 'door', 'like', 'swept', 'day', 'hair', 'bed', 'old', 'washed', 'blood', 'stain', 'absolute', 'worst', 'yes', 'worse', 'someone', 'else', 'pubes', 'turned', 'shower', 'water', 'sprayed', 'everywhere', 'sprayed', 'much', 'upwards', 'getting', 'water', 'part', 'roof', 'dripping', 'entire', 'bathroom', 'soaking', 'etc', 'called', 'front', 'desk', 'let', 'know', 'know', 'anything', 'ever', 'done', 'terrible', 'even', 'wash', 'hair', 'shower', 'nightmare', 'basically', 'shower', 'totally', 'unusable', 'paying', 'awful', 'hotel', 'breakfast', 'bad', 'got', 'rush', 'min', 'later', 'never', 'would', 'got', 'seat', 'since', 'definitely', 'enough', 'seating', 'seem', 'restocking', 'food', 'quickly', 'free', 'internet', 'worked', 'room', 'small', 'fitness', 'room', 'dinky', 'hot', 'tub', 'honestly', 'would', 'never', 'stay', 'comfort', 'inn', 'good', 'luck', 'need', 'pro', 'large', 'room', 'queen', 'lot', 'space', 'internet', 'signal', 'strong', 'room', 'con', 'parking', 'check', 'late', 'front', 'desk', 'clerk', 'caring', 'lot', 'hair', 'bathroom', 'next', 'tub', 'tub', 'budget', 'half', 'sized', 'pillow', 'never', 'seen', 'anything', 'like', 'alittle', 'worried', 'reading', 'review', 'booked', 'king', 'size', 'suite', 'sofa', 'bed', 'since', 'four', 'adult', 'spending', 'one', 'night', 'cruise', 'hotel', 'great', 'value', 'money', 'since', 'want', 'spend', 'one', 'night', 'post', 'complaint', 'thin', 'wall', 'problem', 'hearing', 'people', 'breakfast', 'menu', 'several', 'item', 'food', 'good', 'several', 'pizza', 'place', 'deliver', 'room', 'since', 'restaruants', 'walking', 'distance', 'negative', 'linen', 'room', 'sofa', 'bed', 'called', 'desk', 'person', 'said', 'planning', 'sleeping', 'reservation', 'four', 'adult', 'one', 'night', 'bring', 'linen', 'pillow', 'opened', 'bed', 'bowed', 'middle', 'even', 'know', 'begin', 'tell', 'horrible', 'stay', 'u', 'start', 'saying', 'arrived', 'hotel', 'around', 'found', 'first', 'literally', 'parking', 'hotel', 'questionable', 'area', 'park', 'street', 'nervous', 'already', 'leaving', 'car', 'area', 'went', 'got', 'key', 'already', 'noticing', 'run', 'place', 'went', 'room', 'smell', 'hallway', 'stinky', 'fresh', 'kind', 'smelt', 'like', 'dog', 'pee', 'got', 'room', 'smell', 'bed', 'definitely', 'smelt', 'like', 'dog', 'pee', 'sickened', 'pet', 'u', 'enjoy', 'smelling', 'someone', 'elses', 'pet', 'reluctantly', 'called', 'front', 'desk', 'asked', 'room', 'could', 'switched', 'cold', 'rude', 'finally', 'said', 'come', 'another', 'key', 'went', 'second', 'room', 'family', 'never', 'unpacks', 'anything', 'checking', 'bed', 'stuff', 'room', 'carefully', 'bedbug', 'went', 'ahead', 'room', 'might', 'mention', 'also', 'smelled', 'moldy', 'upon', 'lifting', 'mattress', 'see', 'underneath', 'husband', 'found', 'bug', 'moving', 'freaked', 'u', 'never', 'actually', 'found', 'bug', 'went', 'told', 'desk', 'clerk', 'found', 'denied', 'made', 'u', 'feel', ...], ['experience', 'day', 'inn', 'perfect', 'staff', 'great', 'manager', 'ted', 'angel', 'helpful', 'complimentary', 'breakfast', 'always', 'hot', 'also', 'provided', 'bbq', 'grill', 'really', 'recommend', 'place', 'others', 'planning', 'staying', 'san', 'antonio', 'staff', 'front', 'desk', 'extremely', 'helpful', 'went', 'way', 'ensure', 'trip', 'enjoyable', 'attending', 'nephew', 'air', 'force', 'graduation', 'staff', 'gave', 'u', 'useful', 'information', 'make', 'navigation', 'base', 'easier', 'special', 'thanks', 'mr', 'angel', 'worked', 'front', 'desk', 'morning', 'departure', 'location', 'great', 'close', 'base', 'however', 'hotel', 'disgusting', 'dirty', 'roach', 'sure', 'still', 'open', 'never', 'ever', 'stay', 'location', 'location', 'risk', 'deal', 'environment', 'wish', 'people', 'would', 'mentioned', 'review', 'could', 'selected', 'different', 'hotel', 'happier', 'note', 'proud', 'graduate', 'congrats', 'share', 'feeling', 'pride', 'service', 'great', 'helpful', 'front', 'desk', 'matter', 'time', 'day', 'room', 'ok', 'bathroom', 'need', 'updating', 'bed', 'high', 'short', 'people', 'comfortable', 'would', 'stay', 'reserved', 'king', 'room', 'none', 'available', 'check', 'left', 'pizza', 'thrown', 'away', 'reason', 'know', 'son', 'would', 'enjoyed', 'location', 'location', 'location', 'get', 'issue', 'perfect', 'location', 'lackland', 'air', 'base', 'staff', 'outstanding', 'helpful', 'polite', 'friendly', 'staff', 'room', 'however', 'damp', 'feeling', 'dark', 'dingy', 'carpet', 'tub', 'room', 'needed', 'replaced', 'old', 'building', 'need', 'work', 'also', 'feel', 'safe', 'sometimes', 'although', 'problem', 'quiet', 'room', 'clean', 'min', 'downtown', 'asked', 'stair', 'close', 'parking', 'problem', 'tv', 'line', 'could', 'use', 'update', 'cannot', 'compliment', 'enough', 'employee', 'front', 'desk', 'ted', 'angel', 'honestly', 'went', 'beyond', 'came', 'giving', 'exact', 'direction', 'around', 'city', 'got', 'lost', 'airport', 'almost', 'hr', 'could', 'find', 'hotel', 'near', 'tear', 'point', 'ted', 'stayed', 'phone', 'u', 'directed', 'u', 'right', 'parking', 'lot', 'min', 'away', 'point', 'helpful', 'friendly', 'trip', 'let', 'employee', 'get', 'away', 'hard', 'find', 'hotel', 'cab', 'driver', 'get', 'parking', 'lot', 'room', 'ready', 'check', 'booked', 'online', 'disappointed', 'hotel', 'far', 'either', 'airport', 'conference', 'centre', 'staff', 'met', 'ground', 'thorough', 'courteous', 'mind', 'staying', 'walking', 'distance', 'conference', 'centre', 'general', 'manager', 'ash', 'day', 'inn', 'name', 'jon', 'family', 'stayed', 'day', 'inn', 'past', 'weekend', 'wanted', 'compliment', 'employee', 'jacob', 'thursday', 'night', 'checked', 'helpful', 'accommodating', 'exemplified', 'customer', 'service', 'seen', 'quite', 'say', 'great', 'employee', 'worth', 'favorable', 'review', 'express', 'room', 'nice', 'clean', 'bed', 'comfortable', 'except', 'bit', 'fresh', 'paint', 'top', 'great', 'room', 'host', 'enjoyed', 'complimentary', 'hot', 'breakfast', 'served', 'btw', 'never', 'asked', 'pay', 'parking', 'fee', 'wanted', 'say', 'thank', 'excellent', 'experience', 'sure', 'pas', 'recommendation', 'friend', 'regard', 'jon', 'place', 'good', 'far', 'cost', 'realize', 'day', 'park', 'yes', 'parking', 'lot', 'parking', 'garage', 'maybe', 'old', 'motel', 'like', 'parking', 'situation', 'guess', 'lot', 'going', 'san', 'antonio', 'come', 'put', 'price', 'room', 'good', 'time', 'nice', 'staff', 'hot', 'breakfast', 'comfortable', 'bed', 'wifi', 'cooling', 'heat', 'good', 'hot', 'shower', 'know', 'older', 'hotel', 'served', 'purpose', 'close', 'lackland', 'afb', 'hard', 'find', 'several', 'hotel', 'nearby', 'parking', 'easy', 'park', 'far', 'inner', 'section', 'pool', 'use', 'pool', 'nice', 'really', 'impressed', 'hot', 'breakfast', 'worry', 'go', 'eat', 'graduate', 'bmt', 'nice', 'close', 'upon', 'check', 'evening', 'receptionist', 'friendly', 'helpful', 'although', 'quite', 'people', 'checking', 'ahead', 'wait', 'time', 'minimal', 'friendly', 'courteous', 'everyone', 'room', 'look', 'attempted', 'upgrade', 'include', 'hdtv', 'refrigerator', 'hair', 'dryer', 'ironing', 'board', 'iron', 'bed', 'comfortable', 'room', 'clean', 'room', 'faced', 'pool', 'little', 'noisy', 'kid', 'playing', 'overall', 'value', 'good', 'family', 'husband', 'booked', 'priceline', 'day', 'room', 'double', 'queen', 'good', 'rate', 'staff', 'welcoming', 'friendly', 'helpful', 'liked', 'room', 'connected', 'u', 'family', 'stick', 'together', 'room', 'neatly', 'updated', 'hdtv', 'comfortable', 'bed', 'breakfast', 'area', 'small', 'great', 'denny', 'walking', 'distance', 'away', 'would', 'return', 'budget', 'oh', 'plus', 'got', 'little', 'gift', 'bag', 'appreciate', 'made', 'u', 'feel', 'welcome', 'thanked', 'guest', 'housekeeping', 'like', 'barge', 'letting', 'otherwise', 'totally', 'banging', 'door', 'view', 'window', 'brick', 'wall', 'swimming', 'pool', 'look', 'like', 'cess', 'pit', 'room', 'ugly', 'clean', 'location', 'convenient', 'slightest', 'stayed', 'hotel', 'different', 'time', 'past', 'month', 'satisfied', 'staff', 'friendly', 'helpfully', 'clean', 'room', 'part', 'think', 'may', 'upgrading', 'room', 'second', 'room', 'stayed', 'nice', 'nicer', 'bathroom', 'others', 'others', 'still', 'nice', 'convenient', 'going', 'visiting', 'lackland', 'afb', 'base', 'literally', 'ther', 'street', 'clean', 'pool', 'want', 'swim', 'good', 'breakfast', 'even', 'though', 'went', 'twice', 'perfect', 'hotel', 'price', 'range', 'feel', 'safe', 'stay', 'important', 'complaint', 'hojo', 'staff', 'reception', 'pleasant', 'request', 'accomidated', 'breakfast', 'nice', 'carbs', 'one', 'back', 'room', 'pleasantly', 'large', 'room', 'fridge', 'microwave', 'know', 'older', 'facility', 'show', 'age', 'noticable', 'repair', 'lieu', 'upgrade', 'like', 'staying', 'great', 'aunt', 'house', 'whose', 'failing', 'vision', 'see', 'allow', 'see', 'dust', 'grime', 'sheet', 'need', 'good', 'bleaching', 'make', 'bed', 'nicely', 'work', 'hard', 'welcome', 'air', 'heat', 'could', 'worked', 'better', 'interior', 'pool', 'looked', 'wonderful', 'lush', 'though', 'property', 'surrounded', 'side', 'large', 'wrought', 'iron', 'fencing', 'back', 'neighborhood', 'looked', 'fine', 'felt', 'comfortable', 'immediate', 'area']]
# Initialize BM25
bm25 = BM25Okapi(corpus)
# Define function to retrieve most similar place
def retrieve_bm25(query, k=1):
query = preprocess(query)
scores = bm25.get_scores(query)
# Returns the indices of scores sorted in descending order & selects the top k indices corresponding to the highest scores.
top_k_idx = np.argsort(scores)[::-1][:k]
return final_df.iloc[top_k_idx][['offering_id', 'name', 'hotel_class', 'ratings', 'reviews']]
# Example usage
query_service = 'excellent service and clean rooms'
retrieve_bm25(query_service)
offering_id | name | hotel_class | ratings | reviews | |
---|---|---|---|---|---|
2612 | 258705 | Hotel Commonwealth | 4.0 | {'service': 4.8, 'cleanliness': 4.9, 'overall'... | I was pleasantly surprised that this hotel was... |
query_food = 'delicious food and great view'
retrieve_bm25(query_food)
offering_id | name | hotel_class | ratings | reviews | |
---|---|---|---|---|---|
166 | 79868 | Bay Club Hotel & Marina | 3.0 | {'service': 4.6, 'cleanliness': 4.5, 'overall'... | Great hopitality and a wonderful location. The... |
Here, we will experiment with different methods to improve on BM25. We'll start with TF-IDF and progress to embedding-based models using sentence-transformers
. Finally, we may re-rank using a similarity metric to find the best match.
Using TF-IDF (Term Frequency - Inverse Document Frequency), we can create vector representations for each place's concatenated reviews. Then, we’ll compare a query with these vectors using cosine similarity.
# Instantiate TF-IDF Vectorizer
tfidf_vectorizer = TfidfVectorizer(stop_words='english')
# Fit and transform reviews into TF-IDF vectors
tfidf_matrix = tfidf_vectorizer.fit_transform(final_df['reviews']) # 'reviews' column with concatenated reviews per place
def retrieve_tfidf(query, k=5):
# Transform the query text into TF-IDF vector
query_vec = tfidf_vectorizer.transform([query])
# Compute cosine similarity between the query vector and all document vectors
scores = cosine_similarity(query_vec, tfidf_matrix).flatten()
# Get the indices of the top-k most similar places
top_k_idx = scores.argsort()[::-1][:k]
# Return the top-k places based on similarity
return final_df.iloc[top_k_idx][['offering_id', 'name', 'hotel_class', 'ratings', 'reviews']]
retrieve_tfidf(query_service)
offering_id | name | hotel_class | ratings | reviews | |
---|---|---|---|---|---|
1091 | 98940 | Houston Inn and Suites | 0.0 | {'service': 3.0, 'cleanliness': 3.0, 'overall'... | I stay for a weekend, and the rooms were nice ... |
2570 | 249793 | BEST WESTERN Fort Worth Inn & Suites | 3.0 | {'service': 4.7, 'cleanliness': 4.8, 'overall'... | I was very impressed when as I was walking in ... |
1531 | 109101 | La Quinta Inn & Suites Fort Worth North | 2.5 | {'service': 4.4, 'cleanliness': 4.6, 'overall'... | Rolling into Fort Worth after a long day on th... |
90 | 74845 | Comfort Inn West | 2.0 | {'service': 4.5, 'cleanliness': 4.5, 'overall'... | We had a wonderful stay!! Beautiful redone roo... |
1973 | 124066 | Ramada Limited Addison | 0.0 | {'service': 4.0, 'cleanliness': 3.0, 'overall'... | Hotel based on a main road but within walking ... |
retrieve_tfidf(query_food)
offering_id | name | hotel_class | ratings | reviews | |
---|---|---|---|---|---|
1645 | 112136 | Penn's View Hotel | 3.0 | {'service': 4.5, 'cleanliness': 4.6, 'overall'... | This hotel is located in the old city and is c... |
603 | 87608 | Holiday Inn Chicago - Mart Plaza | 3.0 | {'service': 4.1, 'cleanliness': 4.3, 'overall'... | If your visiting Chicago, and are a little fle... |
1263 | 100567 | The Edgewater Hotel Seattle | 4.0 | {'service': 4.3, 'cleanliness': 4.3, 'overall'... | I have traveled to Seattle extremely often for... |
602 | 87603 | Hotel 71, Wyndham Affiliate | 3.5 | {'service': 4.4, 'cleanliness': 4.4, 'overall'... | Stayed there for 6 nights, Upon arrival shocke... |
703 | 89620 | Hyatt Harborside at Boston's Logan Internation... | 4.0 | {'service': 4.3, 'cleanliness': 4.5, 'overall'... | My boyfriend and I loved this hotel! Our room ... |
Using Sentence Transformers (like all-MiniLM-L6-v2
), we can create dense embeddings of the review text, which generally capture semantic similarities better than TF-IDF.
# Load a pre-trained Sentence Transformer model
model = SentenceTransformer('all-MiniLM-L6-v2')
# Generate embeddings for each place's concatenated reviews
embeddings = model.encode(final_df['reviews'].tolist(), show_progress_bar=True)
Batches: 0%| | 0/118 [00:00<?, ?it/s]
def retrieve_embeddings(query, k=5):
# Encode the query into an embedding vector
query_embedding = model.encode(query)
# Compute cosine similarity between the query embedding and all document embeddings
scores = cosine_similarity([query_embedding], embeddings).flatten()
# Get indices of the top-k most similar places
top_k_idx = np.argsort(scores)[::-1][:k]
# Return the top-k most similar places
return final_df.iloc[top_k_idx][['offering_id', 'name', 'hotel_class', 'ratings', 'reviews']]
retrieve_embeddings(query_service)
offering_id | name | hotel_class | ratings | reviews | |
---|---|---|---|---|---|
3301 | 1174784 | Holiday Inn Baltimore-Towson | 0.0 | {'service': 5.0, 'cleanliness': 5.0, 'overall'... | Found the room exceptionally clean, the staff ... |
3086 | 656554 | Charlotte Express Inn | 2.0 | {'service': 3.5, 'cleanliness': 2.5, 'overall'... | Very courteous, helpful and professional staff... |
1818 | 119997 | Belcaro Motel | 0.0 | {'service': 5.0, 'cleanliness': 5.0, 'overall'... | Perfectly clean. Some new bath renovations, bu... |
2823 | 497952 | Americas Best Value Inn - San Antonio / Lackla... | 2.0 | {'service': 2.8, 'cleanliness': 3.8, 'overall'... | Great clean rooms and great service.\nHotel wa... |
2881 | 553345 | Americas Best Value Inn & Suites Granada Hills | 2.0 | {'service': 4.7, 'cleanliness': 4.4, 'overall'... | Rooms were clean,air conditioner worked well,t... |
retrieve_embeddings(query_food)
offering_id | name | hotel_class | ratings | reviews | |
---|---|---|---|---|---|
3723 | 2627745 | Hotel Palomar Phoenix - a Kimpton Hotel | 4.0 | {'service': 4.9, 'cleanliness': 4.9, 'overall'... | We are big fans of Kimpton Hotels and have sta... |
2692 | 275455 | Scottish Inn Memphis Airport | 0.0 | {'service': 4.0, 'cleanliness': 4.0, 'overall'... | Very nice property located several long blocks... |
3691 | 2151571 | Hotel Americano | 0.0 | {'service': 3.9, 'cleanliness': 4.4, 'overall'... | I have just come back from a 9 day trip from t... |
1499 | 108980 | Hampton Inn Austin - Arboretum Northwest | 2.5 | {'service': 4.8, 'cleanliness': 4.7, 'overall'... | Everything about this hotel screams that they ... |
1629 | 111751 | Hotel Bel-Air | 5.0 | {'service': 4.7, 'cleanliness': 4.9, 'overall'... | Beautiful & classic high class hotel. The spac... |
To combine the strengths of both models, we create a hybrid model where we:
def retrieve_hybrid(query, initial_k=10, final_k=5):
# Step 1: Initial retrieval with TF-IDF or BM25 to get top-k candidates
initial_candidates = retrieve_tfidf(query, k=initial_k)
# Step 2: Generate embeddings for the initial candidates' reviews
candidate_embeddings = model.encode(initial_candidates['reviews'].tolist())
query_embedding = model.encode(query)
# Step 3: Re-rank candidates based on embedding similarity
scores = cosine_similarity([query_embedding], candidate_embeddings).flatten()
top_k_idx = np.argsort(scores)[::-1][:final_k]
# Return final top-k ranked places
return initial_candidates.iloc[top_k_idx]
retrieve_hybrid(query_service)
offering_id | name | hotel_class | ratings | reviews | |
---|---|---|---|---|---|
1091 | 98940 | Houston Inn and Suites | 0.0 | {'service': 3.0, 'cleanliness': 3.0, 'overall'... | I stay for a weekend, and the rooms were nice ... |
90 | 74845 | Comfort Inn West | 2.0 | {'service': 4.5, 'cleanliness': 4.5, 'overall'... | We had a wonderful stay!! Beautiful redone roo... |
2178 | 223171 | Super 8 Houston | 2.0 | {'service': 4.4, 'cleanliness': 4.2, 'overall'... | The hotel was very neat and good for the price... |
2570 | 249793 | BEST WESTERN Fort Worth Inn & Suites | 3.0 | {'service': 4.7, 'cleanliness': 4.8, 'overall'... | I was very impressed when as I was walking in ... |
3625 | 1846923 | Sleep Inn & Suites I-45 / Airtex | 2.0 | {'service': 4.8, 'cleanliness': 4.8, 'overall'... | I stay in many Choice Hotels during the year. ... |
retrieve_hybrid(query_food)
offering_id | name | hotel_class | ratings | reviews | |
---|---|---|---|---|---|
166 | 79868 | Bay Club Hotel & Marina | 3.0 | {'service': 4.6, 'cleanliness': 4.5, 'overall'... | Great hopitality and a wonderful location. The... |
302 | 81126 | Mandarin Oriental, San Francisco | 5.0 | {'service': 4.8, 'cleanliness': 4.9, 'overall'... | The sweeping views from the 40 th floor are ju... |
2306 | 223983 | Baltimore Marriott Waterfront | 4.0 | {'service': 4.4, 'cleanliness': 4.6, 'overall'... | I had a reservation at a different hotel but a... |
1234 | 100507 | Inn at the Market | 4.0 | {'service': 4.8, 'cleanliness': 4.9, 'overall'... | My cousin and I went to Seattle to attend the ... |
1645 | 112136 | Penn's View Hotel | 3.0 | {'service': 4.5, 'cleanliness': 4.6, 'overall'... | This hotel is located in the old city and is c... |
For evaluation, we will use Mean Squared Error (MSE) to calculate the error between ratings on each aspect for the recommended and actual places. This score will be calculated across both BM25 and custom models to compare performance.
# Calculate MSE for a single recommendation
def calculate_mse(actual_ratings, predicted_ratings):
return root_mean_squared_error(actual_ratings, predicted_ratings)
# Define the sample size of query places for evaluation
sample_size = 100
samples = final_df.sample(sample_size)
max_char = 280 # Max limit of characters for query, like an X post
We will run the BM25 and custom model to retrieve places for several test queries, then calculate the MSE for each model and compare the results.
# Store MSE scores for each model
bm25_mse_scores = []
custom_mse_scores = []
custom_embedding_mse_scores = []
custom_hybrid_mse_scores = []
# Step 1: Loop over a sample of query places in the dataset
progress_bar = tqdm(samples.iterrows(), total=sample_size, desc="MSE Calculations")
for _, query_place in progress_bar:
query_text = query_place['reviews'][:max_char] # Use the concatenated reviews for the place as the query
actual_ratings = query_place["ratings"] # Actual ratings for MSE calculation
# Step 2: Retrieve the most similar place using BM25
bm25_recommendation = retrieve_bm25(query_text, k=1)
bm25_predicted_ratings = bm25_recommendation["ratings"].iloc[0]
# Calculate MSE for BM25
bm25_mse = calculate_mse(list(actual_ratings.values()), list(bm25_predicted_ratings.values()))
bm25_mse_scores.append(bm25_mse)
# Step 3: Retrieve the most similar place using the Custom Model
custom_recommendation = retrieve_tfidf(query_text, k=1)
custom_predicted_ratings = custom_recommendation["ratings"].iloc[0]
# Calculate MSE for the Custom Model
custom_mse = calculate_mse(list(actual_ratings.values()), list(custom_predicted_ratings.values()))
custom_mse_scores.append(custom_mse)
# Step 4: Retrieve the most similar place using the Custom Model
custom_embedding_recommendation = retrieve_embeddings(query_text, k=1)
custom_embedding_predicted_ratings = custom_embedding_recommendation["ratings"].iloc[0]
# Calculate MSE for the Custom Model
custom_embedding_mse = calculate_mse(list(actual_ratings.values()), list(custom_embedding_predicted_ratings.values()))
custom_embedding_mse_scores.append(custom_embedding_mse)
# Step 5: Retrieve the most similar place using the Custom Model
custom_hybrid_recommendation = retrieve_hybrid(query_text, final_k=1)
custom_hybrid_predicted_ratings = custom_hybrid_recommendation["ratings"].iloc[0]
# Calculate MSE for the Custom Model
custom_hybrid_mse = calculate_mse(list(actual_ratings.values()), list(custom_hybrid_predicted_ratings.values()))
custom_hybrid_mse_scores.append(custom_hybrid_mse)
# Step 6: Compute the average MSE across all queries for each model
avg_bm25_mse = sum(bm25_mse_scores) / len(bm25_mse_scores)
avg_custom_mse = sum(custom_mse_scores) / len(custom_mse_scores)
avg_custom_embedding_mse = sum(custom_embedding_mse_scores) / len(custom_embedding_mse_scores)
avg_custom_hybrid_mse = sum(custom_hybrid_mse_scores) / len(custom_hybrid_mse_scores)
print(f"Average BM25 MSE: {(avg_bm25_mse * 100):.2f}%")
print(f"Average Custom Model MSE: {(avg_custom_mse * 100):.2f}%")
print(f"Average Embedding Model MSE: {(avg_custom_embedding_mse * 100):.2f}%")
print(f"Average Hybrid Model MSE: {(avg_custom_hybrid_mse * 100):.2f}%")
print(f"Average BM25 MSE: {(avg_bm25_mse * 100):.2f}%")
print(f"Average Custom Model MSE: {(avg_custom_mse * 100):.2f}%")
print(f"Average Embedding Model MSE: {(avg_custom_embedding_mse * 100):.2f}%")
print(f"Average Hybrid Model MSE: {(avg_custom_hybrid_mse * 100):.2f}%")
Average BM25 MSE: 29.91% Average Custom Model MSE: 31.34% Average Embedding Model MSE: 29.76% Average Hybrid Model MSE: 22.13%
plt.figure(figsize=(10, 8)) # Set the figure size
plt.plot(range(1, sample_size + 1), bm25_mse_scores, marker='o', label=f'BM25')
# plt.plot(range(1, sample_size + 1), custom_mse_scores, label=f'Custom (TF-IDF)')
# plt.plot(range(1, sample_size + 1), custom_embedding_mse_scores, label=f'Custom Embedding')
plt.plot(range(1, sample_size + 1), custom_hybrid_mse_scores, marker='o', label=f'Custom Hybrid (TF_IDF + Embedding)')
# Set titles and labels
plt.title("Details of Performance of Both Models")
plt.xlabel("Sample")
plt.ylabel("MSE")
plt.grid(True)
plt.legend()
plt.show()
The Hybrid model, combining the initial ranking of TF-IDF with re-ranking by embeddings, performs best, with an 26.45% MSE. This likely indicates that embeddings add value when used to refine results within a more relevant subset, offering a good balance between term-based and semantic similarity.
This model has a much higher MSE. This could happen if embeddings aren’t fine-tuned on similar hotel review data, making the model potentially less aligned with the dataset’s vocabulary or context.
BM25 achieves a slightly higher MSE, likely due to its inability to consistently capture the full semantic similarity, despite its strong ability to retrieve similar documents based on term frequency and document frequency.
TF-IDF relies on term frequency but might miss some contextual relevance, especially in cases where semantic meaning is important which might explain its poor performance compared to the other models.
It looks like the *hybrid model* is a strong candidate here, with room for further improvements to potentially outperform BM25 by an even wider margin.
# Store NDCG scores for each model
bm25_ndcg_scores = []
custom_ndcg_scores = []
custom_embedding_ndcg_scores = []
custom_hybrid_ndcg_scores = []
# Loop over a sample of query places in the dataset
for _, query_place in tqdm(samples.iterrows(), total=float(sample_size), desc="NDCG Calculations"):
query_text = query_place['reviews'][:max_char] # Use the concatenated reviews for the place as the query
actual_ratings = query_place["ratings"] # Actual ratings
# Convert actual ratings to relevance scores and ensure it's a list
actual_relevance = [list(actual_ratings.values())]
# Step 1: Retrieve the most similar place using BM25
bm25_recommendation = retrieve_bm25(query_text, k=1)
bm25_predicted_ratings = bm25_recommendation["ratings"].iloc[0]
bm25_relevance = [list(bm25_predicted_ratings.values())]
# Calculate NDCG for BM25
bm25_ndcg = ndcg_score(actual_relevance, bm25_relevance)
bm25_ndcg_scores.append(bm25_ndcg)
# Step 2: Retrieve the most similar place using the Custom Model (TF-IDF)
custom_recommendation = retrieve_tfidf(query_text, k=1)
custom_predicted_ratings = custom_recommendation["ratings"].iloc[0]
custom_relevance = [list(custom_predicted_ratings.values())]
# Calculate NDCG for the Custom Model
custom_ndcg = ndcg_score(actual_relevance, custom_relevance)
custom_ndcg_scores.append(custom_ndcg)
# Step 3: Retrieve the most similar place using the Embedding Model
custom_embedding_recommendation = retrieve_embeddings(query_text, k=1)
custom_embedding_predicted_ratings = custom_embedding_recommendation["ratings"].iloc[0]
custom_embedding_relevance = [list(custom_embedding_predicted_ratings.values())]
# Calculate NDCG for the Embedding Model
custom_embedding_ndcg = ndcg_score(actual_relevance, custom_embedding_relevance)
custom_embedding_ndcg_scores.append(custom_embedding_ndcg)
# Step 4: Retrieve the most similar place using the Hybrid Model
custom_hybrid_recommendation = retrieve_hybrid(query_text, final_k=1)
custom_hybrid_predicted_ratings = custom_hybrid_recommendation["ratings"].iloc[0]
custom_hybrid_relevance = [list(custom_hybrid_predicted_ratings.values())]
# Calculate NDCG for the Hybrid Model
custom_hybrid_ndcg = ndcg_score(actual_relevance, custom_hybrid_relevance)
custom_hybrid_ndcg_scores.append(custom_hybrid_ndcg)
# Compute the average NDCG across all queries for each model
avg_bm25_ndcg = np.mean(bm25_ndcg_scores)
avg_custom_ndcg = np.mean(custom_ndcg_scores)
avg_custom_embedding_ndcg = np.mean(custom_embedding_ndcg_scores)
avg_custom_hybrid_ndcg = np.mean(custom_hybrid_ndcg_scores)
# Print average NDCG results
print(f"Average BM25 NDCG: {avg_bm25_ndcg:.4f}")
print(f"Average Custom Model NDCG: {avg_custom_ndcg:.4f}")
print(f"Average Embedding Model NDCG: {avg_custom_embedding_ndcg:.4f}")
print(f"Average Hybrid Model NDCG: {avg_custom_hybrid_ndcg:.4f}")
NDCG Calculations: 100%|██████████| 100/100.0 [02:07<00:00, 1.28s/it]
Average BM25 NDCG: 0.9933 Average Custom Model NDCG: 0.9933 Average Embedding Model NDCG: 0.9917 Average Hybrid Model NDCG: 0.9949
# Models for plots
models = ['BM25', 'Custom Model (TF-IDF)', 'Embedding Model', 'Hybrid Model']
ndcg_scores = [avg_bm25_ndcg, avg_custom_ndcg, avg_custom_embedding_ndcg, avg_custom_hybrid_ndcg]
# Sorting results for display
sorted_data = sorted(zip(models, ndcg_scores), key=lambda x: x[1], reverse=True)
sorted_models, sorted_scores = zip(*sorted_data) # Unpack the sorted data
# Plots
plt.figure(figsize=(10, 6))
plt.bar(sorted_models, sorted_scores, color=['blue', 'orange', 'green', 'red'])
plt.title('NDCG Comparison of Different Recommendation Models')
plt.xlabel('Model')
plt.ylabel('Average NDCG Score')
plt.ylim(.975, 1) # NDCG scores between 0.975 and 1
plt.show()