Corin1998 commited on
Commit
b622347
·
verified ·
1 Parent(s): 0b511cf

Create scoring.py

Browse files
Files changed (1) hide show
  1. src/scoring.py +34 -0
src/scoring.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from datetime import datetime, timedelta
2
+ from sqlmodel import select
3
+ from .models import Visti, TokenBalance
4
+ from .db import get_session
5
+
6
+ # 重みは適宜調整
7
+ W_RECENCY = 0.5
8
+ W_FREQUENCY = 0.3
9
+ W_POINTS30 = 0.2
10
+
11
+ def calc_score(user_id: int) -> float:
12
+ now = datetime.utcnow()
13
+ cutoff_30 = now - timedelta(days=30)
14
+ with get_session() as s:
15
+ visits = s.exec(select(Visit).where(Visit.user_id == user_id).order_by(Visit.created_at.desc())).all()
16
+ if not visits:
17
+ return 0.0
18
+ last_visit = visits[0].created_at
19
+ days_since = (now - last_visit).days
20
+ recency_score = max(0.0, 1.0 -days_since/ 30.0) #30日で減衰
21
+ freq_score = min(1.0, len([v for v in visits if v.created_at > now -timedelta(days=90)])/ 10.0) #90日10回で満点
22
+ points30 = s.exec(select(TokenBalance).where(TokenBalance.user_id == user_id)).all()
23
+ points_amounts = sum(tb.amount for tb in points30)
24
+ points30_score = min(1.0, points_amounts / 1000.0)
25
+ return W_RECENCY * recency_score + W_FREQUENCY * freq_score + W_POINTS30 *points30_score
26
+
27
+ def segment(socre: float) -> str:
28
+ if score >= 0.75:
29
+ return "loyal"
30
+ if score >= 0.4:
31
+ return "active"
32
+ if score > 0.0:
33
+ return "at-risk"
34
+ return "new"