| Current Path : /home/deltalab/PMS/recommendations/recommender-system-batch/components/ |
| Current File : //home/deltalab/PMS/recommendations/recommender-system-batch/components/vendorBased_RS.py |
import json
from textwrap import indent
from _library import toolkit
from tabulate import tabulate
class vendorBased_RS:
def __init__(self, products, product_identifier, filterSamePlatform):
self.platfrom_products = products
self.product_identifier = product_identifier
self.vendor_attribute_name = 'Vendor'
self.unknown_category_marker = ''
self.filterSamePlatform = filterSamePlatform
self.rs_name = 'vendorBased'
def filter_similar_items(self, recommendations):
simProduct_col_name = 'similar_products'
similarity_threshold = 0.4
minBundleDim = 4
# A list of dictionaries. Each dictionary represents a product.
filtered_recommendations = recommendations.copy()
recommendation_names = {item['product_name']: item['item_sku'] for item in recommendations}
for recommendation in recommendations:
item_name = recommendation['product_name']
if item_name in recommendation_names.keys():
pos = list(recommendation_names.keys()).index(item_name)
else:
continue
# Compute similarity
similarity_func = lambda word_to_compare: toolkit.jaccard_similarity(item_name, word_to_compare)
similarities = dict(zip(recommendation_names.keys(), map(similarity_func, recommendation_names.keys())))
if item_name in similarities.keys():
similarities.pop(item_name)
# Retrieve similar items
similar_items = [product_name for product_name, similarity in similarities.items()
if similarity >= similarity_threshold]
sku_similarItems = [recommendation_names[item_name] for item_name in similar_items]
if len(similar_items) > 0:
itemToattach = dict(zip(sku_similarItems, similar_items))
# Add the elements in the new attribute
if simProduct_col_name in filtered_recommendations[pos].keys():
filtered_recommendations[pos][simProduct_col_name].update(itemToattach)
else:
filtered_recommendations[pos][simProduct_col_name] = itemToattach
# Delate similar items
for similar_item in similar_items:
pos = list(recommendation_names.keys()).index(similar_item)
if len(recommendation_names) > minBundleDim:
recommendation_names.pop(similar_item)
filtered_recommendations.pop(pos)
return filtered_recommendations
def generate_recommendations(self, reference_items, filterSamePlatform, verbose = False):
recommended_items = list()
for reference_item in reference_items:
item_name = reference_item['item_name']
product_name = reference_item['product_name']
item_vendor = reference_item['vendor']
item_source = reference_item['inTrentino_source']
# Filtering conditions
vendorBased_cond = self.platfrom_products[self.vendor_attribute_name] == item_vendor
sourcePlatformBased_cond = self.platfrom_products['inTrentino_source'] == item_source
if filterSamePlatform:
main_cond = vendorBased_cond & sourcePlatformBased_cond
else:
main_cond = vendorBased_cond
# Try to retrieve the products
items_vendor = self.platfrom_products[main_cond]
# Drop the reference item
reference_item_idx = items_vendor[items_vendor[self.product_identifier] == item_name].index
items_vendor = items_vendor.drop(index = reference_item_idx)
# Compute the similarity with the reference
items_vendor['similarity'] = items_vendor['Title'].apply(
lambda item_name: toolkit.jaccard_similarity(item_name, product_name))
# Order according to: (1) the dissmilarity, (2) the frequency (3) the title
items_vendor = items_vendor.drop_duplicates(subset = [self.product_identifier])
items_vendor = items_vendor.sort_values(
by = ['similarity', 'Frequency', 'Title'],
ascending = [True, False, False]).reset_index(drop = True)
if verbose:
print(f"\nvendorBased --> [{reference_item['item_type']}] {reference_item['product_name']} by "\
f"'{reference_item['vendor']}'")
print(tabulate(items_vendor, headers=items_vendor.columns, tablefmt = 'pretty'))
print("-" * 40)
# Rename the columns
items_vendor = items_vendor.drop(columns = ['Type id', 'Frequency', 'similarity'])
items_vendor = items_vendor.rename(
columns = {
'Title': 'product_name',
'Product Type': 'item_type',
'Vendor': 'item_vendor',
'SKU': 'item_sku',
'Seller': 'seller',
'production_areas': 'linked_production_area'
}
)
selected_cols = ['item_vendor', 'item_sku', 'product_name', 'item_type', 'seller', 'inTrentino_source', 'linked_production_area']
items_vendor = items_vendor[selected_cols]
# Create the attribute "item_name" for compatibility with the follow-up steps
itemName_attribute = 'item_sku' if self.product_identifier.lower() == 'sku' else 'product_name'
items_vendor['item_name'] = items_vendor[itemName_attribute]
# Build the explaination
items_vendor['explaination'] = "Ti potrebbero interessare prodotti dello stesso marchio"
# Generate the ranks
items_vendor = items_vendor.reset_index(drop = True)
items_vendor['rank'] = [idx + 1 for idx in items_vendor.index]
# Save the recommended items
recommended_items.extend(items_vendor.to_dict(orient = 'records'))
return recommended_items
def itemWise_vendorBased_recommendations(self, reference_items):
# Slight artefact
if (not isinstance(reference_items, list)) or (not isinstance(reference_items, set)):
reference_items = [reference_items]
# Generate the recommendations
recommended_items = self.generate_recommendations(reference_items, self.filterSamePlatform)
# Filter similar items
recommended_items = self.filter_similar_items(recommended_items)
# Add the name of this method to the recommendations
#for recommendations in recommendedItems_byCategory.values():
recommended_items = toolkit.add_recommendationSource(recommended_items, self.rs_name)
return recommended_items
def generate_vendorBased_recommendations(self):
# Pre-processing the products
reference_products = self.platfrom_products.apply(
func = lambda df_row: toolkit.extract_referenceProduct(df_row, self.product_identifier),
axis = 1)
# Compute the recommendation for each products
recommendations = reference_products.apply(
func = lambda product: self.itemWise_vendorBased_recommendations(product))
# Improve the data representation
recommendations.index = reference_products.apply(lambda product: product['item_name'])
recommendations = recommendations.to_dict()
return recommendations