ENH: gb.is_monotonic_increasing #17015
State: closed

- [x] closes [#17015](https://github.com/pandas-dev/pandas/issues/17015#issuecomment-316238679)
- [x] tests added / passed: 
updated test_tab_completion to expect additional functions `is_monotonic_increasing` and `is_monotonic_decreasing` 
added (semi-redundant) tests of gb.is_monotonically_increasing() - strictly increasing/decreasing, non-strictly, w/ inf vals, w/ nan vals
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [x] whatsnew entry
added at the end of the `Other Enhancements` section

This is my first PR to Pandas, so I don't doubt that I'll need to edit things.

Labels:
name: Enhancement
name: Groupby

Comments:
tests go in ``pandas/tests/groupby/test_groupby.py``
Added basic tests, for strictly monotonically increasing/decreasing, non-strictly, groups with inf, groups with nan, and to check method result == .apply(lambda x: x.is_monotonic_increasing) (though the method is just syntactic sugar in this implementation). (Not sure how much detail should be in the tests of gb.is_monotonic_increasing vs. Series.is_monotonic_increasing.)
# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/17453?src=pr&el=h1) Report
> Merging [#17453](https://codecov.io/gh/pandas-dev/pandas/pull/17453?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/324379ce75269aa6bced90ecf3edb692539a2742?src=pr&el=desc) will **decrease** coverage by `0.03%`.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/pandas-dev/pandas/pull/17453/graphs/tree.svg?width=650&height=150&src=pr&token=eZ4WkYLtcO)](https://codecov.io/gh/pandas-dev/pandas/pull/17453?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master   #17453      +/-   ##
==========================================
- Coverage   91.61%   91.58%   -0.04%     
==========================================
  Files         150      150              
  Lines       48807    48867      +60     
==========================================
+ Hits        44716    44755      +39     
- Misses       4091     4112      +21
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `89.96% <ø> (-0.04%)` | :arrow_down: |
| #single | `41.75% <ø> (+0.02%)` | :arrow_up: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/17453?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/groupby.py](https://codecov.io/gh/pandas-dev/pandas/pull/17453/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvZ3JvdXBieS5weQ==) | `92.2% <ø> (ø)` | :arrow_up: |
| [pandas/io/s3.py](https://codecov.io/gh/pandas-dev/pandas/pull/17453/diff?src=pr&el=tree#diff-cGFuZGFzL2lvL3MzLnB5) | `72.72% <0%> (-13.64%)` | :arrow_down: |
| [pandas/plotting/\_converter.py](https://codecov.io/gh/pandas-dev/pandas/pull/17453/diff?src=pr&el=tree#diff-cGFuZGFzL3Bsb3R0aW5nL19jb252ZXJ0ZXIucHk=) | `65.22% <0%> (-1.74%)` | :arrow_down: |
| [pandas/io/packers.py](https://codecov.io/gh/pandas-dev/pandas/pull/17453/diff?src=pr&el=tree#diff-cGFuZGFzL2lvL3BhY2tlcnMucHk=) | `87.31% <0%> (-1.34%)` | :arrow_down: |
| [pandas/core/arrays/base.py](https://codecov.io/gh/pandas-dev/pandas/pull/17453/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvYXJyYXlzL2Jhc2UucHk=) | `60% <0%> (-0.61%)` | :arrow_down: |
| [pandas/io/json/json.py](https://codecov.io/gh/pandas-dev/pandas/pull/17453/diff?src=pr&el=tree#diff-cGFuZGFzL2lvL2pzb24vanNvbi5weQ==) | `92.23% <0%> (-0.37%)` | :arrow_down: |
| [pandas/io/common.py](https://codecov.io/gh/pandas-dev/pandas/pull/17453/diff?src=pr&el=tree#diff-cGFuZGFzL2lvL2NvbW1vbi5weQ==) | `68.77% <0%> (-0.3%)` | :arrow_down: |
| [pandas/io/parquet.py](https://codecov.io/gh/pandas-dev/pandas/pull/17453/diff?src=pr&el=tree#diff-cGFuZGFzL2lvL3BhcnF1ZXQucHk=) | `71.79% <0%> (-0.28%)` | :arrow_down: |
| [pandas/io/parsers.py](https://codecov.io/gh/pandas-dev/pandas/pull/17453/diff?src=pr&el=tree#diff-cGFuZGFzL2lvL3BhcnNlcnMucHk=) | `95.32% <0%> (-0.25%)` | :arrow_down: |
| [pandas/core/series.py](https://codecov.io/gh/pandas-dev/pandas/pull/17453/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvc2VyaWVzLnB5) | `94.56% <0%> (-0.05%)` | :arrow_down: |
| ... and [14 more](https://codecov.io/gh/pandas-dev/pandas/pull/17453/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/17453?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/17453?src=pr&el=footer). Last update [324379c...787c436](https://codecov.io/gh/pandas-dev/pandas/pull/17453?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

@jreback I went ahead and parametrized the tests. Wanted to have the method itself as a param as I could then just use one test function to test both is_monotonic_increasing and decreasing, but I couldn't figure out a way to pass a method as a param. 

Also added these to SeriesGroupBy in api.rst. Not sure what else I should add. If I run  the `api_rst_coverage.py` script I found mentioned in the docs, I get a gigantic laundry list of `Class members (other than those beginning with '_') missing from api.rst`. Let me know if you have a suggestion for that.
I rebased to try to integrate changes to pandas-dev/pandas, but it seems the commit history is profoundly screwed up now. (It does look to me like the upstream changes are now reflected, though.) Could someone suggest how to fix this?
@AdamShamlian you need to build the extensions

``python setup.py build_ext --inplace``

you should do this whenever you pull (it has no effect if they are already built).

extensions are undergoing a lot of renovation lately.
@No-Stream I rebased you. please have a look thru and make any additional corrections 
@jreback I've rebased to upstream/master, done the two changes requested, and tests are passing. 

By the way, for the test in question `pd.Series(index=list('abcd', data=out_vals, name='B')` actually doesn't work because the `tm.assert_series_equal()` test fails on the index names being different, not the series names being different. So I just define the index with its name and then use it in the series construction in order to avoid defining `series.index.name` manually. 
@jreback any chance you can take a look and see if you want any further edits? Commit was clean when submitted, now would just need to redo edits to a few files to edits to match up with upstream.
you will need to merge master and push again
@jreback re-merged and pushed changes
can you rebase and update according to comments
@jorisvandenbossche was able to implement it as you requested. This change does make the syntax a bit uglier. i.e. it's `series_groupby.is_monotonic_increasing` rather than `series_groupby.is_monotonic_increasing()`. That makes it inconsistent with other groupby methods, but it's working fine. 
@gfyoung can you rebase this
@jreback : Resolved the merge conflict, though I don't know if the CI will be all green.
> @jorisvandenbossche was able to implement it as you requested. This change does make the syntax a bit uglier. i.e. it's series_groupby.is_monotonic_increasing rather than series_groupby.is_monotonic_increasing(). That makes it inconsistent with other groupby methods, but it's working fine.

That's actually a good point. We don't have many precedents for attributes on groupby objects (or for methods that are the equivalent of attributes). 
From a a quick look, we have `.dtype` (an attribute both on Series and SeriesGroupBy, but not sure of the usefulness of this one), and `.size()` (an attribute on Series, but method on SeriesGroupBy)

look ok to me. @gfyoung can you rebase again.
@jreback @jorisvandenbossche : CI is passing, and the PR is mergeable.  PTAL.
Thanks @No-Stream and @gfyoung