在一系列合并操作上使用 tqdm

Use tqdm over a sequence of merge operations

我需要一组(可能很长)合并操作的 tqdm 进度条。 在我的应用程序中,我有一组级联操作,如下所示

data = data.merge(get_data_source1(), on="id", how="left")\
           .merge(get_data_source2(), on="id", how="left")\
           ...
           .merge(get_data_sourceN(), on="id", how="left")

get_data_source<i> 函数的作用无关紧要,它们从某个地方(例如,从不同的文件或不同的数据库)提取数据,并且它们 returns 一个带有“id”的 DataFrame列,这需要几秒钟。

我需要一个与 N 一起使用的进度条。将每个合并操作封装在 lambda 函数中并将它们放入一个可迭代对象中可能是可行的,但它看起来像是一个过度设计且难以阅读的解决方案,如果我试着想想(如果你认为我错了请纠正我)。 另外,我知道可以使用 progress_apply 函数(如报告的 )为每个合并操作添加一个进度条,但这会生成几个 (N) 个短进度条而不是一个单人

为了模拟工作设置,让我们考虑这个玩具示例

import pandas as pd
import numpy as np
import time

data = pd.DataFrame(np.random.randint(0,100,size=(100,3)), columns=["id","A", "B"])

def get_data(col):
    time.sleep(1.0)
    return pd.DataFrame(np.random.randint(0,100,size=(100,2)), columns=["id",col])

data.merge(get_data("C"), on="id", how="left")\
    .merge(get_data("D"), on="id", how="left")\
    .merge(get_data("E"), on="id", how="left")\
    .merge(get_data("F"), on="id", how="left")\
    .merge(get_data("G"), on="id", how="left")\
    .merge(get_data("H"), on="id", how="left")

解决问题的最佳方法是什么?

您可以使用要应用函数 get_data 的值创建一个列表,然后使用 tqdm 迭代此列表。

import pandas as pd
import numpy as np
import time
import tqdm


data = pd.DataFrame(np.random.randint(0,100,size=(100,3)), columns=["id","A", "B"])

def get_data(col):
    time.sleep(1.0)
    return pd.DataFrame(np.random.randint(0,100,size=(100,2)), columns=["id",col])

values = ["C","D","E","F","G","H"]

for i in tqdm.tqdm(values):
    data = data.merge(get_data(i), on="id", how="left")
data

您可以像上例一样在每一步将合并的数据帧分配给数据数据帧,或者使用 inplace 参数来避免在每一步返回新的数据帧。

编辑: 由于所有 get_data 函数都不同,我建议像问题一样创建一个可迭代的函数。不需要使用 lambda,如下例所示:

functions = [get_data1,get_data2,get_data3]
for func in functions:
    data = func(param1,param2,param3)

这将遍历列表的所有函数并使用给定的参数执行它们。

我建议使用 functools.reduce

这是一些示例数据框的片段,但它适用于任何可迭代的数据框,只需用 tqdm 包裹它。

import functools
import numpy as np
import pandas as pd
from tqdm.auto import tqdm

N = 10
columns = [["A", "B"], ["C"], ["D", "E", "F"]]
dfs = [
    pd.DataFrame(
        {
            "key": range(N),
            **{c: np.random.rand(N) for c in cols}
        }
    )
    for cols in columns
]
functools.reduce(lambda x, y: x.merge(y), tqdm(dfs[1:]), dfs[0])