File size: 5,360 Bytes
133a630
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
daa3d2a
 
133a630
daa3d2a
 
 
 
133a630
 
 
daa3d2a
 
 
133a630
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import numpy as np
import pandas as pd


class KnowledgeBasedRecommender:
    def __init__(self, products_df):
        self.products = products_df.copy()

    def constraint_based(self, constraints, n_recommendations=10):
        filtered = self.products.copy()

        if "budget_max" in constraints:
            filtered = filtered[filtered["price"] <= constraints["budget_max"]]
        if "budget_min" in constraints:
            filtered = filtered[filtered["price"] >= constraints["budget_min"]]
        if "category" in constraints and constraints["category"]:
            filtered = filtered[filtered["category"].isin(constraints["category"])]

        brand_match = None
        if "brand" in constraints and constraints["brand"]:
            brand_match = filtered[filtered["brand"].isin(constraints["brand"])]
        if brand_match is not None and not brand_match.empty:
            filtered = brand_match

        if "min_rating" in constraints:
            filtered = filtered[filtered["avg_rating"] >= constraints["min_rating"]]
        if "subcategory" in constraints and constraints["subcategory"]:
            sub_match = filtered[filtered["subcategory"].isin(constraints["subcategory"])]
            if not sub_match.empty:
                filtered = sub_match

        filtered = filtered.sort_values("avg_rating", ascending=False)
        results = [(int(row["product_id"]), float(row["avg_rating"])) for _, row in filtered.head(n_recommendations).iterrows()]
        return results

    def rule_based(self, context, n_recommendations=10):
        rules = {
            "laptop": {"category": "Electronics", "subcategory": "Laptops"},
            "smartphone": {"category": "Electronics", "subcategory": "Smartphones"},
            "book": {"category": "Books"},
            "camera": {"category": "Electronics", "subcategory": "Cameras"},
            "headphone": {"category": "Electronics", "subcategory": "Headphones"},
        }

        accessoires_map = {
            "Laptops": ["Laptop Bag", "Mouse", "Keyboard", "Cooling Pad"],
            "Smartphones": ["Phone Case", "Screen Protector", "Charger", "Power Bank"],
            "Cameras": ["Camera Bag", "Tripod", "Memory Card", "Lens Kit"],
            "Headphones": ["Headphone Stand", "Cable", "Carrying Case", "Ear Pads"],
        }

        interacted_category = context.get("interacted_category", "")
        scores = []

        for _, product in self.products.iterrows():
            score = 0
            if interacted_category and product["category"] == "Electronics":
                if product["subcategory"] in accessoires_map.get(interacted_category, []):
                    score += 50
            if context.get("preferred_categories") and product["category"] in context["preferred_categories"]:
                score += 20
            if context.get("budget_min", 0) <= product["price"] <= context.get("budget_max", 999999):
                score += 15
            if context.get("favorite_brands") and product["brand"] in context["favorite_brands"]:
                score += 10
            scores.append((int(product["product_id"]), score))

        scores.sort(key=lambda x: x[1], reverse=True)
        return scores[:n_recommendations]

    def utility_based(self, preferences, weights=None, n_recommendations=10):
        if weights is None:
            weights = {"price": 0.2, "category": 0.3, "brand": 0.2, "rating": 0.3}

        price_min = preferences.get("budget_min", 0)
        price_max = preferences.get("budget_max", 999999)
        pref_cats = preferences.get("preferred_categories", set())
        fav_brands = preferences.get("favorite_brands", set())

        max_price = self.products["price"].max()
        min_price = self.products["price"].min()
        max_rating = self.products["avg_rating"].max()

        scores = []
        for _, product in self.products.iterrows():
            u = 0.0

            if price_max > price_min:
                price_score = 1.0 - abs(product["price"] - (price_min + price_max) / 2) / ((price_max - price_min) / 2)
                price_score = max(0, min(1, price_score))
            else:
                price_score = 1.0 if price_min <= product["price"] <= price_max else 0.0
            u += weights["price"] * price_score

            cat_score = 1.0 if product["category"] in pref_cats else 0.0
            u += weights["category"] * cat_score

            brand_score = 1.0 if product["brand"] in fav_brands else 0.0
            u += weights["brand"] * brand_score

            rating_score = product["avg_rating"] / max_rating if max_rating > 0 else 0
            u += weights["rating"] * rating_score

            scores.append((int(product["product_id"]), round(u, 4)))

        scores.sort(key=lambda x: x[1], reverse=True)
        return scores[:n_recommendations]

    def recommend(self, method, constraints=None, context=None, preferences=None, n_recommendations=10):
        if method == "constraint":
            return self.constraint_based(constraints or {}, n_recommendations)
        elif method == "rule":
            return self.rule_based(context or {}, n_recommendations)
        elif method == "utility":
            return self.utility_based(preferences or {}, n_recommendations=n_recommendations)
        else:
            raise ValueError(f"Unknown method: {method}")