Spaces:
Build error
Build error
| # -*- coding: utf-8 -*- | |
| import pandas as pd | |
| import numpy as np | |
| import re | |
| import itertools | |
| import matplotlib.pyplot as plt | |
| from sklearn.feature_extraction.text import TfidfVectorizer | |
| from sklearn.metrics.pairwise import linear_kernel | |
| #from huggingface_hub import upload_file | |
| #fuzz = upload_file(path_in_repo="fuzz.py") | |
| from fuzzywuzzy import fuzz | |
| from sklearn.feature_extraction.text import TfidfVectorizer | |
| import gradio as gr | |
| from datasets import load_dataset | |
| dataset = load_dataset("seyia92coding/steam-clean-games-2019") | |
| df = pd.read_csv(dataset, error_bad_lines=False, encoding='utf-8') | |
| # the function to extract years | |
| def extract_year(date): | |
| year = date[:4] | |
| if year.isnumeric(): | |
| return int(year) | |
| else: | |
| return np.nan | |
| df['year'] = df['release_date'].apply(extract_year) | |
| df['steamspy_tags'] = df['steamspy_tags'].str.replace(' ','-') | |
| df['genres'] = df['steamspy_tags'].str.replace(';',' ') | |
| counts = dict() | |
| for i in df.index: | |
| for g in df.loc[i,'genres'].split(' '): | |
| if g not in counts: | |
| counts[g] = 1 | |
| else: | |
| counts[g] = counts[g] + 1 | |
| def create_score(row): | |
| pos_count = row['positive_ratings'] | |
| neg_count = row['negative_ratings'] | |
| total_count = pos_count + neg_count | |
| average = pos_count / total_count | |
| return round(average, 2) | |
| def total_ratings(row): | |
| pos_count = row['positive_ratings'] | |
| neg_count = row['negative_ratings'] | |
| total_count = pos_count + neg_count | |
| return total_count | |
| df['total_ratings'] = df.apply(total_ratings, axis=1) | |
| df['score'] = df.apply(create_score, axis=1) | |
| # Calculate mean of vote average column | |
| C = df['score'].mean() | |
| m = df['total_ratings'].quantile(0.90) | |
| # Function that computes the weighted rating of each game | |
| def weighted_rating(x, m=m, C=C): | |
| v = x['total_ratings'] | |
| R = x['score'] | |
| # Calculation based on the IMDB formula | |
| return round((v/(v+m) * R) + (m/(m+v) * C), 2) | |
| # Define a new feature 'score' and calculate its value with `weighted_rating()` | |
| df['weighted_score'] = df.apply(weighted_rating, axis=1) | |
| # create an object for TfidfVectorizer | |
| tfidf_vector = TfidfVectorizer(stop_words='english') | |
| tfidf_matrix = tfidf_vector.fit_transform(df['genres']) | |
| # create the cosine similarity matrix | |
| sim_matrix = linear_kernel(tfidf_matrix,tfidf_matrix) | |
| # create a function to find the closest title | |
| def matching_score(a,b): | |
| #fuzz.ratio(a,b) calculates the Levenshtein Distance between a and b, and returns the score for the distance | |
| return fuzz.ratio(a,b) | |
| """# Make our Recommendation Engine | |
| We need combine our formatted dataset with the similarity logic to return recommendations. This is also where we can fine-tune it if we do not like the results. | |
| """ | |
| ##These functions needed to return different attributes of the recommended game titles | |
| #Convert index to title_year | |
| def get_title_year_from_index(index): | |
| return df[df.index == index]['year'].values[0] | |
| #Convert index to title | |
| def get_title_from_index(index): | |
| return df[df.index == index]['name'].values[0] | |
| #Convert index to title | |
| def get_index_from_title(title): | |
| return df[df.name == title].index.values[0] | |
| #Convert index to score | |
| def get_score_from_index(index): | |
| return df[df.index == index]['score'].values[0] | |
| #Convert index to weighted score | |
| def get_weighted_score_from_index(index): | |
| return df[df.index == index]['weighted_score'].values[0] | |
| #Convert index to total_ratings | |
| def get_total_ratings_from_index(index): | |
| return df[df.index == index]['total_ratings'].values[0] | |
| #Convert index to platform | |
| def get_platform_from_index(index): | |
| return df[df.index == index]['platforms'].values[0] | |
| # A function to return the most similar title to the words a user type | |
| def find_closest_title(title): | |
| #matching_score(a,b) > a is the current row, b is the title we're trying to match | |
| leven_scores = list(enumerate(df['name'].apply(matching_score, b=title))) #[(0, 30), (1,95), (2, 19)~~] A tuple of distances per index | |
| sorted_leven_scores = sorted(leven_scores, key=lambda x: x[1], reverse=True) #Sorts list of tuples by distance [(1, 95), (3, 49), (0, 30)~~] | |
| closest_title = get_title_from_index(sorted_leven_scores[0][0]) | |
| distance_score = sorted_leven_scores[0][1] | |
| return closest_title, distance_score | |
| def gradio_contents_based_recommender_v2(game, how_many, sort_option, min_year, platform, min_score): | |
| #Return closest game title match | |
| closest_title, distance_score = find_closest_title(game) | |
| #Create a Dataframe with these column headers | |
| recomm_df = pd.DataFrame(columns=['Game Title', 'Year', 'Score', 'Weighted Score', 'Total Ratings']) | |
| #find the corresponding index of the game title | |
| games_index = get_index_from_title(closest_title) | |
| #return a list of the most similar game indexes as a list | |
| games_list = list(enumerate(sim_matrix[int(games_index)])) | |
| #Sort list of similar games from top to bottom | |
| similar_games = list(filter(lambda x:x[0] != int(games_index), sorted(games_list,key=lambda x:x[1], reverse=True))) | |
| #Print the game title the similarity matrix is based on | |
| print('Here\'s the list of games similar to '+'\033[1m'+str(closest_title)+'\033[0m'+'.\n') | |
| #Only return the games that are on selected platform | |
| n_games = [] | |
| for i,s in similar_games: | |
| if platform in get_platform_from_index(i): | |
| n_games.append((i,s)) | |
| #Only return the games that are above the minimum score | |
| high_scores = [] | |
| for i,s in n_games: | |
| if get_score_from_index(i) > min_score: | |
| high_scores.append((i,s)) | |
| #Return the game tuple (game index, game distance score) and store in a dataframe | |
| for i,s in n_games[:how_many]: | |
| #Dataframe will contain attributes based on game index | |
| row = {'Game Title': get_title_from_index(i), 'Year': get_title_year_from_index(i), 'Score': get_score_from_index(i), | |
| 'Weighted Score': get_weighted_score_from_index(i), | |
| 'Total Ratings': get_total_ratings_from_index(i),} | |
| #Append each row to this dataframe | |
| recomm_df = recomm_df.append(row, ignore_index = True) | |
| #Sort dataframe by Sort_Option provided by user | |
| recomm_df = recomm_df.sort_values(sort_option, ascending=False) | |
| #Only include games released same or after minimum year selected | |
| recomm_df = recomm_df[recomm_df['Year'] >= min_year] | |
| return recomm_df | |
| #Create list of unique calendar years based on main df column | |
| years_sorted = sorted(list(df['year'].unique())) | |
| #Interface will include these buttons based on parameters in the function with a dataframe output | |
| recommender = gr.Interface(gradio_contents_based_recommender_v2, ["text", gr.inputs.Slider(1, 20, step=int(1)), | |
| gr.inputs.Radio(['Year','Score','Weighted Score','Total Ratings']), | |
| gr.inputs.Slider(int(years_sorted[0]), int(years_sorted[-1]), step=int(1)), | |
| gr.inputs.Radio(['windows','xbox','playstation','linux','mac']), | |
| gr.inputs.Slider(0, 10, step=0.1)], | |
| "dataframe") | |
| recommender.launch(debug=True) |