我如何用fas替换FOR循环

2024-04-19 19:18:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我正试图根据某些条件转换我的数据帧。下面是我的输入数据帧

In [11]: df
Out[11]: 
   DocumentNumber     I_Date     N_Date     P_Date  Amount
0            1234 2016-01-01 2017-01-01 2017-10-23   38.38
1            2345 2016-01-02 2017-01-02 2018-03-26   41.00
2            1324 2016-01-12 2017-01-03 2018-03-26   30.37
3            5421 2016-01-13 2017-01-02 2018-03-06  269.00
4            5532 2016-01-15 2017-01-04 2018-06-30  271.00

理想解决方案:

  • 每一行都是一个唯一的文档,我的目标是找到满足上述条件的文档数和它们的总量,如果我每天运行和增量组合。你知道吗
  • 我可以通过for-loop获得我想要的结果,但我知道这不是理想的方法,而且随着数据的增加,速度会变慢。因为我是python新手,所以我需要帮助通过列表理解或任何其他更快的选项来摆脱循环。你知道吗

代码:

d1 = datetime.date(2017, 1, 1)
d2 = datetime.date(2017, 1, 15)

mydates = pd.date_range(d1, d2).tolist()
Delta = pd.Series(range(0,5)).tolist()

df_A =[]


for i in mydates: 
    for j in Delta:
        A = df[(df["I_Date"]<i) & (df["N_Date"]>i+j) & (df["P_Date"]>i) ]
        A["DateCutoff"] = i
        A["Delta"]=j
        A = A.groupby(['DateCutoff','Delta'],as_index=False).agg({'Amount':'sum','DocumentNumber':'count'})
        A.columns = ['DateCutoff','Delta','A_PaymentAmount','A_DocumentNumber']
        df_A.append(A)

df_A = pd.concat(df_A, sort = False)

输出:

In [14]: df_A
Out[14]: 
  DateCutoff  Delta  A_PaymentAmount  A_DocumentNumber
0 2017-01-01      0           611.37                 4
0 2017-01-01      1           301.37                 2
0 2017-01-01      2           271.00                 1
0 2017-01-02      0           301.37                 2
0 2017-01-02      1           271.00                 1
0 2017-01-03      0           271.00                 1

Tags: 数据in文档dffordateout条件
1条回答
网友
1楼 · 发布于 2024-04-19 19:18:27
  1. 我看不到从代码中删除循环的方法,因为循环是基于mydatesDelta的内容创建单独的数据帧。
    • 在本例中,您将创建75个不同的数据帧
    • 在每个数据帧上,您.groupby,然后.agg支付的sum和文档编号的count。你知道吗
    • 每个数据帧都附加到一个列表中。你知道吗
    • pd.concat将完整列表放入数据帧中。你知道吗
  2. 一个显著的改进
    • 在创建数据帧并执行其余操作之前,请检查布尔条件。在本例中,对69个空数据帧执行了操作。通过先检查条件,操作将仅在包含数据的6个数据帧上执行。你知道吗
    • condition.any()返回True,只要至少有一个元素是True
  3. 细微变化
    • datetime+int已弃用,因此将其更改为datetime+timedelta(days=x)
    • pd.Series(range(0,5)).tolist()列一张单子太过分了。现在需要timedelta对象,所以使用[timedelta(days=x) for x in range(5)]
    • 使用mydatesDelta上的itertools.product,而不是使用两个for-loops进行迭代。这将创建一个(Timestamp('2017-01-01 00:00:00', freq='D'), datetime.timedelta(0))形式的元组生成器
    • 在创建数据帧A时使用.copy(),以防止SettingWithCopyWarning
  4. 注:
    • 问题中提到了list comprehension。它们只是一种pythonic的方法,但并不一定能提高性能。你知道吗
    • 所有的计算都使用pandas方法,而不是for-loopsfor-loop只根据条件创建数据帧。你知道吗

更新代码:

from itertools import product
import pandas as pd
from datetime import date, timedelta

d1 = date(2017, 1, 1)
d2 = date(2017, 1, 15)

mydates = pd.date_range(d1, d2)
Delta = [timedelta(days=x) for x in range(5)]

df_list = list()

for t in product(mydates, Delta):
    condition = (df["I_Date"]<t[0]) & (df["N_Date"]>t[0]+t[1]) & (df["P_Date"]>t[0])
    if condition.any():
        A = df[condition].copy()
        A["DateCutoff"] = t[0]
        A["Delta"] = t[1]
        A = A.groupby(['DateCutoff','Delta'],as_index=False).agg({'Amount':'sum','DocumentNumber':'count'})
        A.columns = ['DateCutoff','Delta','A_PaymentAmount','A_DocumentNumber']
        df_list.append(A)

df_CutOff = pd.concat(df_list, sort = False)

输出

  • 和原来一样
  DateCutoff  Delta  A_PaymentAmount  A_DocumentNumber
0 2017-01-01      0           611.37                 4
0 2017-01-01      1           301.37                 2
0 2017-01-01      2           271.00                 1
0 2017-01-02      0           301.37                 2
0 2017-01-02      1           271.00                 1
0 2017-01-03      0           271.00                 1

相关问题 更多 >