edge_replay_features.py liczy na prodzie cechy znane w chwili kazdego
wyswietlenia, edge_tuning_analysis.py ocenia formuly (AUC w obrebie
urzadzenia, podzial w czasie). Na nich dobrana punktacja z 4666fcb.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
82 lines
3.4 KiB
Python
82 lines
3.4 KiB
Python
"""Ocena punktacji feedu Edge na cechach z scripts/edge_replay_features.py.
|
|
|
|
Trening na 70% najstarszych wyswietlen, test na reszcie. Glowna miara: AUC W OBREBIE
|
|
URZADZENIA (czy wyzszy wynik u tego samego urzadzenia znaczy lepsza reakcje), bo globalne
|
|
AUC miesza aktywnych z nowymi. Dwie etykiety: lajk albo >= 10 s ogladania (odporna na
|
|
dlugosc klipu) oraz dokonczenie albo lajk. F5 to formula wdrozona 2026-10-02.
|
|
Wymaga pandas i scikit-learn (lokalnie, nie w kontenerze).
|
|
"""
|
|
import sys
|
|
|
|
import numpy as np
|
|
import pandas as pd
|
|
from sklearn.linear_model import LogisticRegression
|
|
from sklearn.metrics import roc_auc_score
|
|
|
|
df = pd.read_csv(sys.argv[1], parse_dates=["ts"])
|
|
A = 10.0
|
|
P_LIKE, P_SKIP = 0.03, 0.5
|
|
df["like_rate"] = (df.c_like + A * P_LIKE) / (df.c_seen + A)
|
|
df["skip_rate"] = (df.c_skip + A * P_SKIP) / (df.c_seen + A)
|
|
df["popul"] = df["pop"]
|
|
slog = lambda x: np.sign(x) * np.log1p(np.abs(x)) # noqa: E731
|
|
for c in ["tag_sum", "tag_idf_sum", "creator_w", "niche_sum"]:
|
|
df["s_" + c] = slog(df[c])
|
|
|
|
|
|
def within(d, col):
|
|
num = den = 0.0
|
|
for _, g in d.groupby("dev"):
|
|
if len(g) < 30 or g.y.nunique() < 2 or g[col].nunique() < 2:
|
|
continue
|
|
num += roc_auc_score(g.y, g[col]) * len(g)
|
|
den += len(g)
|
|
return num / den if den else float("nan")
|
|
|
|
|
|
def labelled(kind):
|
|
if kind == "dwell":
|
|
good = (df.liked == 1) | (df.dwell >= 10000)
|
|
else:
|
|
good = (df.kind == "complete") | (df.liked == 1)
|
|
bad = df.kind == "skip"
|
|
d = df[good | bad].copy()
|
|
d["y"] = good[good | bad].astype(int)
|
|
return d.sort_values("ts")
|
|
|
|
|
|
def cur(d):
|
|
return d.tag_sum + 2 * d.niche_sum + 3 * d.creator_w + 0.3 * d.popul + 0.5 * d.fresh
|
|
|
|
|
|
def formula(d, w):
|
|
return (w["tag"] * d.s_tag_idf_sum + w["creator"] * d.s_creator_w + w["pop"] * d.popul
|
|
+ w["like"] * (d.like_rate - P_LIKE) - w["skip"] * (d.skip_rate - P_SKIP))
|
|
|
|
|
|
for kind in ("dwell", "complete"):
|
|
d = labelled(kind)
|
|
cut = int(len(d) * 0.7)
|
|
tr, te = d.iloc[:cut].copy(), d.iloc[cut:].copy()
|
|
print(f"\n===== etykieta {kind}: trening {len(tr)}, test {len(te)}")
|
|
print(" AUC w obrebie urzadzenia (test):")
|
|
for f in ["s_tag_sum", "s_tag_idf_sum", "tag_idf_pos", "s_creator_w", "s_niche_sum", "popul", "like_rate"]:
|
|
print(f" {f:14s} {within(te, f):.3f}")
|
|
cols = ["s_tag_idf_sum", "s_creator_w", "s_niche_sum", "popul", "like_rate", "skip_rate"]
|
|
m = LogisticRegression(max_iter=3000).fit(tr[cols], tr.y)
|
|
coef = dict(zip(cols, m.coef_[0]))
|
|
base = coef["s_tag_idf_sum"]
|
|
print(" wspolczynniki w jednostkach tagu:", {c: round(v / base, 2) for c, v in coef.items()})
|
|
te["cur"] = cur(te)
|
|
te["model"] = m.decision_function(te[cols])
|
|
for name, w in {
|
|
"F1": {"tag": 1.0, "creator": 1.0, "pop": 0.3, "like": 20.0, "skip": 2.0},
|
|
"F2": {"tag": 1.0, "creator": 1.5, "pop": 0.5, "like": 30.0, "skip": 3.0},
|
|
"F3": {"tag": 1.0, "creator": 1.0, "pop": 0.5, "like": 40.0, "skip": 4.0},
|
|
"F4": {"tag": 1.0, "creator": 2.5, "pop": 0.8, "like": 120.0, "skip": 15.0},
|
|
}.items():
|
|
te[name] = formula(te, w)
|
|
print(" porownanie (test): AUC globalnie / w obrebie urzadzenia")
|
|
te["F5"] = formula(te, {"tag": 1.0, "creator": 2.5, "pop": 0.8, "like": 120.0, "skip": 15.0}) + 0.25 * te.s_niche_sum + 0.3 * te.fresh
|
|
for f in ["cur", "model", "F1", "F2", "F3", "F4", "F5"]:
|
|
print(f" {f:6s} {roc_auc_score(te.y, te[f]):.3f} / {within(te, f):.3f}")
|