看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
本例将演示一个商品仓储物流的分配逻辑写法,看看 pandas 是如何实现这种规划问题的。
本案例在 pandas 2.2 下通过。
我们有一个需求数据,代表了订单,订单中每个商品的下单时间及数量:
import pandas as pd
import io
data1 = '''
ID Item 需求日期 需求数量
1 A 2023/9/8 50
2 A 2023/9/10 50
3 B 2023/9/7 50
4 B 2023/9/11 30
'''
df1 = pd.read_csv(io.StringIO(data1), sep=r'\s+')
df1
# ...
另外是一个仓库的供货情况表,每个商品批次的数量:
data2 = '''
Item 供货日期 供货数量
A 2023/9/7 40
A 2023/9/8 40
A 2023/9/11 40
B 2023/9/6 20
B 2023/9/7 20
B 2023/9/8 20
'''
df2 = pd.read_csv(io.StringIO(data2), sep='\s+')
df2
# ...
最终要得到一个订单需求与供货分配的对照表,按订单需求量对仓库供货进行分配,按订单时间优先分配历史未分配完的订单,先进先出,直到满足需求量为止。多出或不足的量用空白表示。
如下:
data = '''
ID Item 需求日期 需求数量 供货日期 供货数量
1 A 2023/9/8 50 2023/9/7 40
1 A 2023/9/8 50 2023/9/8 10
2 A 2023/9/10 50 2023/9/8 30
2 A 2023/9/10 50 2023/9/11 20
2 A None None 2023/9/11 20
3 B 2023/9/7 50 2023/9/6 20
3 B 2023/9/7 50 2023/9/7 20
3 B 2023/9/7 50 2023/9/8 10
4 B 2023/9/11 30 2023/9/8 10
4 B 2023/9/11 30 None None
'''
df = pd.read_csv(io.StringIO(data), sep='\s+')
df
# ...
在订单需求和仓库商品中,商品 Item 内进行分配,即不同商品不能互相分配,所以我们需要分组来完成这个事,以 Item 分组分别分配 A 和 B 商品。我们可以先对 Item 进行分组,然后写个函数来处理各个商品的分配问题,这样,问题就限定在了同一商品的分配上。
接下的我们其实可以通过迭代的方式按照逻辑进行分配,它在个这过程比较复杂,我们可以尝试用模拟分配的情况来「暴力」完成需求。
df1 订单需求和 df2 仓库供货情况中都有相应的数量,我们可以将这两个 DataFrame 根据数量扩展为明细,即一行就是一个货,比如 df1 总共有 180 个商品,就会产生 180 行数据,扩展后的新数据的自然索引可以认为是它们的需求编号和商品编号,需求和供应是一一对应的。
最后按照两个表的索引将它们按列拼接起来,就实现了需求和供应的一一对应,最后再分组聚合计算出每个商品对应需求的供货数量。
def func(a: pd.DataFrame, b: pd.DataFrame) -> pd.DataFrame:
b = b.loc[b.Item == a.name]
a = (
a.loc[a.index.repeat(a.需求数量)]
.reset_index(drop=True)
)
b = (
b.loc[b.index.repeat(b.供货数量)]
.reset_index(drop=True)
)
return (
pd.concat([a, b], axis=1)
.groupby(['ID', '需求日期', '需求数量', '供货日期'],
as_index=False,
sort=False,
dropna=False)
.count()
.drop('Item', axis=1)
.assign(ID=lambda x: x.ID.ffill().astype(int))
.replace({0: pd.NA})
)
(
df1.groupby('Item')
.apply(func, b=df2, include_groups=False)
.reset_index()
.drop('level_1', axis=1)
.reindex(df.columns, axis=1)
)
'''
ID Item 需求日期 需求数量 供货日期 供货数量
0 1 A 2023/9/8 50.0 2023/9/7 40
1 1 A 2023/9/8 50.0 2023/9/8 10
2 2 A 2023/9/10 50.0 2023/9/8 30
3 2 A 2023/9/10 50.0 2023/9/11 20
4 2 A NaN NaN 2023/9/11 20
5 3 B 2023/9/7 50.0 2023/9/6 20
6 3 B 2023/9/7 50.0 2023/9/7 20
7 3 B 2023/9/7 50.0 2023/9/8 10
8 4 B 2023/9/11 30.0 2023/9/8 10
9 4 B 2023/9/11 30.0 NaN <NA>
'''
这样就完成了需求。
(完)
更新时间:Aug. 18, 2024, 4:17 p.m. 标签:pandas python 拼接