如何使用多线程或并行处理来减少运行时间?

2024-06-28 11:17:15 发布

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

我有嵌套的循环,并希望检查外循环值与每个内循环值的总和。我正在得到想要的结果,但这需要几个小时。有什么办法可以缩短时间吗。你知道吗

我使用df.iterrows()遍历所有行。df1大小为100万,df2大小为1000。你知道吗

如果时间能减少到5-10分钟甚至更少,那将是非常有帮助的,因为同样的工作需要每天重复。你知道吗

这是数据帧的外观:

df1......
       col1      col2  NEWVALUE
0  0.727900  0.007912       NaN
1  0.249418  0.087288       NaN
2  0.592969  0.443518       NaN
3  0.832903  0.101647       NaN
4  0.129666  0.321423       NaN
df2...
       col1      col2  OLDVALUE
0  0.176620  0.857886        43
1  0.758241  0.086826       609
2  0.855264  0.959226       388
3  0.929884  0.349760       137
4  0.693689  0.375171         0

代码如下:

list_values = []
for idx, xitems in df1.iterrows():
    savVal = -1
    i = 99
    for idy, yitems in df2.iterrows():
        value = xitems[‘col1’] + xitems[‘col2’] + yitems[‘col1’] + yitems[‘col2’]
        #it only runs for the first time to store the value into savVal
        if savVal == -1:
            savVal = value

        else:
            if value <= 1 and value < savVal:
                savVal = value
                i = idy
                break
    if i == 99:
        #df1.iat[idx , ‘NEWVALUE’] = “LESSTHAN”
        #in case above code throws error then alternative is list
        list_values.append(“LESSTHAN”)
    else:
        #df1.iat[idx, ‘NEWVALUE’] = df2.loc[i, ‘OLDVALUE’]
        list_values.append(df2.loc[i, ‘OLDVALUE’])


Tags: forvaluenanlistcol2col1df1values
1条回答
网友
1楼 · 发布于 2024-06-28 11:17:15

正如评论中提到的,您应该尽量避免iterrows,并从矩阵问题的角度来考虑这一点。我的第一步是分别计算每个数据帧的“col1”和“col2”之和

df1["sum_col"] = df1["col1"] + df1["col2"]
df2["sum_col"] = df2["col1"] + df2["col2"]

然后,这些数字可以加上一点numpy魔法,得到两个数字的所有可能和

all_values = (df1["sum_col"].values[np.newaxis].T +
              df2["sum_col"].values[np.newaxis])

all_values现在将具有形状(1000000, 1000),这是两列的所有可能总和。你知道吗

现在,下一部分是我不太清楚你想做什么。。。如果我错了,请纠正我。在我看来,您正在将savVal设置为df2每次迭代的第一个值(?)在这种情况下,它的形状应该是1000000,所以我们可以这样做

sav_val = all_values[:, 0]

然后我们要找到第一个(?)小于或等于1且小于sav_val的内部循环的值。我们来看看这些条件是否分别满足

less_than_one = np.less_equal(all_values, 1)

以及

less_than_sav_val = np.less(all_values.T, sav_val).T

.T是帮助我们广播到正确形状的转置。你知道吗

我们可以结合我们的两个条件,使用argmax(参见this question)在每行中找到第一个True值,如果没有True值,我们将得到每行中的第一个条目(索引0)

passes_condition = less_than_one & less_than_sav_val
result = df2['OLDVALUE'].values.take(passes_condition.argmax(axis=1))

好的,快到了。result的形状是1000000。现在,我们可以用值<;=1和<;第一次迭代替换那些没有条目的条目。我们现在将它们设置为-999。你知道吗

result[~passes_condition.any(axis=1)] = -999

result的形状是1000000

把它们放在一起

def rajat_func(df1, df2):
    list_values = []
    for idx, xitems in df1.iterrows():
        savVal = -1
        i = 99
        for idy, yitems in df2.iterrows():
            value = xitems['col1'] + xitems['col2'] + yitems['col1'] + yitems['col2']
            #it only runs for the first time to store the value into savVal
            if savVal == -1:
                savVal = value
            else:
                if value <= 1 and value < savVal:
                    savVal = value
                    i = idy
                    break
        if i == 99:
            #df1.iat[idx , ‘NEWVALUE’] = “LESSTHAN”
            #in case above code throws error then alternative is list
            list_values.append(-999)
        else:
            #df1.iat[idx, ‘NEWVALUE’] = df2.loc[i, ‘OLDVALUE’]
            list_values.append(df2.loc[i, 'OLDVALUE'])
    return list_values

def new_func(df1, df2):
    x = (df1["col1"] + df1["col2"]).values
    y = (df2["col1"] + df2["col2"]).values
    all_values = (x[np.newaxis].T + y[np.newaxis])
    sav_val = all_values[:, 0]
    less_than_one = np.less_equal(all_values, 1)
    less_than_sav_val = np.less(all_values.T, sav_val).T
    passes_condition = less_than_one & less_than_sav_val
    result = df2['OLDVALUE'].values.take(passes_condition.argmax(axis=1))
    result[~passes_condition.any(axis=1)] = -999
    return result

df1测试1000行,用df2测试100行。你知道吗

all(new_func(df1, df2) == rajat_func(df1, df2))

这是真的。你知道吗

%timeit rajat_func(df1, df2)

给予

5.07 s ± 115 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit new_func(df1, df2)

给予

601 µs ± 17 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

进步真大!在new_func上运行%time,使用df1df2分别有1000000行和1000行

CPU times: user 4.9 s, sys: 3.05 s, total: 7.96 s
Wall time: 7.99 s

这能解决你的问题吗?还是我完全误解了你的意图?你知道吗

相关问题 更多 >