-
-
Notifications
You must be signed in to change notification settings - Fork 18.4k
ENH: gb.is_monotonic_increasing #17015 #17453
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 10 commits
d2759d5
4c70dae
d88acdd
53e5a2b
5a30ee4
2e4bb15
3122f1f
a6d0640
4ecc479
ea42697
ffb6200
ee9eb01
ee9fa7e
2c3002f
f24e476
d01b62e
db3e6c0
fb0bc3c
e5a90fa
1a15209
3c13163
d747d35
dd9a7fc
495718c
02d4369
13d4dd9
787c436
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1743,6 +1743,55 @@ def pipe(self, func, *args, **kwargs): | |
""" | ||
return _pipe(self, func, *args, **kwargs) | ||
|
||
@Substitution(name='groupby') | ||
@Appender(_doc_template) | ||
def is_monotonic_increasing(self): | ||
""" | ||
Returns whether each group is monotonically increasing. | ||
|
||
Equivalent to ``.apply(lambda x: x.is_monotonic_increasing)``. | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add a I also think we should keep this for 0.22.0, as it is a new feature, 0.21.1 is for bug fixes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jorisvandenbossche thanks for the feedback. I've gone ahead and fixed the whatsnew references and added the I wanted to clarify the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you need to add it to |
||
Examples | ||
-------- | ||
>>> source_dict = { | ||
... 'A': ['this', 'col', 'is', 'entirely', 'irrelevant', '.'], | ||
... 'B': ['cat_a', 'cat_a', 'cat_a', 'cat_b', 'cat_b', 'cat_b'], | ||
... 'C': [1, 2, 3, 2, 2, 0]} | ||
|
||
>>> df = pd.DataFrame(source_dict) | ||
... df.groupby(['B']).C.is_monotonic_increasing() | ||
B | ||
cat_a True | ||
cat_b False | ||
Name: C, dtype: bool | ||
|
||
""" | ||
return self.apply(lambda x: x.is_monotonic_increasing) | ||
|
||
@Substitution(name='groupby') | ||
@Appender(_doc_template) | ||
def is_monotonic_decreasing(self): | ||
""" | ||
Returns whether each group is monotonically decreasing. | ||
|
||
Equivalent to ``.apply(lambda x: x.is_monotonic_decreasing)``. | ||
|
||
Examples | ||
-------- | ||
>>> source_dict = { | ||
... 'A': ['this', 'col', 'is', 'entirely', 'irrelevant', '.'], | ||
... 'B': ['cat_a', 'cat_a', 'cat_a', 'cat_b', 'cat_b', 'cat_b'], | ||
... 'C': [1, 2, 3, 2, 2, 0]} | ||
|
||
>>> df = pd.DataFrame(source_dict) | ||
... df.groupby(['B']).C.is_monotonic_decreasing() | ||
B | ||
cat_a False | ||
cat_b True | ||
Name: C, dtype: bool | ||
""" | ||
return self.apply(lambda x: x.is_monotonic_decreasing) | ||
|
||
|
||
GroupBy._add_numeric_operations() | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3701,6 +3701,64 @@ def test_cummin_cummax(self): | |
expected = pd.Series([1, 2, 1], name='b') | ||
tm.assert_series_equal(result, expected) | ||
|
||
@pytest.mark.parametrize('in_vals, out_vals', [ | ||
# Basics: strictly increasing (T), strictly decreasing (F), | ||
# abs val increasing (F), non-strictly increasing (T) | ||
([1, 2, 5, 3, 2, 0, 4, 5, -6, 1, 1], | ||
[True, False, False, True]), | ||
# Test with inf vals | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you add a blank line before comments |
||
([1, 2.1, np.inf, 3, 2, np.inf, -np.inf, 5, 11, 1, -np.inf], | ||
[True, False, True, False]), | ||
# Test with nan vals; should always be False | ||
([1, 2, np.nan, 3, 2, np.nan, np.nan, 5, -np.inf, 1, np.nan], | ||
[False, False, False, False]), | ||
]) | ||
def test_is_monotonic_increasing(self, in_vals, out_vals): | ||
# GH 17015 | ||
source_dict = { | ||
'A': ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11'], | ||
'B': ['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd'], | ||
'C': in_vals} | ||
df = pd.DataFrame(source_dict) | ||
result = df.groupby(['B']).C.is_monotonic_increasing() | ||
expected = pd.Series(index=['a', 'b', 'c', 'd'], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can write this as |
||
data=out_vals, | ||
name='C') | ||
expected.index.name = 'B' | ||
tm.assert_series_equal(result, expected) | ||
|
||
# Also check result equal to manually taking x.is_monotonic_increasing. | ||
expected = ( | ||
df.groupby(['B']).C.apply(lambda x: x.is_monotonic_increasing)) | ||
tm.assert_series_equal(result, expected) | ||
|
||
@pytest.mark.parametrize('in_vals, out_vals', [ | ||
# Basics: strictly decreasing (T), strictly increasing (F), | ||
# abs val decreasing (F), non-strictly increasing (T) | ||
([10, 9, 7, 3, 4, 5, -3, 2, 0, 1, 1], | ||
[True, False, False, True]), | ||
# Test with inf vals | ||
([np.inf, 1, -np.inf, np.inf, 2, -3, -np.inf, 5, -3, -np.inf, -np.inf], | ||
[True, True, False, True]), | ||
# Test with nan vals; should always be False | ||
([1, 2, np.nan, 3, 2, np.nan, np.nan, 5, -np.inf, 1, np.nan], | ||
[False, False, False, False]), | ||
]) | ||
def test_is_monotonic_decreasing(self, in_vals, out_vals): | ||
# GH 17015 | ||
source_dict = { | ||
'A': ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11'], | ||
'B': ['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd'], | ||
'C': in_vals} | ||
|
||
df = pd.DataFrame(source_dict) | ||
result = df.groupby('B').C.is_monotonic_decreasing() | ||
expected = pd.Series(index=['a', 'b', 'c', 'd'], | ||
data=out_vals, | ||
name='C') | ||
expected.index.name = 'B' | ||
tm.assert_series_equal(result, expected) | ||
|
||
def test_apply_numeric_coercion_when_datetime(self): | ||
# In the past, group-by/apply operations have been over-eager | ||
# in converting dtypes to numeric, in the presence of datetime | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can add
:func:
where needed here