
本文详细介绍了如何在pandas数据框中,以可扩展的方式根据分组条件(如商店和工人)自动化分配“箱子”数量。通过`groupby().transform()`结合自定义函数,实现了为每个工人分配最多100个箱子,并处理了单人商店的特殊情况,避免了手动`iloc`索引的不可伸缩性,显著提升了数据处理效率和代码的健壮性。
在数据处理和资源分配场景中,我们经常需要根据特定规则将总量分配给不同的实体。一个常见需求是,在分组数据中,按照优先级为每个组内成员分配资源,并遵循最大容量限制,同时可能存在特殊情况(例如,当组内成员数量为一时)。手动处理这些分配逻辑,特别是当组规模或组数量庞大时,会变得极其繁琐且难以维护。本教程将展示如何利用Pandas的强大功能,特别是groupby().transform()方法,以一种高效、可扩展且易于理解的方式解决此类问题。
假设我们有一个包含商店、工人、工人拥有的箱子数量以及待分配的“最优箱子”数量的数据框。我们的目标是根据以下规则填充optimal_boxes列:
以下是示例数据框:
import pandas
import numpy
data_stack_exchange = {'store': ['A','B', 'B', 'C', 'C', 'C', 'D', 'D', 'D', 'D'],
'worker': [1,1,2,1,2,3,1,2,3,4],
'boxes': [105, 90, 100, 80, 10, 200, 70, 210, 50, 0],
'optimal_boxes': [0,0,0,0,0,0,0,0,0,0]}
df_stack_exchange = pandas.DataFrame(data_stack_exchange)
print("原始数据框:")
print(df_stack_exchange)原始的数据框如下:
store worker boxes optimal_boxes 0 A 1 105 0 1 B 1 90 0 2 B 2 100 0 3 C 1 80 0 4 C 2 10 0 5 C 3 200 0 6 D 1 70 0 7 D 2 210 0 8 D 3 50 0 9 D 4 0 0
预期的结果数据框如下:
store worker boxes optimal_boxes 0 A 1 105 105 1 B 1 90 100 2 B 2 100 90 3 C 1 80 100 4 C 2 10 100 5 C 3 200 90 6 D 1 70 100 7 D 2 210 100 8 D 3 50 100 9 D 4 0 30
一个常见的初学者方法是使用groupby().apply()结合条件判断和手动iloc索引来处理每个组。然而,这种方法存在严重缺陷:它要求针对不同组大小编写冗长的if/elif语句,并且在每个分支中手动指定iloc索引。这不仅导致代码重复,而且当组大小增加时,代码将变得难以维护和扩展。
为了解决上述问题,我们可以设计一个更通用的函数,该函数能够处理任意大小的组,并利用pandas.groupby().transform()方法将结果高效地应用回原始数据框。transform()方法特别适用于此类场景,因为它要求自定义函数返回一个与输入组具有相同索引和长度的Series或DataFrame,从而可以直接将结果映射回原始数据框的相应位置。
我们将创建一个名为assign_boxes的函数,它接收一个Pandas Series(代表一个商店中所有工人的boxes列),并返回一个列表,其中包含每个工人应获得的optimal_boxes数量。
大部分的工资还是以打印工资条的形式进行,偶有公司使用邮件发放工资条,而工资条的现代形式应该是移动工资条,以实现信息的备忘、到达、管理、对帐、环保、高效等需求……,用户已经习惯使用手机(或以其它移动方式)实现一切需求,应用的移动化是大势所趋。工资查查就在这样的背景下诞生,北京亦卓科技于2017的开发并推出了微信小程序工资查查。由于对有用户对数据隐私与安全性的考虑,北京亦卓科技在推出了云端应用--工资
0
def assign_boxes(s: pandas.Series) -> list:
"""
根据分配规则计算每个工人的最优箱子数量。
参数:
s (pandas.Series): 一个商店中所有工人的 'boxes' 列。
返回:
list: 对应每个工人应分配的 'optimal_boxes' 数量列表。
"""
total_boxes = s.sum() # 计算当前商店箱子总数
num_workers = len(s) # 获取当前商店的工人数量
# 处理单人商店的特殊情况:如果只有一个工人,他将获得所有箱子
if num_workers == 1:
return [total_boxes]
# 对于多于一个工人的商店,计算能分配满100箱子的工人数量
# d 是能够获得完整100箱子的工人数量。
# min(total_boxes // 100, num_workers - 1) 的逻辑是:
# 1. total_boxes // 100 给出理论上能分配满100箱子的工人数量。
# 2. num_workers - 1 是为了确保至少有一个工人(最后一个工人)可以获得剩余的箱子,
# 即使这部分箱子超过100。这样避免了所有工人都分配满100后,还有箱子剩余但无人接收的情况。
d = min(total_boxes // 100, num_workers - 1)
# 构建分配列表
# 1. [100] * d: 前 d 个工人每人获得 100 箱子。
# 2. [total_boxes - 100 * d]: 第 d+1 个工人获得剩余的所有箱子。
# 3. [0] * (num_workers - d - 1): 如果还有多余的工人,他们将获得 0 箱子。
assigned_list = [100] * d + [total_boxes - 100 * d] + [0] * (num_workers - d - 1)
return assigned_list
为了更好地理解上述函数,我们通过几个示例来逐步分析其工作原理:
示例 1: 商店D的箱子分配 (s = [70, 210, 50, 0])
示例 2: 商店B的箱子分配 (s = [90, 100])
现在,我们可以将这个函数应用到我们的数据框中。首先,我们需要确保每个商店内的工人是按优先级(worker列)排序的,因为我们的分配逻辑是基于顺序的。然后,使用groupby('store')['boxes'].transform(assign_boxes)来执行分配。
# 确保在每个商店内部,工人是按 worker ID 排序的,以便正确分配优先级
df_stack_exchange_sorted = df_stack_exchange.sort_values(by=['store', 'worker']).copy()
# 应用自定义函数,并将其结果直接赋值给 'optimal_boxes' 列
df_stack_exchange_sorted['optimal_boxes'] = df_stack_exchange_sorted.groupby('store')['boxes'].transform(assign_boxes)
print("\n最终分配结果数据框:")
print(df_stack_exchange_sorted)输出结果:
最终分配结果数据框: store worker boxes optimal_boxes 0 A 1 105 105 1 B 1 90 100 2 B 2 100 90 3 C 1 80 100 4 C 2 10 100 5 C 3 200 90 6 D 1 70 100 7 D 2 210 100 8 D 3 50 100 9 D 4 0 30
这个结果与我们预期的完全一致。
通过本教程,我们学习了如何利用Pandas的groupby().transform()方法,结合一个精心设计的自定义函数,高效且可扩展地解决分组数据中的条件分配问题。这种方法不仅避免了传统手动iloc索引带来的不可伸缩性,还通过将复杂逻辑封装在通用函数中,显著提升了代码的专业性和可维护性。掌握这种模式对于处理大规模数据集和实现复杂业务逻辑的自动化至关重要。
以上就是利用Pandas实现数据框分组条件分配的自动化与优化的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号