相关文章推荐
强健的苦瓜  ·  python基础 - 凫弥 ·  1 月前    · 
潇洒的牙膏  ·  ImportError cannot ...·  1 年前    · 
爱搭讪的消炎药  ·  PowerShell ...·  1 年前    · 
干练的创口贴  ·  Koa2 引入ssl证书, ...·  2 年前    · 
个性的红茶  ·  containersnotready ...·  2 年前    · 

在Python中,如何编写这个for循环以加快处理速度?

2 人关注

我对Python不够熟悉,不明白如何能让for循环走得更快。以下是我想做的事情。

假设我们有以下的价格数据框架。

import pandas as pd
df = pd.DataFrame.from_dict({'price': {0: 98, 1: 99, 2: 101, 3: 99, 4: 97, 5: 100, 6: 100, 7: 98}})

我们的目标是创建一个名为updown的新列,将每一行分类为 "向上 "或 "向下",标志着在查看随后的每一行时,首先是什么--向上2,或向下2。

df['updown'] = 0
for i in range(df.shape[0]):
    while df.price.iloc[i+j] < (df.price.iloc[i] + 2) and df.price.iloc[i+j] > (df.price.iloc[i] - 2):
        j= j+1
    if df.price.iloc[i+j] >= (df.price.iloc[i] + 2):
        df.updown.iloc[i] = "Up"
    if df.price.iloc[i+j] <= (df.price.iloc[i] - 2):
        df.updown.iloc[i] = "Down"

这样做很好,但在运行数百万行时,运行速度就太慢了。请注意,我知道一旦代码运行到最后一行,就会抛出一个错误,这对我来说很好。

我在哪里可以学到如何使这样的事情发生得更快(最好是几秒钟,或至少几分钟,而不是10多个小时,这就是现在需要的时间。

python
pandas
batataman
batataman
发布于 2022-08-07
2 个回答
John M.
John M.
发布于 2022-08-07
已采纳
0 人赞同

通过一堆不同的例子,以下代码中的第二种方法对于例子数据集来说,大约快了x75。

import pandas as pd, numpy as np
from random import randint
import time
data = [randint(90, 120) for i in range(10000)]
df1 = pd.DataFrame({'price': data})
t0 = time.time()
df1['updown'] = np.nan
count = df1.shape[0]
for i in range(count):
    j = 1
    up = df1.price.iloc[i] + 2
    down = up - 4
    while (pos := i + j) < count:
        if(value := df1.price.iloc[pos]) >= up:
            df1.loc[i, 'updown'] = "Up"
            break
        elif value <= down:
            df1.loc[i, 'updown'] = "Down"
            break
        else:
            j = j + 1
t1 = time.time()
print(f'Method 1: {t1 - t0}')
res1 = df1.head()
df2 = pd.DataFrame({'price': data})
t2 = time.time()
count = len(df2)
df2['updown'] = np.nan
up = df2.price + 2
down = df2.price - 2
# increase shift range until updown is set for all columns
# or there is insufficient data to change remaining rows
i = 1
while (i < count) and (not (isna := df2.updown.isna()) is None and ((i == 1) or (isna[:-(i - 1)].any()))):
    shift = df2.price.shift(-i)
    df2.loc[isna & (shift >= up), 'updown'] =  'Up'
    df2.loc[isna & (shift <= down), 'updown'] = 'Down'
    i += 1
t3 = time.time()
print(f'Method 2: {t3 - t2}')
s1 = df1.updown
s2 = df2.updown
match = (s1.isnull() == s2.isnull()).all() and (s1[s1.notnull()] == s2[s2.notnull()]).all()
print(f'Series match: {match}')

速度提高的主要原因是,我们不是在python中对行进行迭代,而是对数据的数组进行操作,而这些操作都将在C代码中进行。虽然Python调用pandas或numpy(C语言库)是相当快的,但也有一些开销,如果你经常这样做,很快就会成为限制因素。

性能的提高取决于输入数据,但与数据框架中的行数成比例:行数越多,迭代速度越慢。

   iterations     method1   method2     increase
0         100    0.056002  0.018267     3.065689
1        1000    0.209895  0.005000    41.982070
2       10000    2.625701  0.009001   291.727054
3      100000  108.080149  0.042001  2573.260448
    
这很好,谢谢你!谢谢你解释为什么它处理得更快,这很有帮助。
John M.
John M.
发布于 2022-08-07
0 人赞同

有各种错误阻止了示例代码的工作,至少对我来说是这样。你能确认这是你希望算法做的事情吗?

import pandas as pd
df = pd.DataFrame.from_dict({'price': {0: 98, 1: 99, 2: 101, 3: 99, 4: 97, 5: 100, 6: 100, 7: 98}})
df['updown'] = 0
count = df.shape[0]
for i in range(count):
    j = 1
    up = df.price.iloc[i] + 2
    down = up - 4
    while (pos := i + j) < count:
        if(value := df.price.iloc[pos]) >= up:
            df.loc[i, 'updown'] = "Up"
            break
        elif value <= down:
            df.loc[i, 'updown'] = "Down"
            break
        else: