【问题标题】:Why is my Python code running so slow? How can I speed it up?为什么我的 Python 代码运行这么慢?我怎样才能加快速度?
【发布时间】:2021-08-02 00:03:27
【问题描述】:

我正在编写与库存管理相关的代码。我写了一个关于最迟日期的代码,为即将缺货的产品提供新产品。

这是我当前的数据。

df = pd.DataFrame({
    'SKU' : ["20651","27394","28443","27766","23767","24704","27824","19612","27339","27851"],
    'DailyMean': [6,9,6,7,9,3,4,8,7,1],
    'Stock': [8,15,9,5,4,11,19,16,28,29],
    'LeadTime': [5,6,6,8,3,7,4,1,8,1],
    'alert': [False,False,False,False,False,False,True,True,False,True],
    'LeadDate': ["2021-05-11","2021-05-11","2021-05-11","2021-05-11","2021-05-11","2021-05-11","2021-05-11","2021-05-11","2021-05-11","2021-05-11",]                    
})

    SKU   DailyMean  Stock  LeadTime    alert   LeadDate
0   20651      6       8       5        False   2021-05-11
1   27394      9      15       6        False   2021-05-11
2   28443      6       9       6        False   2021-05-11
3   27766      7       5       8        False   2021-05-11
4   23767      9       4       3        False   2021-05-11
5   24704      3      11       7        False   2021-05-11
6   27824      4      19       4        True    2021-05-11
7   19612      8      16       1        True    2021-05-11
8   27339      7      28       8        False   2021-05-11
9   27851      1      29       1        True    2021-05-11

这是我写的代码。

for i in range(len(df)):
    new_stock = df.Stock[i]
    x = 0
    
    while((new_stock - (df.LeadTime[i] * df.DailyMean[i])) > 0):
        new_stock = new_stock - (df.LeadTime[i] * df.DailyOrder[i])
        if new_stock >= 0:
            x = x + 1

    df.LeadDate[i] = df.LeadDate[i] + datetime.timedelta(days=x)

这是我的预期。

    SKU   DailyMean  Stock  LeadTime    alert   LeadDate
0   20651      6       8       5        False   2021-05-11
1   27394      9      15       6        False   2021-05-11
2   28443      6       9       6        False   2021-05-11
3   27766      7       5       8        False   2021-05-11
4   23767      9       4       3        False   2021-05-11
5   24704      3      11       7        False   2021-05-11
6   27824      4      19       4        True    2021-05-12
7   19612      8      16       1        True    2021-05-12
8   27339      7      28       8        False   2021-05-11
9   27851      1      29       1        True    2021-06-08

这段代码也在大数据上运行了很长时间。如何优化此代码以更快地运行。

【问题讨论】:

  • 确保数据不存储在代码文件中,而是以某种格式(例如 json、csv 等)存储在代码文件之外...
  • 其实我是从 SQL 数据库中获取数据的
  • DailyMean 是计算列吗?因为我没有看到它包含在您的示例代码中?
  • 数据库的大小是多少? (以兆字节为单位)因为对于某些非常大的数据库而言,在 SQL 上获取它可能会很慢
  • 如果我错了,请纠正我,您是否能够检索整个数据库或者您必须进行多个查询

标签: python dataframe performance for-loop


【解决方案1】:

我认为您的问题是算法复杂度不好:循环中的代码在您想要 O(1) 的地方具有 O(n) 复杂度。

我不太明白你代码的语义,所以我猜你想实现以下目标:

  • 您拥有一定数量的资源(称为stock
  • 该资源将定期减少(您通过减去 leadTime * dailyMean 来表示)
  • 您想知道:我还能在多少时间段内拥有可用资源 - 或者换句话说:我什么时候会用完这些资源?

所以,您的代码要回答的问题是:如果我有 500 件库存,并且我定期卖出 10 件,我会在多少个时期内缺货?

您使用循环实现了这一点:

stock = 500
daily_reduction = 10
days = 0
while (stock - daily_reduction) >= 0:
    days += 1
    stock -= daily_reduction

这里的重要方面如下:对于这个计算,循环必须运行days 次,所以我们有 O(n) 复杂度。很容易看出我们如何才能更快地计算:

stock = 500
daily_reduction = 10
days = stock // daily_reduction  # // is integer divion, which we want here.

这段代码只需要进行一次除法即可得到结果,因此它的运行复杂度为 O(1)。

另外,您有一个pandas.DataFrame,但您正在 python 中手动进行计算。您可能想要执行以下操作:

# element-wise division of the elements: How often can we subtract until we hit 0?
subtract_counts = df.Stock // (df.LeadTime * df.DailyMean)

# transform numbers to datetimes
days_to_add = subtract_counts.apply(lambda x: datetime.timedelta(days=x))

# element-wise add
df.LeadDate += days_to_add

注意:这个计算有点不同:你的 while 循环有条件> 0,但在这里我们在语义上使用>= 0,但我想你还是想这样做?如果我误解了,请纠正我。

这种方法应该运行得相当快,也适用于大量数据。您提供的(非常小的)样本数据的基准表明速度提高了 4 倍,即使内部 while 循环对于大多数列都没有执行一次。

【讨论】:

  • 我会在这里补充:最让我困惑的是你减去了(leadTime * dailyMean)。我认为,为了使这具有正确的现实意义,您宁愿做的是除以 dailyMean 以找出您何时会缺货,然后从这些时间点中减去 leadTime 以找出您何时必须订购,以便在您缺货之前订单到达。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-22
  • 2020-06-28
  • 2023-03-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多