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

求从DataFrame筛选各Bin列值唯一子集的高效算法

问题描述

现有一个约1万行的DataFrame,结构示例如下:

x         y    Bin1  Bin2  Bin3 
153.0303 -27.17894      10     6     5        
153.0303 -27.17916       8     7     8        
153.0303 -27.17938       1     6     3        
153.0300 -27.17960      10     1     8     

其中Bin1、Bin2、Bin3列的取值均为1-10的整数。需求是从中选取一个随机子集,要求每个Bin列内的取值均唯一(即每个Bin列中1-10各出现一次)。当前采用重复随机选行直至符合条件的暴力方法,效率极低,需更高效的解决方案。

高效解决方案

方法1:逐列锚定+定向替换

核心思路是先锚定一个Bin列的唯一性,再通过定向替换逐步修正其他Bin列的重复值,避免暴力随机的无效尝试。

步骤说明

  1. 锚定首个Bin列:对Bin1列的每个取值(1-10),从原DataFrame中随机抽取一行,组成初始的10行子集,此时Bin1列已完全唯一。
  2. 修正Bin2列重复:检查子集的Bin2列,若存在重复值,针对每个重复值,从原DataFrame中选取满足「Bin2等于该重复值、且Bin1未在当前子集的Bin1中出现」的行,随机替换子集里的重复行,直到Bin2列无重复。
  3. 修正Bin3列重复:同理,针对Bin3列的重复值,从原DataFrame中选取满足「Bin3等于该重复值、且Bin1和Bin2均未在当前子集对应列中出现」的行,随机替换重复行,直到Bin3列无重复。

代码实现

import pandas as pd
import numpy as np

# 假设原数据存储在df中
bin_columns = ['Bin1', 'Bin2', 'Bin3']
target_values = list(range(1, 11))  # 覆盖1-10所有值

# 1. 构建Bin1唯一的初始子集
subset = pd.DataFrame()
for val in target_values:
    # 筛选Bin1等于当前值的所有行
    candidate_rows = df[df['Bin1'] == val]
    # 随机选一行加入子集
    subset = pd.concat([subset, candidate_rows.sample(n=1)], ignore_index=True)

# 2. 修正Bin2列的重复值
while len(subset['Bin2'].unique()) != 10:
    # 找出所有重复的Bin2值
    duplicate_bin2 = subset['Bin2'][subset['Bin2'].duplicated(keep=False)].unique()
    for dup_val in duplicate_bin2:
        # 随机选一个要替换的重复行
        row_to_replace = subset[subset['Bin2'] == dup_val].sample(n=1).iloc[0]
        # 筛选符合条件的候选行:Bin2=dup_val且Bin1不在当前子集的Bin1中
        valid_candidates = df[(df['Bin2'] == dup_val) & (~df['Bin1'].isin(subset['Bin1']))]
        if not valid_candidates.empty:
            new_row = valid_candidates.sample(n=1)
            # 替换行
            subset = subset.drop(row_to_replace.name)
            subset = pd.concat([subset, new_row], ignore_index=True)

# 3. 修正Bin3列的重复值
while len(subset['Bin3'].unique()) != 10:
    duplicate_bin3 = subset['Bin3'][subset['Bin3'].duplicated(keep=False)].unique()
    for dup_val in duplicate_bin3:
        row_to_replace = subset[subset['Bin3'] == dup_val].sample(n=1).iloc[0]
        # 筛选候选行:Bin3=dup_val且Bin1、Bin2均不在当前子集对应列中
        valid_candidates = df[(df['Bin3'] == dup_val) & 
                             (~df['Bin1'].isin(subset['Bin1'])) & 
                             (~df['Bin2'].isin(subset['Bin2']))]
        if not valid_candidates.empty:
            new_row = valid_candidates.sample(n=1)
            subset = subset.drop(row_to_replace.name)
            subset = pd.concat([subset, new_row], ignore_index=True)

# 输出最终符合要求的子集
print(subset)

方法2:排列组合匹配(适用于数据多样性高的场景)

如果原DataFrame中不同Bin值的组合足够丰富,可以将问题转化为寻找一组10行,使得三个Bin列分别是1-10的排列:

  1. 将原数据按(Bin1, Bin2, Bin3)三元组分组,记录每个三元组对应的行(若有重复三元组则保留多行)。
  2. 生成Bin1、Bin2、Bin3的排列组合,筛选出存在于分组中的三元组集合,从中随机选取一组对应的行。

该方法的前提是原数据有足够多的三元组组合,否则可能找不到符合要求的子集,因此方法1的通用性更强。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 03:25:26