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

如何用Pandas、Numpy、Itertools创建总和相近的分组?含DataFrame文件分组场景

如何用Pandas/Numpy/Itertools创建总和相近的分组?

核心思路:贪心算法(快速且实用)

既然你提到不需要严格的最优解(毕竟背包问题的精确解法太耗时),贪心算法绝对是性价比最高的选择——尤其是处理文件大小这类场景,速度快且结果足够接近平均值,完全能满足需求。

步骤拆解(结合Pandas实现)

先假设你的DataFrame结构是这样的:

import pandas as pd
import numpy as np

# 示例数据
df = pd.DataFrame({
    'file_name': ['file1', 'file2', 'file3', 'file4', 'file5', 'file6'],
    'size': [100, 200, 150, 300, 250, 180]
})
n_groups = 3  # 要分成的组数
  1. 先排序(关键操作!)
    把文件按大小从大到小排序,这是贪心算法的核心——先把大文件分配妥当,避免最后剩下大文件导致分组严重失衡。
df_sorted = df.sort_values('size', ascending=False).reset_index(drop=True)
  1. 初始化分组容器
    用列表存储每个分组的总大小,以及对应的文件列表:
group_sizes = [0] * n_groups
groups = [[] for _ in range(n_groups)]
  1. 逐个分配文件
    遍历每个文件,把它放到当前总大小最小的分组里:
for idx, row in df_sorted.iterrows():
    # 找到当前总大小最小的分组索引
    smallest_group_idx = np.argmin(group_sizes)
    # 将文件加入该分组
    groups[smallest_group_idx].append(row['file_name'])
    # 更新分组总大小
    group_sizes[smallest_group_idx] += row['size']
  1. 查看最终结果
    打印分组和对应的总大小:
for i, (files, total_size) in enumerate(zip(groups, group_sizes), 1):
    print(f"分组{i}: 文件={files}, 总大小={total_size}")

为什么这个方法好用?

  • 速度快:时间复杂度是O(m log m + m*n)(m是文件数),比动态规划的背包解法快太多,适合处理大数量的文件。
  • 结果足够平衡:先处理大文件的逻辑,避免了大文件最后无处可去的尴尬,分组总大小的差异通常很小。
  • 实现简单:用基础的Pandas和Numpy操作就能完成,不需要依赖复杂的第三方库。

进阶优化:迭代调整(可选)

如果想让结果更接近平均值,可以在贪心分配后做一次小调整:遍历每个分组,把分组里的小文件和其他分组的小文件交换,看是否能缩小总大小的差异。比如:

# 计算目标平均值
target_avg = df['size'].sum() / n_groups

# 尝试调整分组,缩小差异
for i in range(n_groups):
    for j in range(i+1, n_groups):
        # 仅当分组i超均值、分组j低于均值时尝试调整
        if group_sizes[i] > target_avg and group_sizes[j] < target_avg:
            # 找到两个分组里最小的文件
            get_size = lambda x: df.loc[df['file_name']==x, 'size'].values[0]
            file_i = min(groups[i], key=get_size)
            file_j = min(groups[j], key=get_size)
            size_i = get_size(file_i)
            size_j = get_size(file_j)
            
            # 判断交换后是否更接近平均值
            new_i_size = group_sizes[i] - size_i + size_j
            new_j_size = group_sizes[j] - size_j + size_i
            if abs(new_i_size - target_avg) < abs(group_sizes[i] - target_avg) and abs(new_j_size - target_avg) < abs(group_sizes[j] - target_avg):
                # 执行交换
                groups[i].remove(file_i)
                groups[i].append(file_j)
                groups[j].remove(file_j)
                groups[j].append(file_i)
                group_sizes[i] = new_i_size
                group_sizes[j] = new_j_size

这个调整步骤能进一步缩小分组间的差异,而且不会增加太多耗时。

关于Itertools的说明

Itertools适合生成所有可能的组合,但当文件数量超过10个时,组合数会爆炸式增长,完全不实用。所以除非你的文件数量非常少(比如5个以内),否则不建议用Itertools来解决这个问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:08:18