我对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]):
    j=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多个小时的时间).

推荐答案

运行一系列不同的示例,下面代码中的第二个方法对于示例数据集来说大约快了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

Python相关问答推荐

Select 用a和i标签包裹的复选框?

即使在可见的情况下也不相互作用

Python daskValue错误:无法识别的区块管理器dask -必须是以下之一:[]

将jit与numpy linSpace函数一起使用时出错

查找两极rame中组之间的所有差异

如何将Docker内部运行的mariadb与主机上Docker外部运行的Python脚本连接起来

如何获取numpy数组的特定索引值?

如何在Polars中从列表中的所有 struct 中 Select 字段?

Pandas—在数据透视表中占总数的百分比

使用Python从URL下载Excel文件

Plotly Dash Creating Interactive Graph下拉列表

CommandeError:模块numba没有属性generated_jit''''

通过ManyToMany字段与Through在Django Admin中过滤

无法在Spyder上的Pandas中将本地CSV转换为数据帧

当HTTP 201响应包含 Big Data 的POST请求时,应该是什么?  

合并相似列表

如何获得满足掩码条件的第一行的索引?

如何在Quarto中的标题页之前创建序言页

如何在表单中添加管理员风格的输入(PDF)

有没有一种方法可以根据不同索引集的数组从2D数组的对称子矩阵高效地构造3D数组?