我怎样才能用更快的东西替换 FOR 循环
How can I replace the FOR loop by something faster
我正在尝试根据特定条件转换我的数据框。以下是我的输入数据框
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
- 我看不到从您的代码中删除循环的方法,因为循环正在根据
mydates
和 Delta
的内容创建单独的数据帧。
- 在此示例中,您将创建 75 个不同的数据帧
- 在每个数据框上
.groupby
,然后 .agg
付款 sum
和文件编号 count
。
- 每个数据框都附加到一个列表中。
pd.concat
将完整列表放入数据框。
- 一项显着改进
- 在创建数据帧和执行剩余操作之前检查布尔条件。在此示例中,对 69 个空数据帧执行了操作。通过先检查条件,将只对包含数据的 6 个数据帧执行操作。
condition.any()
returns True
只要至少有一个元素是 True
- 小改动
datetime
+ int
已弃用,因此请将其更改为 datetime
+ timedelta(days=x)
pd.Series(range(0,5)).tolist()
做一个列表有点过分了。现在需要 timedelta
个对象,所以使用 [timedelta(days=x) for x in range(5)]
- 不要使用两个
for-loops
进行迭代,而是在 mydates
和 Delta
上使用 itertools.product
。这将创建一个 (Timestamp('2017-01-01 00:00:00', freq='D'), datetime.timedelta(0))
形式的元组生成器
- 创建数据帧时使用
.copy()
A
,以防止SettingWithCopyWarning
- 注意:
- 问题中提到了一个
list comprehension
。它们只是制作 for-loop
的 pythonic
方法,但不一定会提高性能。
- 所有计算都使用pandas方法,而不是
for-loops
。 for-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
我正在尝试根据特定条件转换我的数据框。以下是我的输入数据框
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
- 我看不到从您的代码中删除循环的方法,因为循环正在根据
mydates
和Delta
的内容创建单独的数据帧。- 在此示例中,您将创建 75 个不同的数据帧
- 在每个数据框上
.groupby
,然后.agg
付款sum
和文件编号count
。 - 每个数据框都附加到一个列表中。
pd.concat
将完整列表放入数据框。
- 一项显着改进
- 在创建数据帧和执行剩余操作之前检查布尔条件。在此示例中,对 69 个空数据帧执行了操作。通过先检查条件,将只对包含数据的 6 个数据帧执行操作。
condition.any()
returnsTrue
只要至少有一个元素是True
- 小改动
datetime
+int
已弃用,因此请将其更改为datetime
+timedelta(days=x)
pd.Series(range(0,5)).tolist()
做一个列表有点过分了。现在需要timedelta
个对象,所以使用[timedelta(days=x) for x in range(5)]
- 不要使用两个
for-loops
进行迭代,而是在mydates
和Delta
上使用itertools.product
。这将创建一个(Timestamp('2017-01-01 00:00:00', freq='D'), datetime.timedelta(0))
形式的元组生成器
- 创建数据帧时使用
.copy()
A
,以防止SettingWithCopyWarning
- 注意:
- 问题中提到了一个
list comprehension
。它们只是制作for-loop
的pythonic
方法,但不一定会提高性能。 - 所有计算都使用pandas方法,而不是
for-loops
。for-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