-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
bump version, Merge pull request tqdm#9 from tqdm/pandas-progress
Add progress bar to pandas apply function
- Loading branch information
Showing
7 changed files
with
182 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import pandas as pd | ||
import numpy as np | ||
from tqdm import tqdm, tqdm_pandas | ||
|
||
df = pd.DataFrame(np.random.randint(0, 100, (100000, 6))) | ||
|
||
# Create and register a new `tqdm` instance with `pandas` | ||
# (can use tqdm_gui, optional kwargs, etc.) | ||
tqdm_pandas(tqdm()) | ||
|
||
# Now you can use `progress_apply` instead of `apply` | ||
df.groupby(0).progress_apply(lambda x: x**2) | ||
|
||
|
||
""" Source code for `tqdm_pandas` (really simple!) """ | ||
# def tqdm_pandas(t): | ||
# from pandas.core.groupby import DataFrameGroupBy | ||
# def inner(groups, func, *args, **kwargs): | ||
# t.total = len(groups) + 1 | ||
# def wrapper(*args, **kwargs): | ||
# t.update(1) | ||
# return func(*args, **kwargs) | ||
# result = groups.apply(wrapper, *args, **kwargs) | ||
# t.close() | ||
# return result | ||
# DataFrameGroupBy.progress_apply = inner |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# future division is important to divide integers and get as | ||
# a result precise floating numbers (instead of truncated int) | ||
from __future__ import absolute_import | ||
|
||
|
||
__author__ = "github.com/casperdcl" | ||
__all__ = ['tqdm_pandas'] | ||
|
||
|
||
def tqdm_pandas(t): # pragma: no cover | ||
""" | ||
Registers the given `tqdm` instance with | ||
`pandas.core.groupby.DataFrameGroupBy.progress_apply`. | ||
It will even close() the `tqdm` instance upon completion. | ||
Examples | ||
-------- | ||
>>> import pandas as pd | ||
>>> import numpy as np | ||
>>> from tqdm import tqdm, tqdm_pandas | ||
>>> | ||
>>> df = pd.DataFrame(np.random.randint(0, 100, (100000, 6))) | ||
>>> tqdm_pandas(tqdm()) # can use tqdm_gui, optional kwargs, etc | ||
>>> # Now you can use `progress_apply` instead of `apply` | ||
>>> df.groupby(0).progress_apply(lambda x: x**2) | ||
References | ||
---------- | ||
https://stackoverflow.com/questions/18603270/ | ||
progress-indicator-during-pandas-operations-python | ||
""" | ||
from pandas.core.groupby import DataFrameGroupBy | ||
|
||
def inner(groups, func, *args, **kwargs): | ||
""" | ||
Parameters | ||
---------- | ||
groups : DataFrameGroupBy | ||
Grouped data. | ||
func : function | ||
To be applied on the grouped data. | ||
*args and *kwargs are transmitted to DataFrameGroupBy.apply() | ||
""" | ||
t.total = len(groups) + 1 # pandas calls update once too many | ||
|
||
def wrapper(*args, **kwargs): | ||
t.update() | ||
return func(*args, **kwargs) | ||
|
||
result = groups.apply(wrapper, *args, **kwargs) | ||
|
||
t.close() | ||
|
||
return result | ||
|
||
# Enable custom tqdm progress in pandas! | ||
DataFrameGroupBy.progress_apply = inner |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
# Definition of the version number | ||
version_info = 3, 2, 0 # major, minor, patch, -extra | ||
version_info = 3, 3, 0 # major, minor, patch, -extra | ||
|
||
# Nice string for the version | ||
__version__ = '.'.join(map(str, version_info)).replace('.-', '-').strip('.-') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
from nose.plugins.skip import SkipTest | ||
|
||
from tqdm import tqdm | ||
|
||
try: | ||
from StringIO import StringIO | ||
except: | ||
from io import StringIO | ||
# Ensure we can use `with closing(...) as ... :` syntax | ||
if getattr(StringIO, '__exit__', False) and \ | ||
getattr(StringIO, '__enter__', False): | ||
def closing(arg): | ||
return arg | ||
else: | ||
from contextlib import closing | ||
|
||
|
||
def test_pandas(): | ||
try: | ||
from numpy.random import randint | ||
from tqdm import tqdm_pandas | ||
import pandas as pd | ||
except: | ||
raise SkipTest | ||
|
||
with closing(StringIO()) as our_file: | ||
df = pd.DataFrame(randint(0, 100, (1000, 6))) | ||
tqdm_pandas(tqdm(file=our_file, leave=False, ascii=True)) | ||
df.groupby(0).progress_apply(lambda x: None) | ||
|
||
our_file.seek(0) | ||
|
||
try: | ||
# don't expect final output since no `leave` and | ||
# high dynamic `miniters` | ||
assert '100%|##########| 101/101' not in our_file.read() | ||
except: | ||
raise AssertionError('Did not expect:\n\t100%|##########| 101/101') | ||
|
||
|
||
def test_pandas_leave(): | ||
try: | ||
from numpy.random import randint | ||
from tqdm import tqdm_pandas | ||
import pandas as pd | ||
except: | ||
raise SkipTest | ||
|
||
with closing(StringIO()) as our_file: | ||
df = pd.DataFrame(randint(0, 100, (1000, 6))) | ||
tqdm_pandas(tqdm(file=our_file, leave=True, ascii=True)) | ||
df.groupby(0).progress_apply(lambda x: None) | ||
|
||
our_file.seek(0) | ||
|
||
try: | ||
assert '100%|##########| 101/101' in our_file.read() | ||
except: | ||
our_file.seek(0) | ||
raise AssertionError('\n'.join(('Expected:', | ||
'100%|##########| 101/101', 'Got:', | ||
our_file.read()))) |