Corin1998 commited on
Commit
167c1df
·
verified ·
1 Parent(s): d5be10a

Update app/bandit.py

Browse files
Files changed (1) hide show
  1. app/bandit.py +10 -19
app/bandit.py CHANGED
@@ -5,26 +5,20 @@ from . import storage
5
 
6
  class ThompsonBandit:
7
  """
8
- CTR(クリック)とCVR(コンバージョン)の二段ベータ。
9
- 目的関数: E[value] = p_click * p_conv * value_per_conversion
10
- 季節性は CTR 側の仮想カウントで補正。
11
  """
12
  def __init__(self, campaign_id: str, seasonality_boost: float = 5.0):
13
  self.campaign_id = campaign_id
14
  self.seasonality_boost = seasonality_boost
15
 
16
- def sample_arm(
17
- self,
18
- context: Dict[str, Any],
19
- seasonal_fn: Optional[Callable[[Dict[str, Any]], float]] = None, # ← キーワード引数OK
20
- ) -> Tuple[Optional[str], float]:
21
  metrics = storage.get_metrics(self.campaign_id)
22
  if not metrics:
23
  return None, -1.0
24
-
25
  vpc = storage.get_campaign_value_per_conversion(self.campaign_id)
26
 
27
- # 季節性スコア s ∈ (0, 1)
28
  s = 0.5
29
  if seasonal_fn is not None:
30
  try:
@@ -33,21 +27,18 @@ class ThompsonBandit:
33
  except Exception:
34
  s = 0.5
35
 
36
- best_score, best_variant = -1.0, None
37
- for row in metrics:
38
- ac, bc = float(row["alpha_click"]), float(row["beta_click"])
39
- av, bv = float(row["alpha_conv"]), float(row["beta_conv"])
40
-
41
- # 季節性でクリック側の事前分布を微調整
42
  ac_eff = ac + self.seasonality_boost * s
43
  bc_eff = bc + self.seasonality_boost * (1.0 - s)
44
-
45
  pc = random.betavariate(max(1e-6, ac_eff), max(1e-6, bc_eff))
46
  pv = random.betavariate(max(1e-6, av), max(1e-6, bv))
47
  score = pc * pv * vpc
48
  if score > best_score:
49
- best_score, best_variant = score, row["variant_id"]
50
- return best_variant, best_score
51
 
52
  @staticmethod
53
  def update_with_event(campaign_id: str, variant_id: str, event_type: str):
 
5
 
6
  class ThompsonBandit:
7
  """
8
+ CTRとCVRの二段ベータ。EV=pc*pv*V。
9
+ 季節性はクリック側の事前にブースト。
 
10
  """
11
  def __init__(self, campaign_id: str, seasonality_boost: float = 5.0):
12
  self.campaign_id = campaign_id
13
  self.seasonality_boost = seasonality_boost
14
 
15
+ def sample_arm(self, context: Dict[str, Any], seasonal_fn: Optional[Callable[[Dict[str, Any]], float]] = None
16
+ ) -> Tuple[Optional[str], float]:
 
 
 
17
  metrics = storage.get_metrics(self.campaign_id)
18
  if not metrics:
19
  return None, -1.0
 
20
  vpc = storage.get_campaign_value_per_conversion(self.campaign_id)
21
 
 
22
  s = 0.5
23
  if seasonal_fn is not None:
24
  try:
 
27
  except Exception:
28
  s = 0.5
29
 
30
+ best_score, best_vid = -1.0, None
31
+ for r in metrics:
32
+ ac, bc = float(r["alpha_click"]), float(r["beta_click"])
33
+ av, bv = float(r["alpha_conv"]), float(r["beta_conv"])
 
 
34
  ac_eff = ac + self.seasonality_boost * s
35
  bc_eff = bc + self.seasonality_boost * (1.0 - s)
 
36
  pc = random.betavariate(max(1e-6, ac_eff), max(1e-6, bc_eff))
37
  pv = random.betavariate(max(1e-6, av), max(1e-6, bv))
38
  score = pc * pv * vpc
39
  if score > best_score:
40
+ best_score, best_vid = score, r["variant_id"]
41
+ return best_vid, best_score
42
 
43
  @staticmethod
44
  def update_with_event(campaign_id: str, variant_id: str, event_type: str):