File size: 4,735 Bytes
133a630
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b1410eb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133a630
 
b1410eb
 
 
 
 
133a630
 
b1410eb
 
133a630
b1410eb
 
 
 
 
133a630
 
 
 
 
b1410eb
 
 
 
 
133a630
 
b1410eb
 
133a630
b1410eb
 
133a630
 
 
 
 
b1410eb
28e5413
b1410eb
 
133a630
 
b1410eb
133a630
 
b1410eb
 
 
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
class Explainer:
    def __init__(self, products_df, users_df):
        self.products = products_df
        self.users = users_df
        self._product_cache = {}
        self._user_cache = {}
        for _, row in products_df.iterrows():
            self._product_cache[row["product_id"]] = row
        for _, row in users_df.iterrows():
            self._user_cache[row["user_id"]] = row

    def _get_product(self, product_id):
        return self._product_cache.get(product_id, {})

    def _get_user(self, user_id):
        return self._user_cache.get(user_id, {})

    def _fmt_score(self, score):
        if score >= 0.9:
            return "Excellent match"
        elif score >= 0.7:
            return "Strong match"
        elif score >= 0.5:
            return "Good match"
        elif score >= 0.3:
            return "Moderate match"
        else:
            return "Partial match"

    def _pref_list(self, user, key):
        raw = user.get(key, "")
        if raw is None or isinstance(raw, float):
            return []
        if isinstance(raw, str):
            return [p.strip() for p in raw.split(",") if p.strip()][:2]
        return list(raw)[:2] if raw else []

    def explain_cf(self, method, user_id, product_id, details=None):
        product = self._get_product(product_id)
        user = self._get_user(user_id)
        pname = product.get("name", f"Item #{product_id}")
        cat = product.get("category", "")
        brand = product.get("brand", "")
        price = product.get("price", 0)
        details = details or {}
        sim = min(details.get('sim_score', 0), 1.0)
        pref_cats = self._pref_list(user, "preferred_categories")

        templates = {
            "user_based": f"Users with {cat} taste also liked {pname}",
            "item_based": f"Matches your {cat} preferences — similar to items you've rated highly",
            "svd": f"Fits your profile: {brand}'s {cat} — top latent factor match" if brand and cat else f"Fits your profile: {cat} — top latent factor match",
            "knn": f"Popular among peers who also like {cat}" if cat else f"Popular among users with similar taste",
            "slope_one": f"Frequently chosen by users who liked the same {cat} products" if cat else f"Frequently chosen by users with your taste",
        }
        return templates.get(method, f"Recommended based on collaborative filtering")

    def explain_content(self, method, user_id, product_id, details=None):
        product = self._get_product(product_id)
        user = self._get_user(user_id)
        pname = product.get("name", f"Item #{product_id}")
        cat = product.get("category", "")
        brand = product.get("brand", "")
        sub = product.get("subcategory", "")
        details = details or {}
        score = min(details.get('score', 0), 1.0)
        pref_cats = self._pref_list(user, "preferred_categories")

        templates = {
            "tfidf": f"Content matches: {cat} / {sub} — strongly aligns with your past likes" if sub else f"Content matches your preferred {cat} items",
            "feature_match": f"Matches your preferences: {cat}, {brand}" if brand else f"Matches your preferred category: {cat}",
        }
        return templates.get(method, f"Recommended based on item features")

    def explain_knowledge(self, method, user_id, product_id, details=None):
        product = self._get_product(product_id)
        user = self._get_user(user_id)
        details = details or {}
        pname = product.get("name", f"Item #{product_id}")
        cat = product.get("category", "")
        brand = product.get("brand", "")
        price = product.get("price", 0)
        budget_max = details.get("budget_max", 0)

        templates = {
            "constraint": f"Fits your criteria: ${price:.0f} within budget · {cat} · {brand}" if brand else f"Fits your criteria: ${price:.0f} within budget · {cat}",
            "rule": f"{cat} buyers commonly add {pname} — cross-sell match" if cat else f"Customers also purchased {pname}",
            "utility": f"Top utility score: {cat} × {brand} matches your preference weights" if brand else f"Top utility score: {cat} matches your preference weights",
        }
        return templates.get(method, f"Recommended based on your requirements")

    def get_explanation(self, approach, method, user_id, product_id, details=None):
        if approach == "cf":
            return self.explain_cf(method, user_id, product_id, details)
        elif approach == "content":
            return self.explain_content(method, user_id, product_id, details)
        elif approach == "knowledge":
            return self.explain_knowledge(method, user_id, product_id, details)
        return ""