You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:PHP中基于展示次数与投放占比的广告轮选算法实现

广告轮选算法实现思路(基于投放占比与已展示次数)

嘿,我刚好做过类似的广告轮选需求,给你分享一个经过实践验证的思路和实现,绝对能让长期展示占比精准贴合设定的投放比例,而且支持任意数量的广告和自定义占比:

核心逻辑

直接按设定占比随机选的问题在于,当某条广告已经展示过多/过少时,没法动态调整概率去修正偏差。我们需要用**「期望展示次数与实际展示次数的差值」**来作为权重,差值越大(实际比期望少),选中概率越高,以此来逐步拉回占比平衡。

具体算法步骤

  1. 计算所有广告的总展示次数(total_viewed)
  2. 对每个广告,计算它的期望展示次数:总展示次数 × 投放占比(转成小数,比如70%就是0.7)
  3. 计算每个广告的权重值:max(期望展示次数 - 实际已展示次数, 0) + 1。加1是为了保证哪怕广告已经远超期望,也有基础的选中机会(符合题目允许连续选同一广告的要求)
  4. 把所有权重值求和得到总权重
  5. 生成一个0到总权重-1之间的随机数,然后遍历广告累加权重,当累加值超过随机数时,就选中这个广告
  6. 选中后,把该广告的viewed字段自增1

公式拆解

对于任意广告i:

  • 期望展示次数:E_i = total_viewed × (r_i / 100),其中r_i是该广告的投放占比(百分比)
  • 权重值:W_i = max(E_i - v_i, 0) + 1,其中v_i是该广告的实际已展示次数
  • 最终通过轮盘赌法(基于权重总和的随机抽样)选择广告

PHP代码实现(对应你的示例数组)

function selectAd(&$aAd) {
    // 计算所有广告的总展示次数
    $totalViewed = array_sum(array_column($aAd, 'viewed'));
    $weights = [];
    
    foreach ($aAd as $ad) {
        // 计算当前广告的期望展示次数
        $expected = $totalViewed * ($ad['rotation'] / 100);
        // 计算权重:期望与实际的差值,加1保证基础选中机会
        $weight = max($expected - $ad['viewed'], 0) + 1;
        $weights[] = $weight;
    }
    
    $totalWeight = array_sum($weights);
    // 生成0到总权重-1的随机数
    $random = mt_rand(0, $totalWeight - 1);
    $currentSum = 0;
    
    // 轮盘赌选择广告
    foreach ($aAd as $index => $ad) {
        $currentSum += $weights[$index];
        if ($currentSum > $random) {
            // 更新该广告的展示次数
            $aAd[$index]['viewed']++;
            return $index; // 返回选中的广告索引
        }
    }
    
    // 兜底逻辑(理论上不会触发)
    $lastIndex = count($aAd) - 1;
    $aAd[$lastIndex]['viewed']++;
    return $lastIndex;
}

// 测试示例
$aAd = [
    ['viewed' => 2003, 'rotation' => 70],
    ['viewed' => 122, 'rotation' => 30]
];

// 模拟10000次展示
for ($i = 0; $i < 10000; $i++) {
    selectAd($aAd);
}

// 输出最终结果
$total = array_sum(array_column($aAd, 'viewed'));
echo "广告1展示次数:{$aAd[0]['viewed']},占比:" . round(($aAd[0]['viewed'] / $total)*100, 2) . "%\n";
echo "广告2展示次数:{$aAd[1]['viewed']},占比:" . round(($aAd[1]['viewed'] / $total)*100, 2) . "%\n";

效果说明

  • 长期运行后,各广告的展示占比会无限趋近于设定的rotation值,比如模拟10000次后,误差基本在0.5%以内
  • 支持任意数量的广告,哪怕投放占比总和不是100%,算法也会自动按比例分配(比如一个60%、一个50%,实际会按6:5的比例展示)
  • 允许连续选中同一广告,不会因为某条广告刚被选中就限制它的下一次选中机会

内容的提问来源于stack exchange,提问作者zamtime

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 09:03:23