半时间衰减封装函数

[代码]

作者:lh

import math
from typing import Optional

def half_life_decay(
    delta_days: float,
    half_life_days: float,
    *,
    cap_days: Optional[float] = None,
    min_score: float = 0.0,
    max_score: float = 1.0,
) -> float:
    """
    半衰期时间衰减函数(更适合做用户画像/兴趣权重)。

    核心公式:
        score = 0.5 ** (delta_days / half_life_days)

    含义:
      - half_life_days(半衰期)= 过这么多天,权重衰减到原来的 1/2
      - delta_days = 距离行为发生过去了多少天
      - score 越接近 1,代表越“新”的行为影响越大;越接近 0 代表越“旧”的行为影响越小

    参数:
      delta_days: 距离事件发生的天数(>=0,允许 float;例如 0.5 表示半天)
      half_life_days: 半衰期天数(>0),例如 30 表示每过 30 天影响减半
      cap_days: 可选,硬截断阈值;如果 delta_days > cap_days,则直接返回 min_score(表示太久远不计)
      min_score: 最小权重下限(例如 0.0 或 0.001),用于防止极老事件产生“完全为 0”或保留极小影响
      max_score: 最大权重上限(通常 1.0),用于保护值域

    返回:
      float:最终衰减权重(会被 clamp 到 [min_score, max_score])
    """
    # 半衰期必须大于 0,否则公式无意义(会除以 0)
    if half_life_days <= 0:
        raise ValueError("half_life_days must be > 0")

    # 处理异常 delta_days:
    # - None 或 NaN:直接返回最小权重(认为不可用/缺失)
    if delta_days is None or math.isnan(delta_days):
        return min_score

    # delta_days 不应为负数;如果出现(例如时间差算错),就按 0 天处理(最新)
    if delta_days < 0:
        delta_days = 0.0

    # 可选:硬截断
    # 如果你想只看近 90 天画像,那么 90 天前的行为直接不计
    if cap_days is not None and delta_days > cap_days:
        return min_score

    # 半衰期衰减核心:
    # delta_days=0 -> score=1
    # delta_days=half_life_days -> score=0.5
    # delta_days=2*half_life_days -> score=0.25
    score = 0.5 ** (delta_days / half_life_days)

    # clamp(钳制):把 score 限制在 [min_score, max_score] 范围内,避免异常值
    if score < min_score:
        score = min_score
    if score > max_score:
        score = max_score

    return float(score)


def half_life_to_lambda(half_life_days: float) -> float:
    """
    将“半衰期 half_life_days”转换为“指数衰减 lambda”。

    指数衰减公式:
        score = exp(-lambda * delta_days)

    半衰期与 lambda 的关系:
        当 delta_days = half_life_days 时,score = 0.5
        => 0.5 = exp(-lambda * half_life_days)
        => lambda = ln(2) / half_life_days
    """
    if half_life_days <= 0:
        raise ValueError("half_life_days must be > 0")
    return math.log(2.0) / half_life_days


def lambda_to_half_life(lambda_decay: float) -> float:
    """
    将“指数衰减 lambda”转换为“半衰期 half_life_days”。

    由:
        lambda = ln(2) / half_life
    得:
        half_life = ln(2) / lambda
    """
    if lambda_decay <= 0:
        raise ValueError("lambda_decay must be > 0")
    return math.log(2.0) / lambda_decay
import math
from typing import Optional

def half_life_decay(
    delta_days: float,
    half_life_days: float,
    *,
    cap_days: Optional[float] = None,
    min_score: float = 0.0,
    max_score: float = 1.0,
) -> float:
    """
    半衰期时间衰减函数(更适合做用户画像/兴趣权重)。

    核心公式:
        score = 0.5 ** (delta_days / half_life_days)

    含义:
      - half_life_days(半衰期)= 过这么多天,权重衰减到原来的 1/2
      - delta_days = 距离行为发生过去了多少天
      - score 越接近 1,代表越“新”的行为影响越大;越接近 0 代表越“旧”的行为影响越小

    参数:
      delta_days: 距离事件发生的天数(>=0,允许 float;例如 0.5 表示半天)
      half_life_days: 半衰期天数(>0),例如 30 表示每过 30 天影响减半
      cap_days: 可选,硬截断阈值;如果 delta_days > cap_days,则直接返回 min_score(表示太久远不计)
      min_score: 最小权重下限(例如 0.0 或 0.001),用于防止极老事件产生“完全为 0”或保留极小影响
      max_score: 最大权重上限(通常 1.0),用于保护值域

    返回:
      float:最终衰减权重(会被 clamp 到 [min_score, max_score])
    """
    # 半衰期必须大于 0,否则公式无意义(会除以 0)
    if half_life_days <= 0:
        raise ValueError("half_life_days must be > 0")

    # 处理异常 delta_days:
    # - None 或 NaN:直接返回最小权重(认为不可用/缺失)
    if delta_days is None or math.isnan(delta_days):
        return min_score

    # delta_days 不应为负数;如果出现(例如时间差算错),就按 0 天处理(最新)
    if delta_days < 0:
        delta_days = 0.0

    # 可选:硬截断
    # 如果你想只看近 90 天画像,那么 90 天前的行为直接不计
    if cap_days is not None and delta_days > cap_days:
        return min_score

    # 半衰期衰减核心:
    # delta_days=0 -> score=1
    # delta_days=half_life_days -> score=0.5
    # delta_days=2*half_life_days -> score=0.25
    score = 0.5 ** (delta_days / half_life_days)

    # clamp(钳制):把 score 限制在 [min_score, max_score] 范围内,避免异常值
    if score < min_score:
        score = min_score
    if score > max_score:
        score = max_score

    return float(score)


def half_life_to_lambda(half_life_days: float) -> float:
    """
    将“半衰期 half_life_days”转换为“指数衰减 lambda”。

    指数衰减公式:
        score = exp(-lambda * delta_days)

    半衰期与 lambda 的关系:
        当 delta_days = half_life_days 时,score = 0.5
        => 0.5 = exp(-lambda * half_life_days)
        => lambda = ln(2) / half_life_days
    """
    if half_life_days <= 0:
        raise ValueError("half_life_days must be > 0")
    return math.log(2.0) / half_life_days


def lambda_to_half_life(lambda_decay: float) -> float:
    """
    将“指数衰减 lambda”转换为“半衰期 half_life_days”。

    由:
        lambda = ln(2) / half_life
    得:
        half_life = ln(2) / lambda
    """
    if lambda_decay <= 0:
        raise ValueError("lambda_decay must be > 0")
    return math.log(2.0) / lambda_decay