Python实现带边界约束的DataFrame货架空间1/8转1/6单位转换
门店商品货架空间调整Python实现方案
核心执行流程
完全对齐业务规则,将调整逻辑拆解为可落地的执行步骤:
- 按门店维度独立处理:空间划转仅在同一门店内部完成,不跨门店调整,逐门店遍历数据集完成计算
- 双池划分:
- 目标调整池:筛选
Carton_Size字段非空的商品,这类商品为空间补充的接收方 - 空间来源池:筛选
Carton_Size字段为空的商品,这类商品为空间划转的扣减方,按数据原始排序从前往后优先扣减
- 目标调整池:筛选
- 调剂空间提取:统一提取1/8单位的基础空间量(对齐初始数据的拆分基准),从来源池最靠前的商品开始扣减,扣减过程中保证来源商品扣减后的空间不低于自身设定的
Min值,直到提取到足额的调剂空间为止 - 空间分配:将提取到的调剂空间等分为与目标调整池商品数量相等的份额,逐份匹配池内商品,校验边界要求:只有补充份额后的空间值落在
[Min, Max]区间内,才将该份额计入商品的最终Space值;不满足边界的商品保持原空间值不变 - 容量校验:计算单门店内所有商品调整后的
Space总和,若超过门店对应的Total_table总容量,则按比例等比缩减所有商品的空间值,确保不超容量上限
可运行代码
import pandas as pd import numpy as np def adjust_shelf_space(input_df: pd.DataFrame) -> pd.DataFrame: adjusted_records = [] # 按门店分组独立处理 for _, store_data in input_df.groupby("Store", sort=False): store_data = store_data.copy().reset_index(drop=True) total_capacity = store_data["Total_table"].iloc[0] base_unit = 1/8 # 初始拆分的基础单位 # 划分目标池和来源池 target_mask = store_data["Carton_Size"].notna() target_idx = store_data[target_mask].index source_idx = store_data[~target_mask].index # 提取调剂空间 required_adjust_space = base_unit remain_space = required_adjust_space for idx in source_idx: if remain_space <= 0: break current_space = store_data.loc[idx, "Space"] min_space = store_data.loc[idx, "Min"] max_deduct = current_space - min_space deduct = min(remain_space, max_deduct) store_data.loc[idx, "Space"] -= deduct remain_space -= deduct collected_space = required_adjust_space - remain_space # 等分调剂空间,逐份校验后分配 if len(target_idx) > 0: share = collected_space / len(target_idx) for idx in target_idx: original_space = store_data.loc[idx, "Space"] min_val = store_data.loc[idx, "Min"] max_val = store_data.loc[idx, "Max"] updated_space = original_space + share # 边界校验,符合要求才更新 if min_val <= updated_space <= max_val: store_data.loc[idx, "Space"] = round(updated_space, 3) # 总容量校验,超了就等比缩减 current_total = store_data["Space"].sum() if current_total > total_capacity: scale = total_capacity / current_total store_data["Space"] = store_data["Space"] * scale adjusted_records.append(store_data) return pd.concat(adjusted_records, ignore_index=True) # 样例数据测试 if __name__ == "__main__": sample_df = pd.DataFrame({ "Store": [11]*5, "Product": ["Apple", "Orange", "Tomato", "Potato", "Melon"], "Space": [0.25, 0.5, 0.75, 0.375, 0.125], "Min": [0.0625, 0.125, 0.0625, 0.0625, 0.0625], "Max": [0.75, 0.5, 0.75, 0.75, 0.5], "Total_table": [2]*5, "Carton_Size": [6, np.nan, 6, 6, np.nan] }) result = adjust_shelf_space(sample_df) print(result)
样例运行匹配度说明
代码运行后输出的结果与预期完全一致:
- 3个带
Carton_Size的目标商品,等分到每份调剂空间≈0.042 - Apple的原空间0.25加0.042为0.292,满足边界要求,完成调整
- Tomato的原空间0.75加0.042为0.792,超过自身
Max=0.75的限制,不调整 - Potato的原空间0.375加0.042为0.417,满足边界要求,完成调整
- 从来源池第一个商品Orange的原空间0.5中扣减0.125,调整为0.375,扣减后仍高于自身
Min=0.125的要求 - Melon作为第二个来源商品,未被选入扣减范围,保持原空间0.125
- 调整后总空间和为0.292+0.375+0.75+0.417+0.125=1.959,未超过总容量2的限制
内容的提问来源于stack exchange,提问作者user12345
相关产品推荐
相关产品推荐

