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

如何用Python按指定行数与值总和规则拆分Pandas DataFrame?

数据集分组拆分的Python实现方案

核心需求回顾

  • 4792行数据,总值33367
  • 拆分8组:
    • 前7组:每组≈639行,总和≈4448.93
    • 第8组:≈319行,总和≈2224.5

方法一:高低值配对法(易实现、效率高)

这个思路和你提到的「高值搭配低值」逻辑一致,利用全局平均值和分组目标平均值高度接近的特点,通过偏差值配对快速凑出符合要求的组:

步骤

  1. 计算偏差值:给每条数据添加字段 deviation = 该行值 - 6.963(全局平均值,和分组目标平均值几乎一致)
  2. 排序:将数据按deviation从大到小排序
  3. 双指针分组:用左右指针分别从最大偏差和最小偏差取数,每次取数后更新当前组的行数和总和,直到接近目标阈值(比如行数638-640、总和4440-4458),完成一组后重置指针处理剩余数据。

Python代码示例

import pandas as pd

# 假设数据集是df,包含数值列'value'
df = pd.read_csv('your_dataset.csv')
df['deviation'] = df['value'] - 6.963

# 按偏差从大到小排序
df_sorted = df.sort_values('deviation', ascending=False).reset_index(drop=True)

groups = []
remaining_indices = set(range(len(df_sorted)))

# 处理前7组
for _ in range(7):
    current_group = []
    current_sum = 0.0
    current_count = 0
    left, right = 0, len(df_sorted) - 1
    
    # 定位到剩余数据的首尾指针
    while left not in remaining_indices:
        left += 1
    while right not in remaining_indices:
        right -= 1
    
    # 凑组:先取高偏差值,再补低偏差值平衡总和
    while current_count < 639 and remaining_indices:
        # 优先加左指针的高偏差值
        if left in remaining_indices and (current_sum + df_sorted.loc[left, 'value'] <= 4448.93 + 10 or current_count < 630):
            current_group.append(left)
            current_sum += df_sorted.loc[left, 'value']
            current_count += 1
            remaining_indices.remove(left)
            left += 1
            while left not in remaining_indices and left <= right:
                left += 1
        # 再补右指针的低偏差值
        elif right in remaining_indices and current_count < 639:
            current_group.append(right)
            current_sum += df_sorted.loc[right, 'value']
            current_count += 1
            remaining_indices.remove(right)
            right -= 1
            while right not in remaining_indices and right >= left:
                right -= 1
        else:
            break
    groups.append(df_sorted.loc[current_group])

# 处理第8组(剩余数据自动符合行数和总和要求)
groups.append(df_sorted.loc[list(remaining_indices)])

# 验证每组结果
for i, group in enumerate(groups):
    print(f"第{i+1}组:行数{len(group)},总和{group['value'].sum():.2f}")

方法二:启发式背包算法(追求更精准的总和)

如果高低值配对的结果精度不够,可以用启发式背包算法(精确背包在4k数据量下计算量过大,启发式足够满足需求):

核心思路

针对每个组,从剩余数据中选择指定数量的行,通过贪心替换调整总和,使其尽可能接近目标值:

  1. 随机选取初始组,计算与目标总和的偏差
  2. 迭代替换:总和偏高就替换组内高值为剩余数据的低值;总和偏低就替换组内低值为剩余数据的高值,直到偏差在可接受范围内。

简化代码示例

import pandas as pd

def build_group(remaining_df, target_count, target_sum, tolerance=5):
    # 随机选初始组
    group = remaining_df.sample(n=target_count)
    current_sum = group['value'].sum()
    
    while abs(current_sum - target_sum) > tolerance:
        diff = current_sum - target_sum
        if diff > 0:
            # 替换组内最高值为剩余数据的最低值
            max_idx = group['value'].idxmax()
            min_remaining_idx = remaining_df.drop(group.index)['value'].idxmin()
            group = group.drop(max_idx).append(remaining_df.loc[min_remaining_idx])
        else:
            # 替换组内最低值为剩余数据的最高值
            min_idx = group['value'].idxmin()
            max_remaining_idx = remaining_df.drop(group.index)['value'].idxmax()
            group = group.drop(min_idx).append(remaining_df.loc[max_remaining_idx])
        current_sum = group['value'].sum()
    return group

# 初始化剩余数据
remaining_df = df.copy()
groups = []

# 处理前7组
for _ in range(7):
    group = build_group(remaining_df, 639, 4448.93)
    groups.append(group)
    remaining_df = remaining_df.drop(group.index)

# 处理第8组
groups.append(remaining_df)

# 验证每组结果
for i, group in enumerate(groups):
    print(f"第{i+1}组:行数{len(group)},总和{group['value'].sum():.2f}")

注意事项

  • 数据存在较多高值 outliers(中位数2、标准差13.644),高低值配对法能快速平衡总和,优先推荐
  • 启发式背包的tolerance参数可根据精度要求调整,比如设为1即允许总和偏差±1

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 21:31:07