feat(classify): super-linear positive weighting by hit count

正向改为按命中次数 n(require_title + reaction + charge + weak)做平方加权,使多信号同现的真 reaction 不被单个负向词打穿(1+1>2、1+1+1>5);标题不含 require_title 直接 0 分。库内 796 条有效视频复测:线以下误伤由 47 降至 14。
This commit is contained in:
kairee committed 2026-11-01 19:08:59 +08:00
1 parent 742c67a1c3
commit 337e379514
4 files changed
+78 -75

No files matched your search

+15 -23
View File
@@ -74,11 +74,7 @@ _DATE_PATTERNS = (
)
_DATE_RE = re.compile("|".join(_DATE_PATTERNS))
# 各信号的权重(见 project.md §3.3)。
REACTION_SCORE = 3
CHARGE_MULTI_SCORE = 3
CHARGE_SINGLE_SCORE = 1
WEAK_SCORE = 1
# 负向权重(见 project.md §3.3)。正向改为「命中次数」超线性加权,见 score_item。
NEGATIVE_SCORE = 6
DATE_SCORE = 6
SELF_SCORE = 3
@@ -98,29 +94,25 @@ def score_item(
) -> int:
"""按 project.md §3.3 计算候选分数。
强正向 ``reaction`` 只在标题同时命中 ``require_title`` 时成立;时长只作为
已存在 reaction / charge 信号时的加权,避免纯长录像仅靠时长进池。
正向按**命中次数**超线性加权:每命中一个正向词(``require_title`` / ``reaction``
/ ``charge`` / ``weak_positive``)记 1 次,正向得分 = 命中次数²(1→1、2→4、
3→9……),使多信号同现的真 reaction 不会被单个负向词打穿(1+1>2、1+1+1>5)。
标题不含 ``require_title`` 直接 0 分;时长只在此基础上已有命中时加权。
"""
score = 0
require_title = str(classify.get("require_title") or "")
if require_title and not passes_required_title(title, require_title):
return 0
reaction_matched = bool(matched_words(title, classify.get("reaction")))
reaction_hit = reaction_matched and (
not require_title or passes_required_title(title, require_title)
)
if reaction_hit:
score += REACTION_SCORE
hits = 0
if require_title:
hits += 1
hits += len(matched_words(title, classify.get("reaction")))
hits += len(matched_words(title, classify.get("charge")))
hits += len(matched_words(title, classify.get("weak_positive")))
charge_hits = matched_words(title, classify.get("charge"))
if len(charge_hits) >= 2:
score += CHARGE_MULTI_SCORE
elif len(charge_hits) == 1:
score += CHARGE_SINGLE_SCORE
score = hits * hits
if matched_words(title, classify.get("weak_positive")):
score += WEAK_SCORE
if reaction_hit or charge_hits:
if hits:
boost = classify.get("duration_boost") or {}
gt_60 = int(boost.get("gt_60min", 2))
gt_30 = int(boost.get("gt_30min", 1))