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

如何在Python中按指定价值比例从带值项目列表抽取24个唯一样本?

指定比例匹配的抽样解决方案

你需要从40799个带数值的项目中抽取24个唯一项目,使得每个选中项目的数值占选中总和的比例尽可能匹配给定的24个目标比例(总和为1)。以下是两种可在Python中实现的实用方法:

方法一:贪心迭代调整法

这是一种启发式优化方法,通过迭代替换样本中的项目来逐步缩小实际比例与目标比例的误差。

实现步骤

  1. 定义误差函数:用实际比例与目标比例的平方误差和来衡量匹配程度,误差越小匹配度越高。
  2. 生成初始样本:随机挑选24个唯一项目作为初始集合。
  3. 迭代优化:遍历未选中的项目,尝试替换当前样本中的每个项目,保留能让误差减小的替换操作,重复直到误差不再明显下降或达到迭代上限。

Python代码示例

import pandas as pd
import numpy as np

# 替换为你的实际数据
np.random.seed(42)
data = pd.DataFrame({
    'item_id': [f'id{i}' for i in range(1, 40800)],
    'value': np.random.randint(50000, 100000, size=40799)
})

# 替换为你的目标比例列表(总和需为1)
p_list = np.random.dirichlet(np.ones(24))

def calculate_error(selected_values, target_probs):
    sum_v = selected_values.sum()
    if sum_v == 0:
        return float('inf')
    actual_ratios = selected_values / sum_v
    return np.sum((actual_ratios - target_probs) ** 2)

# 初始随机抽样
initial_idx = np.random.choice(data.index, size=24, replace=False)
current_selected = data.loc[initial_idx].copy()
current_error = calculate_error(current_selected['value'], p_list)

best_error = current_error
best_selected = current_selected.copy()
max_iter = 1000
tolerance = 1e-8
iter_count = 0

while iter_count < max_iter:
    improved = False
    # 逐个尝试替换样本中的项目
    for i in range(24):
        unselected_idx = data.index.difference(current_selected.index)
        # 随机采样候选项目(减少计算量)
        candidate_idx = np.random.choice(unselected_idx, size=100, replace=False)
        for idx in candidate_idx:
            temp_selected = current_selected.copy()
            temp_selected.iloc[i] = data.loc[idx]
            temp_error = calculate_error(temp_selected['value'], p_list)
            if temp_error < current_error - tolerance:
                current_selected = temp_selected.copy()
                current_error = temp_error
                improved = True
                if current_error < best_error:
                    best_error = current_error
                    best_selected = current_selected.copy()
                break
        if improved:
            break
    if not improved:
        break
    iter_count += 1

# 输出结果
print(f"最优匹配误差: {best_error:.6f}")
print("选中项目详情:")
print(best_selected[['item_id', 'value']])

# 验证比例匹配情况
sum_selected = best_selected['value'].sum()
actual_ratios = best_selected['value'] / sum_selected
ratio_compare = pd.DataFrame({
    '目标比例': p_list,
    '实际比例': actual_ratios
})
print("\n比例对比:")
print(ratio_compare.round(4))

方法二:目标权重匹配抽样

通过预估选中项目的总和,为每个目标比例匹配最接近的数值项目,再迭代调整总和重新匹配,快速缩小误差。

实现步骤

  1. 预估初始总和:通过多次随机抽样,计算24个项目总和的平均值作为初始预估总和。
  2. 匹配目标数值:根据每个目标比例和预估总和,计算对应目标数值,在未选中项目中挑选数值最接近的项目。
  3. 迭代调整:用选中项目的实际总和重新计算目标数值,再次匹配项目,重复几次优化结果。

Python代码示例

import pandas as pd
import numpy as np

# 替换为你的实际数据
np.random.seed(42)
data = pd.DataFrame({
    'item_id': [f'id{i}' for i in range(1, 40800)],
    'value': np.random.randint(50000, 100000, size=40799)
})

# 替换为你的目标比例列表(总和需为1)
p_list = np.random.dirichlet(np.ones(24))

# 预估初始选中总和
sample_sums = []
for _ in range(1000):
    sample_sum = data.sample(24)['value'].sum()
    sample_sums.append(sample_sum)
initial_S = np.mean(sample_sums)

# 初始匹配项目
selected = pd.DataFrame(columns=data.columns)
for p in p_list:
    target_v = p * initial_S
    candidates = data[~data.index.isin(selected.index)]
    candidates['diff'] = abs(candidates['value'] - target_v)
    best_item = candidates.sort_values('diff').iloc[0]
    selected = pd.concat([selected, best_item.to_frame().T])

# 迭代调整总和与匹配
for _ in range(5):
    current_S = selected['value'].sum()
    new_selected = pd.DataFrame(columns=data.columns)
    for p in p_list:
        target_v = p * current_S
        candidates = data[~data.index.isin(new_selected.index)]
        candidates['diff'] = abs(candidates['value'] - target_v)
        best_item = candidates.sort_values('diff').iloc[0]
        new_selected = pd.concat([new_selected, best_item.to_frame().T])
    selected = new_selected

# 计算误差与输出结果
sum_selected = selected['value'].sum()
actual_ratios = selected['value'] / sum_selected
error = np.sum((actual_ratios - p_list) ** 2)

print(f"匹配误差: {error:.6f}")
print("选中项目详情:")
print(selected[['item_id', 'value']])

print("\n比例对比:")
ratio_compare = pd.DataFrame({
    '目标比例': p_list,
    '实际比例': actual_ratios
})
print(ratio_compare.round(4))

注意事项

  • 两种方法均为启发式算法,无法保证全局最优,但在实际场景中能满足比例匹配需求。
  • 若数据量极大,可减少方法一中的候选项目采样数量,或减少方法二中的迭代次数以提升效率。
  • 可根据需求替换误差函数(比如用绝对误差代替平方误差)。
  • 可多次尝试不同初始样本,选择误差最小的结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 06:12:01