我经常在超过1500万行左右的数据帧上执行pandas操作,我希望能够访问特定操作的进度指示器。
是否存在基于文本的熊猫分裂-应用-组合操作进度指示器?
例如:
df_users.groupby(['userID', 'requestDate']).apply(feature_rollup)
其中feature_rollup是一个有点复杂的函数,它采用许多DF列,并通过各种方法创建新的用户列。对于大数据帧,这些操作可能需要一段时间,所以我想知道是否有可能在iPython笔记本中有基于文本的输出,以更新我的进度。
到目前为止,我已经尝试了Python的规范循环进度指示器,但它们没有以任何有意义的方式与pandas交互。
我希望在pandas库/文档中有一些我忽略了的东西,可以让人们了解分裂-应用-组合的进展。一个简单的实现可能会查看apply函数正在处理的数据帧子集的总数,并将进度报告为这些子集的完成部分。
这可能是需要添加到库中的东西吗?
由于流行的需求,我在tqdm中添加了熊猫支持(pip install "tqdm>=4.9.0")。与其他答案不同,这不会明显地减慢熊猫的速度——下面是DataFrameGroupBy.progress_apply的一个例子:
import pandas as pd
import numpy as np
from tqdm import tqdm
# from tqdm.auto import tqdm # for notebooks
# Create new `pandas` methods which use `tqdm` progress
# (can use tqdm_gui, optional kwargs, etc.)
tqdm.pandas()
df = pd.DataFrame(np.random.randint(0, int(1e8), (10000, 1000)))
# Now you can use `progress_apply` instead of `apply`
df.groupby(0).progress_apply(lambda x: x**2)
如果你对它的工作原理(以及如何为自己的回调修改它)感兴趣,请参阅GitHub上的示例,PyPI的完整文档,或导入模块并运行帮助(tqdm)。其他支持的函数包括map、applymap、聚合和转换。
EDIT
要直接回答原来的问题,请替换为:
df_users.groupby(['userID', 'requestDate']).apply(feature_rollup)
:
from tqdm import tqdm
tqdm.pandas()
df_users.groupby(['userID', 'requestDate']).progress_apply(feature_rollup)
注:tqdm <= v4.8:
对于4.8以下的tqdm版本,而不是tqdm.pandas(),你必须做:
from tqdm import tqdm, tqdm_pandas
tqdm_pandas(tqdm())
调整Jeff的答案(并将其作为一个可重用的函数)。
def logged_apply(g, func, *args, **kwargs):
step_percentage = 100. / len(g)
import sys
sys.stdout.write('apply progress: 0%')
sys.stdout.flush()
def logging_decorator(func):
def wrapper(*args, **kwargs):
progress = wrapper.count * step_percentage
sys.stdout.write('\033[D \033[D' * 4 + format(progress, '3.0f') + '%')
sys.stdout.flush()
wrapper.count += 1
return func(*args, **kwargs)
wrapper.count = 0
return wrapper
logged_func = logging_decorator(func)
res = g.apply(logged_func, *args, **kwargs)
sys.stdout.write('\033[D \033[D' * 4 + format(100., '3.0f') + '%' + '\n')
sys.stdout.flush()
return res
注意:应用进度百分比内联更新。如果你的函数stout,那么这将不起作用。
In [11]: g = df_users.groupby(['userID', 'requestDate'])
In [12]: f = feature_rollup
In [13]: logged_apply(g, f)
apply progress: 100%
Out[13]:
...
像往常一样,你可以把它添加到你的groupby对象作为一个方法:
from pandas.core.groupby import DataFrameGroupBy
DataFrameGroupBy.logged_apply = logged_apply
In [21]: g.logged_apply(f)
apply progress: 100%
Out[21]:
...
正如评论中提到的,这不是core pandas感兴趣的功能。但是python允许你为许多pandas对象/方法创建这些(这样做会有相当多的工作…尽管你应该能够概括这种方法)。
我已经改变了Jeff的答案,以包括一个总数,这样您就可以跟踪进度和一个变量,只打印每个X次迭代(这实际上提高了很多性能,如果“print_at”相当高)
def count_wrapper(func,total, print_at):
def wrapper(*args):
wrapper.count += 1
if wrapper.count % wrapper.print_at == 0:
clear_output()
sys.stdout.write( "%d / %d"%(calc_time.count,calc_time.total) )
sys.stdout.flush()
return func(*args)
wrapper.count = 0
wrapper.total = total
wrapper.print_at = print_at
return wrapper
clear_output()函数来自
from IPython.core.display import clear_output
如果不是在IPython,安迪·海登的答案是没有它的
如果你像我一样需要在Jupyter/ipython笔记本中如何使用它,这里有一个有用的指南和相关文章的来源:
from tqdm._tqdm_notebook import tqdm_notebook
import pandas as pd
tqdm_notebook.pandas()
df = pd.DataFrame(np.random.randint(0, int(1e8), (10000, 1000)))
df.groupby(0).progress_apply(lambda x: x**2)
请注意_tqdm_notebook的导入语句中的下划线。正如参考文章所提到的,开发正处于后期测试阶段。
截至2021年12月11日更新
我目前正在使用pandas==1.3.4和tqdm==4.62.3,我不确定tqdm作者是哪个版本实现了这一更改,但上面的import语句已弃用。而不是使用:
from tqdm.notebook import tqdm_notebook
截至2022年1月2日更新
现在可以简化.py和.ipynb文件的导入语句:
from tqdm.auto import tqdm
tqdm.pandas()
这应该可以在两种开发环境中正常工作,并且应该在pandas数据框架或其他值得tqdm支持的可迭代对象上工作。
截至2022年5月27日更新
如果你在SageMaker上使用jupyter笔记本,这个组合是有效的:
from tqdm import tqdm
from tqdm.gui import tqdm as tqdm_gui
tqdm.pandas(ncols=50)
由于流行的需求,我在tqdm中添加了熊猫支持(pip install "tqdm>=4.9.0")。与其他答案不同,这不会明显地减慢熊猫的速度——下面是DataFrameGroupBy.progress_apply的一个例子:
import pandas as pd
import numpy as np
from tqdm import tqdm
# from tqdm.auto import tqdm # for notebooks
# Create new `pandas` methods which use `tqdm` progress
# (can use tqdm_gui, optional kwargs, etc.)
tqdm.pandas()
df = pd.DataFrame(np.random.randint(0, int(1e8), (10000, 1000)))
# Now you can use `progress_apply` instead of `apply`
df.groupby(0).progress_apply(lambda x: x**2)
如果你对它的工作原理(以及如何为自己的回调修改它)感兴趣,请参阅GitHub上的示例,PyPI的完整文档,或导入模块并运行帮助(tqdm)。其他支持的函数包括map、applymap、聚合和转换。
EDIT
要直接回答原来的问题,请替换为:
df_users.groupby(['userID', 'requestDate']).apply(feature_rollup)
:
from tqdm import tqdm
tqdm.pandas()
df_users.groupby(['userID', 'requestDate']).progress_apply(feature_rollup)
注:tqdm <= v4.8:
对于4.8以下的tqdm版本,而不是tqdm.pandas(),你必须做:
from tqdm import tqdm, tqdm_pandas
tqdm_pandas(tqdm())