-
-
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 17 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 |
---|---|---|
|
@@ -1826,6 +1826,63 @@ 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 |
||
.. versionadded:: 0.22.0 | ||
|
||
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 | ||
|
||
See Also | ||
-------- | ||
pandas.Series.is_monotonic_increasing | ||
pandas.Index.is_monotonic_increasing | ||
""" | ||
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)``. | ||
|
||
.. versionadded:: 0.22.0 | ||
|
||
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 |
---|---|---|
|
@@ -2475,7 +2475,7 @@ def test_group_shift_with_null_key(self): | |
# Generate a moderately large dataframe with occasional missing | ||
# values in column `B`, and then group by [`A`, `B`]. This should | ||
# force `-1` in `labels` array of `g.grouper.group_info` exactly | ||
# at those places, where the group-by key is partilly missing. | ||
# at those places, where the group-by key is partially missing. | ||
df = DataFrame([(i % 12, i % 3 if i % 3 else np.nan, i) | ||
for i in range(n_rows)], dtype=float, | ||
columns=["A", "B", "Z"], index=None) | ||
|
@@ -2600,6 +2600,65 @@ 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', [ | ||
|
||
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. we don't really need all this, as 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. figured as much but wasn't sure whether to test here and risk duplication or not test here and have "untested" code. |
||
# 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() | ||
index = Index(list('abcd'), name='B') | ||
expected = pd.Series(index=index, data=out_vals, name='C') | ||
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() | ||
index = Index(list('abcd'), name='B') | ||
expected = pd.Series(index=index, data=out_vals, name='C') | ||
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.
these need to be
:func:`SeriesGroupBy.is_monotonic_increasing`
(and so on)