PERF: For GH23814, return early in Categorical.__init__
State: closed

- [X] closes #23814
- [X] tests added / passed
- [X] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [X] whatsnew entry


Labels:
name: Performance
description: Memory or execution speed performance
name: Categorical
description: Categorical Data Type

Comments:
Hello @eoveson! Thanks for submitting the PR.

 - There are no PEP8 issues in the file [`asv_bench/benchmarks/categoricals.py`](https://github.com/eoveson/pandas/blob/f6d10b8e8a4cbb93f8c3a499a64735c12898f76d/asv_bench/benchmarks/categoricals.py) !

 - There are no PEP8 issues in the file [`pandas/core/arrays/categorical.py`](https://github.com/eoveson/pandas/blob/f6d10b8e8a4cbb93f8c3a499a64735c12898f76d/pandas/core/arrays/categorical.py) !


# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/23888?src=pr&el=h1) Report
> Merging [#23888](https://codecov.io/gh/pandas-dev/pandas/pull/23888?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/d865e5213515cef6344f16f4c77386be9ce8f223?src=pr&el=desc) will **increase** coverage by `0.01%`.
> The diff coverage is `100%`.

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

```diff
@@            Coverage Diff             @@
##           master   #23888      +/-   ##
==========================================
+ Coverage   92.29%    92.3%   +0.01%     
==========================================
  Files         161      161              
  Lines       51498    51556      +58     
==========================================
+ Hits        47530    47590      +60     
+ Misses       3968     3966       -2
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `90.7% <100%> (+0.01%)` | :arrow_up: |
| #single | `42.43% <0%> (ø)` | :arrow_up: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/23888?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/arrays/categorical.py](https://codecov.io/gh/pandas-dev/pandas/pull/23888/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvYXJyYXlzL2NhdGVnb3JpY2FsLnB5) | `95.4% <100%> (+0.04%)` | :arrow_up: |
| [pandas/core/arrays/timedeltas.py](https://codecov.io/gh/pandas-dev/pandas/pull/23888/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvYXJyYXlzL3RpbWVkZWx0YXMucHk=) | `95.95% <0%> (-0.49%)` | :arrow_down: |
| [pandas/plotting/\_misc.py](https://codecov.io/gh/pandas-dev/pandas/pull/23888/diff?src=pr&el=tree#diff-cGFuZGFzL3Bsb3R0aW5nL19taXNjLnB5) | `38.68% <0%> (-0.31%)` | :arrow_down: |
| [pandas/core/indexes/base.py](https://codecov.io/gh/pandas-dev/pandas/pull/23888/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhlcy9iYXNlLnB5) | `96.32% <0%> (-0.17%)` | :arrow_down: |
| [pandas/core/arrays/datetimes.py](https://codecov.io/gh/pandas-dev/pandas/pull/23888/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvYXJyYXlzL2RhdGV0aW1lcy5weQ==) | `98.37% <0%> (-0.14%)` | :arrow_down: |
| [pandas/tseries/offsets.py](https://codecov.io/gh/pandas-dev/pandas/pull/23888/diff?src=pr&el=tree#diff-cGFuZGFzL3RzZXJpZXMvb2Zmc2V0cy5weQ==) | `96.84% <0%> (-0.14%)` | :arrow_down: |
| [pandas/core/ops.py](https://codecov.io/gh/pandas-dev/pandas/pull/23888/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvb3BzLnB5) | `94.14% <0%> (-0.14%)` | :arrow_down: |
| [pandas/core/config.py](https://codecov.io/gh/pandas-dev/pandas/pull/23888/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvY29uZmlnLnB5) | `87.04% <0%> (-0.13%)` | :arrow_down: |
| [pandas/io/sas/sas\_xport.py](https://codecov.io/gh/pandas-dev/pandas/pull/23888/diff?src=pr&el=tree#diff-cGFuZGFzL2lvL3Nhcy9zYXNfeHBvcnQucHk=) | `90.14% <0%> (-0.1%)` | :arrow_down: |
| [pandas/io/formats/printing.py](https://codecov.io/gh/pandas-dev/pandas/pull/23888/diff?src=pr&el=tree#diff-cGFuZGFzL2lvL2Zvcm1hdHMvcHJpbnRpbmcucHk=) | `93.01% <0%> (-0.08%)` | :arrow_down: |
| ... and [49 more](https://codecov.io/gh/pandas-dev/pandas/pull/23888/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/23888?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/23888?src=pr&el=footer). Last update [d865e52...9e270e9](https://codecov.io/gh/pandas-dev/pandas/pull/23888?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

@eoveson : Thanks for the PR!  Can you run `asv` to check performance benchmarks?
@gfyoung -- yes, ran a subset of the asv suite (tried to target categorical), I can run the entire suite also. It reported no significant difference (maybe because there was no existing test for this scenario? -- which is why I added the new perf test)
(asv continuous -f 1.1 upstream/master category-perf -b ^categorical
> (maybe because there was no existing test for this scenario? -- which is why I added the new perf test)

The test output should list all performance tests that were run.  If it's not there, create a new branch off `master` with just the performance test added, and compare the two branches.
> 
> The test output should list all performance tests that were run. If it's not there, create a new branch off `master` with just the performance test added, and compare the two branches.

@gfyoung, Yes, I saw the test I added show in the output when I ran the command I mentioned.  Should I run all of the asv tests (tried running all asv tests, but it failed when it was about 1/3 done with a file access error for a temporary file), or should I target categorical tests?

Btw, this is the error I saw when trying to run all the asv tests:

```Bash
[ 32.67%] ▒▒▒ Running (index_object.Indexing.time_get_loc--).
Traceback (most recent call last):
  File "c:\users\erikov\appdata\local\continuum\anaconda3\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "c:\users\erikov\appdata\local\continuum\anaconda3\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Users\erikov\AppData\Local\Continuum\anaconda3\scripts\asv.exe\__main__.py", line 9, in <module>
  File "c:\users\erikov\appdata\local\continuum\anaconda3\lib\site-packages\asv\main.py", line 38, in main
    result = args.func(args)
  File "c:\users\erikov\appdata\local\continuum\anaconda3\lib\site-packages\asv\commands\__init__.py", line 49, in run_from_args
    return cls.run_from_conf_args(conf, args)
  File "c:\users\erikov\appdata\local\continuum\anaconda3\lib\site-packages\asv\commands\continuous.py", line 72,in run_from_conf_args
    launch_method=args.launch_method, **kwargs
  File "c:\users\erikov\appdata\local\continuum\anaconda3\lib\site-packages\asv\commands\continuous.py", line 106, in run
    _returns=run_objs, _machine_file=_machine_file)
  File "c:\users\erikov\appdata\local\continuum\anaconda3\lib\site-packages\asv\commands\run.py", line 406, in run
    launch_method=launch_method)
  File "c:\users\erikov\appdata\local\continuum\anaconda3\lib\site-packages\asv\runner.py", line 349, in run_benchmarks
    cwd=cache_dir)
  File "c:\users\erikov\appdata\local\continuum\anaconda3\lib\site-packages\asv\runner.py", line 515, in run_benchmark
    cwd=cwd)
  File "c:\users\erikov\appdata\local\continuum\anaconda3\lib\site-packages\asv\runner.py", line 647, in _run_benchmark_single_param
    os.remove(result_file.name)
PermissionError: [WinError 5] Access is denied: 'C:\\Users\\erikov\\AppData\\Local\\Temp\\tmpfq5htpg5'
```
> Yes, I saw the test I added show in the output when I ran the command I mentioned. Should I run all of the asv tests (tried running all asv tests, but it failed when it was about 1/3 done with a file access error for a temporary file), or should I target categorical tests?

Running the Categorical tests is fine.  I'm concerned though...you didn't see any noticeable improvement in performance, even with your newly added test?
Well, this change only helps in the case that they have passed in an existing instance of Categorical to Categorical.__init__, and used no optional params.  Not sure how common that would be in the tests?  I didn't see that test case in the file I added the test case to.  But I'm also not exactly sure how this asv test suite works.  How does it get a baseline to compare against (since machine specs are different)?  Am I supposed to create a baseline on my machine without my changes, and then run with my changes?  If so, I didn't do that.  I simply ran the asv command I mentioned, so I'm not sure if I'm doing things correctly..
> Well, this change only helps in the case that they have passed in an existing instance of Categorical to Categorical.init, and used no optional params.

Right, but didn't you say you saw no substantial changes in performance?

> I simply ran the asv command I mentioned, so I'm not sure if I'm doing things correctly..

Can you copy / paste the output of your ASV?
I see now that you specifically mentioned the test I added.  So I should have seen a difference for that test, so I guess I need to run with that new test, but without my real changes to __init__ to create the baseline first?
> so I guess I need to run with that new test, but without my real changes to init to create the baseline first?

Exactly.  That's why I said earlier:

> create a new branch off master with just the performance test added, and compare the two branches.
> 
> Exactly. That's why I said earlier:
> 
> > create a new branch off master with just the performance test added, and compare the two branches.

Ah, makes sense, thanks.  I'll compare the two branches and get back to you (I'll first work on the code consolidation requested by jreback since that may impact things).

@gfyoung , it turns out that asv test I added previously was not exercising the code (I should have been passing in a Series rather than Categorical to the constructor).  I added a new asv test for this (but left the other one since it could still be useful).  I re-ran asv, and did see a significant difference reported in that newly added test and one other test.  I didn't expect that other test to change, so I re-ran the same command and looking at the numbers that test doesn't change much.  (However, the reporting no longer says my newly added test shows significant difference in the second run of the command, even though I do see the same difference from the first run of the command).  So I think things are ok now, but pasting the output here so you can take a look.

Here is the first execution of the command (and then down below you will see the second one):

$ asv continuous -f 1.1 upstream/master category-perf -b categorical
▒ Creating environments
▒ Discovering benchmarks
▒▒ Uninstalling from conda-py3.6-Cython-matplotlib-numexpr-numpy-openpyxl-pytables-pytest-scipy-sqlalchemy-xlrd-xlsxwriter-xlwt
▒▒ Building 9e270e9a <category-perf> for conda-py3.6-Cython-matplotlib-numexpr-numpy-openpyxl-pytables-pytest-scipy-sqlalchemy-xlrd-xlsxwriter-xlwt
▒▒ Installing 9e270e9a <category-perf> into conda-py3.6-Cython-matplotlib-numexpr-numpy-openpyxl-pytables-pytest-scipy-sqlalchemy-xlrd-xlsxwriter-xlwt
▒ Running 66 total benchmarks (2 commits * 1 environments * 33 benchmarks)
[  0.00%] ▒ For pandas commit 3e01c384 <master^2> (round 1/2):
[  0.00%] ▒▒ Building for conda-py3.6-Cython-matplotlib-numexpr-numpy-openpyxl-pytables-pytest-scipy-sqlalchemy-xlrd-xlsxwriter-xlwt
[  0.00%] ▒▒ Benchmarking conda-py3.6-Cython-matplotlib-numexpr-numpy-openpyxl-pytables-pytest-scipy-sqlalchemy-xlrd-xlsxwriter-xlwt
[  0.76%] ▒▒▒ Setting up algorithms.py:83                                    ok
[  0.76%] ▒▒▒ Running (algorithms.Hashing.time_series_categorical--)...
[  3.03%] ▒▒▒ Running (categoricals.CategoricalSlicing.time_getitem_list_like--)..
[  4.55%] ▒▒▒ Running (categoricals.CategoricalSlicing.time_getitem_slice--)..
[  6.06%] ▒▒▒ Running (categoricals.Concat.time_union--).................
[ 18.94%] ▒▒▒ Running (categoricals.Rank.time_rank_int--).........
[ 25.00%] ▒ For pandas commit 9e270e9a <category-perf> (round 1/2):
[ 25.00%] ▒▒ Building for conda-py3.6-Cython-matplotlib-numexpr-numpy-openpyxl-pytables-pytest-scipy-sqlalchemy-xlrd-xlsxwriter-xlwt
[ 25.00%] ▒▒ Benchmarking conda-py3.6-Cython-matplotlib-numexpr-numpy-openpyxl-pytables-pytest-scipy-sqlalchemy-xlrd-xlsxwriter-xlwt
[ 25.76%] ▒▒▒ Setting up algorithms.py:83                                    ok
[ 25.76%] ▒▒▒ Running (algorithms.Hashing.time_series_categorical--)..
[ 27.27%] ▒▒▒ Running (categoricals.CategoricalSlicing.time_getitem_list--).
[ 28.03%] ▒▒▒ Running (categoricals.CategoricalSlicing.time_getitem_list_like--)..
[ 29.55%] ▒▒▒ Running (categoricals.CategoricalSlicing.time_getitem_slice--)...
[ 31.82%] ▒▒▒ Running (categoricals.Constructor.time_all_nan--)................
[ 43.94%] ▒▒▒ Running (categoricals.Rank.time_rank_int--).........
[ 50.00%] ▒ For pandas commit 9e270e9a <category-perf> (round 2/2):
[ 50.00%] ▒▒ Benchmarking conda-py3.6-Cython-matplotlib-numexpr-numpy-openpyxl-pytables-pytest-scipy-sqlalchemy-xlrd-xlsxwriter-xlwt
[ 50.76%] ▒▒▒ Setting up algorithms.py:83                                    ok
[ 50.76%] ▒▒▒ algorithms.Hashing.time_series_categorical               15.6▒8ms
[ 51.52%] ▒▒▒ ...s.CategoricalSlicing.time_getitem_bool_array                ok
[ 51.52%] ▒▒▒ ================ ==========
                   index
              ---------------- ----------
               monotonic_incr   2.60▒3ms
               monotonic_decr   3.91▒0ms
               non_monotonic    15.6▒0ms
              ================ ==========

[ 52.27%] ▒▒▒ ...oricals.CategoricalSlicing.time_getitem_list                ok monotonic_incr    679~0us

[ 52.27%] ▒▒▒ ================ ============
                   index
              ---------------- ------------
                             monotonic_decr    1.12▒1ms
               non_monotonic    0▒600000ns
              ================ ============

[ 53.03%] ▒▒▒ ...ls.CategoricalSlicing.time_getitem_list_like                ok monotonic_incr   12.5~5us
 monotonic_decr   14.1~0us
 non_monotonic    14.1~0us

[ 53.03%] ▒▒▒ ================ ==========
                   index
              ---------------- ----------
                                                        ================ ==========

[ 53.79%] ▒▒▒ ...icals.CategoricalSlicing.time_getitem_scalar                ok monotonic_incr   5.05~2us
 monotonic_decr   5.73~0us
 non_monotonic    5.04~0us

[ 53.79%] ▒▒▒ ================ ==========
                   index
              ---------------- ----------
                                                        ================ ==========

[ 54.55%] ▒▒▒ ...ricals.CategoricalSlicing.time_getitem_slice                ok monotonic_incr   3.93~4us
 monotonic_decr   4.27~4us
 non_monotonic    8.45~0us

[ 54.55%] ▒▒▒ ================ ==========
                   index
              ---------------- ----------
                                                        ================ ==========

[ 55.30%] ▒▒▒ categoricals.Concat.time_concat                          7.81▒0ms
[ 56.06%] ▒▒▒ categoricals.Concat.time_union                           15.6▒8ms
[ 56.82%] ▒▒▒ categoricals.Constructor.time_all_nan                    31.2▒0ms
[ 57.58%] ▒▒▒ categoricals.Constructor.time_datetimes                1.30▒0.7ms
[ 58.33%] ▒▒▒ ...goricals.Constructor.time_datetimes_with_nat          1.30▒0ms
[ 59.09%] ▒▒▒ ...ricals.Constructor.time_existing_categorical          3.12▒1ms
[ 59.85%] ▒▒▒ categoricals.Constructor.time_existing_series           42.2~20us
[ 60.61%] ▒▒▒ categoricals.Constructor.time_fastpath                  460~200us
[ 61.36%] ▒▒▒ ...oricals.Constructor.time_from_codes_all_int8         347~200us
[ 62.12%] ▒▒▒ categoricals.Constructor.time_regular                    46.9▒6ms
[ 62.88%] ▒▒▒ categoricals.Constructor.time_with_nan                    156▒0ms
[ 63.64%] ▒▒▒ categoricals.Contains.time_categorical_contains          78.9~0us
[ 64.39%] ▒▒▒ ...als.Contains.time_categorical_index_contains          3.46~0us
[ 65.15%] ▒▒▒ ...me_categorical_index_is_monotonic_decreasing           450▒0ns
[ 65.91%] ▒▒▒ ...me_categorical_index_is_monotonic_increasing         457▒200ns
[ 66.67%] ▒▒▒ ...e_categorical_series_is_monotonic_decreasing          51.4~0us
[ 67.42%] ▒▒▒ ...e_categorical_series_is_monotonic_increasing         62.5~20us
[ 68.18%] ▒▒▒ categoricals.Isin.time_isin_categorical                        ok
[ 68.18%] ▒▒▒ ======== ==========
               dtype
              -------- ----------
               object   15.6▒0ms
               int64    15.6▒6ms
              ======== ==========

[ 68.94%] ▒▒▒ categoricals.Rank.time_rank_int                          11.7▒4ms
[ 69.70%] ▒▒▒ categoricals.Rank.time_rank_int_cat                      7.81▒0ms
[ 70.45%] ▒▒▒ categoricals.Rank.time_rank_int_cat_ordered           0▒8000000ns
[ 71.21%] ▒▒▒ categoricals.Rank.time_rank_string                       172▒10ms
[ 71.97%] ▒▒▒ categoricals.Rank.time_rank_string_cat                   15.6▒0ms
[ 72.73%] ▒▒▒ categoricals.Rank.time_rank_string_cat_ordered           15.6▒6ms
[ 73.48%] ▒▒▒ categoricals.Repr.time_rendering                          744~0us
[ 74.24%] ▒▒▒ categoricals.SetCategories.time_set_categories           31.2▒8ms
[ 75.00%] ▒▒▒ categoricals.ValueCounts.time_value_counts                     ok
[ 75.00%] ▒▒▒ ======== ==========
               dropna
              -------- ----------
                True    15.6▒0ms
               False    15.6▒0ms
              ======== ==========

[ 75.00%] ▒ For pandas commit 3e01c384 <master^2> (round 2/2):
[ 75.00%] ▒▒ Building for conda-py3.6-Cython-matplotlib-numexpr-numpy-openpyxl-pytables-pytest-scipy-sqlalchemy-xlrd-xlsxwriter-xlwt
[ 75.00%] ▒▒ Benchmarking conda-py3.6-Cython-matplotlib-numexpr-numpy-openpyxl-pytables-pytest-scipy-sqlalchemy-xlrd-xlsxwriter-xlwt
[ 75.76%] ▒▒▒ Setting up algorithms.py:83                                    ok
[ 75.76%] ▒▒▒ algorithms.Hashing.time_series_categorical               7.81▒3ms
[ 76.52%] ▒▒▒ ...s.CategoricalSlicing.time_getitem_bool_array                ok
[ 76.52%] ▒▒▒ ================ ==========
                   index
              ---------------- ----------
               monotonic_incr   5.21▒2ms
               monotonic_decr   3.91▒1ms
               non_monotonic    7.81▒4ms
              ================ ==========

[ 77.27%] ▒▒▒ ...oricals.CategoricalSlicing.time_getitem_list                ok monotonic_incr   625~200us
 monotonic_decr   601~300us
 non_monotonic    539~200us

[ 77.27%] ▒▒▒ ================ ===========
                   index
              ---------------- -----------
                                                        ================ ===========

[ 78.03%] ▒▒▒ ...ls.CategoricalSlicing.time_getitem_list_like                ok monotonic_incr   12.5~0us
 monotonic_decr   6.42~6us
 non_monotonic    11.4~0us

[ 78.03%] ▒▒▒ ================ ==========
                   index
              ---------------- ----------
                                                        ================ ==========

[ 78.79%] ▒▒▒ ...icals.CategoricalSlicing.time_getitem_scalar                ok monotonic_decr   6.27~0us
 non_monotonic    4.73~0us

[ 78.79%] ▒▒▒ ================ ==========
                   index
              ---------------- ----------
               monotonic_incr    0▒0ns
                                          ================ ==========

[ 79.55%] ▒▒▒ ...ricals.CategoricalSlicing.time_getitem_slice                ok monotonic_incr   7.82~0us
 non_monotonic    8.52~0us

[ 79.55%] ▒▒▒ ================ ==========
                   index
              ---------------- ----------
                             monotonic_decr   0▒6000ns
                            ================ ==========

[ 80.30%] ▒▒▒ categoricals.Concat.time_concat                          7.81▒0ms
[ 81.06%] ▒▒▒ categoricals.Concat.time_union                           7.81▒0ms
[ 81.82%] ▒▒▒ categoricals.Constructor.time_all_nan                    31.2▒0ms
[ 82.58%] ▒▒▒ categoricals.Constructor.time_datetimes                  1.42▒0ms
[ 83.33%] ▒▒▒ ...goricals.Constructor.time_datetimes_with_nat          1.30▒0ms
[ 84.09%] ▒▒▒ ...ricals.Constructor.time_existing_categorical          2.60▒0ms
[ 84.85%] ▒▒▒ categoricals.Constructor.time_existing_series            3.12▒0ms
[ 85.61%] ▒▒▒ categoricals.Constructor.time_fastpath                    460~0us
[ 86.36%] ▒▒▒ ...oricals.Constructor.time_from_codes_all_int8         434~200us
[ 87.12%] ▒▒▒ categoricals.Constructor.time_regular                   46.9▒10ms
[ 87.88%] ▒▒▒ categoricals.Constructor.time_with_nan                   148▒10ms
[ 88.64%] ▒▒▒ categoricals.Contains.time_categorical_contains         0▒40000ns
[ 89.39%] ▒▒▒ ...als.Contains.time_categorical_index_contains          2.84~0us
[ 90.15%] ▒▒▒ ...me_categorical_index_is_monotonic_decreasing           312▒0ns
[ 90.91%] ▒▒▒ ...me_categorical_index_is_monotonic_increasing           312▒0ns
[ 91.67%] ▒▒▒ ...e_categorical_series_is_monotonic_decreasing          47.3~0us
[ 92.42%] ▒▒▒ ...e_categorical_series_is_monotonic_increasing          56.8~0us
[ 93.18%] ▒▒▒ categoricals.Isin.time_isin_categorical                        ok
[ 93.18%] ▒▒▒ ======== ==========
               dtype
              -------- ----------
               object   15.6▒0ms
               int64    15.6▒8ms
              ======== ==========

[ 93.94%] ▒▒▒ categoricals.Rank.time_rank_int                          7.81▒4ms
[ 94.70%] ▒▒▒ categoricals.Rank.time_rank_int_cat                      7.81▒4ms
[ 95.45%] ▒▒▒ categoricals.Rank.time_rank_int_cat_ordered              7.81▒4ms
[ 96.21%] ▒▒▒ categoricals.Rank.time_rank_string                       156▒10ms
[ 96.97%] ▒▒▒ categoricals.Rank.time_rank_string_cat                   15.6▒0ms
[ 97.73%] ▒▒▒ categoricals.Rank.time_rank_string_cat_ordered           7.81▒0ms
[ 98.48%] ▒▒▒ categoricals.Repr.time_rendering                          710~0us
[ 99.24%] ▒▒▒ categoricals.SetCategories.time_set_categories           31.2▒6ms
[100.00%] ▒▒▒ categoricals.ValueCounts.time_value_counts                     ok
[100.00%] ▒▒▒ ======== ==========
               dropna
              -------- ----------
                True    15.6▒0ms
               False    15.6▒0ms
              ======== ==========

+       0~40000ns         78.9~0us      n/a  -        3.12~0ms        42.2~20us     0.01         before          after         ratio
     [3e01c384]       [9e270e9a]
     <master^2>       <category-perf>
categoricals.Contains.time_categorical_contains
categoricals.Constructor.time_existing_series

SOME BENCHMARKS HAVE CHANGED SIGNIFICANTLY.

$ asv continuous -f 1.1 upstream/master category-perf -b categorical
▒ Creating environments
▒ Discovering benchmarks
▒▒ Uninstalling from conda-py3.6-Cython-matplotlib-numexpr-numpy-openpyxl-pytables-pytest-scipy-sqlalchemy-xlrd-xlsxwriter-xlwt
▒▒ Installing 9e270e9a <category-perf> into conda-py3.6-Cython-matplotlib-numexpr-numpy-openpyxl-pytables-pytest-scipy-sqlalchemy-xlrd-xlsxwriter-xlwt
▒ Running 66 total benchmarks (2 commits * 1 environments * 33 benchmarks)
[  0.00%] ▒ For pandas commit 3e01c384 <master^2> (round 1/2):
[  0.00%] ▒▒ Building for conda-py3.6-Cython-matplotlib-numexpr-numpy-openpyxl-pytables-pytest-scipy-sqlalchemy-xlrd-xlsxwriter-xlwt
[  0.00%] ▒▒ Benchmarking conda-py3.6-Cython-matplotlib-numexpr-numpy-openpyxl-pytables-pytest-scipy-sqlalchemy-xlrd-xlsxwriter-xlwt
[  0.76%] ▒▒▒ Setting up algorithms.py:83                                    ok
[  0.76%] ▒▒▒ Running (algorithms.Hashing.time_series_categorical--)...
[  3.03%] ▒▒▒ Running (categoricals.CategoricalSlicing.time_getitem_list_like--)..
[  4.55%] ▒▒▒ Running (categoricals.CategoricalSlicing.time_getitem_slice--).....
[  8.33%] ▒▒▒ Running (categoricals.Constructor.time_datetimes_with_nat--)..............
[ 18.94%] ▒▒▒ Running (categoricals.Rank.time_rank_int--).........
[ 25.00%] ▒ For pandas commit 9e270e9a <category-perf> (round 1/2):
[ 25.00%] ▒▒ Building for conda-py3.6-Cython-matplotlib-numexpr-numpy-openpyxl-pytables-pytest-scipy-sqlalchemy-xlrd-xlsxwriter-xlwt
[ 25.00%] ▒▒ Benchmarking conda-py3.6-Cython-matplotlib-numexpr-numpy-openpyxl-pytables-pytest-scipy-sqlalchemy-xlrd-xlsxwriter-xlwt
[ 25.76%] ▒▒▒ Setting up algorithms.py:83                                    ok
[ 25.76%] ▒▒▒ Running (algorithms.Hashing.time_series_categorical--)...
[ 28.03%] ▒▒▒ Running (categoricals.CategoricalSlicing.time_getitem_list_like--)..
[ 29.55%] ▒▒▒ Running (categoricals.CategoricalSlicing.time_getitem_slice--).....
[ 33.33%] ▒▒▒ Running (categoricals.Constructor.time_datetimes_with_nat--)..............
[ 43.94%] ▒▒▒ Running (categoricals.Rank.time_rank_int--).........
[ 50.00%] ▒ For pandas commit 9e270e9a <category-perf> (round 2/2):
[ 50.00%] ▒▒ Benchmarking conda-py3.6-Cython-matplotlib-numexpr-numpy-openpyxl-pytables-pytest-scipy-sqlalchemy-xlrd-xlsxwriter-xlwt
[ 50.76%] ▒▒▒ Setting up algorithms.py:83                                    ok
[ 50.76%] ▒▒▒ algorithms.Hashing.time_series_categorical               7.81▒0ms
[ 51.52%] ▒▒▒ ...s.CategoricalSlicing.time_getitem_bool_array                ok
[ 51.52%] ▒▒▒ ================ ==========
                   index
              ---------------- ----------
               monotonic_incr   3.91▒0ms
               monotonic_decr   3.91▒0ms
               non_monotonic    7.81▒0ms
              ================ ==========

[ 52.27%] ▒▒▒ ...oricals.CategoricalSlicing.time_getitem_list                ok monotonic_incr   601~300us
 monotonic_decr    558~0us
 non_monotonic     521~0us

[ 52.27%] ▒▒▒ ================ ===========
                   index
              ---------------- -----------
                                                        ================ ===========

[ 53.03%] ▒▒▒ ...ls.CategoricalSlicing.time_getitem_list_like                ok monotonic_incr   6.41~6us
 monotonic_decr   11.7~0us
 non_monotonic    12.8~6us

[ 53.03%] ▒▒▒ ================ ==========
                   index
              ---------------- ----------
                                                        ================ ==========

[ 53.79%] ▒▒▒ ...icals.CategoricalSlicing.time_getitem_scalar                ok monotonic_incr   4.51~0us
 monotonic_decr   4.31~2us
 non_monotonic    4.55~2us

[ 53.79%] ▒▒▒ ================ ==========
                   index
              ---------------- ----------
                                                        ================ ==========

[ 54.55%] ▒▒▒ ...ricals.CategoricalSlicing.time_getitem_slice                ok monotonic_incr   7.16~3us
 monotonic_decr   7.15~0us
 non_monotonic    7.69~0us

[ 54.55%] ▒▒▒ ================ ==========
                   index
              ---------------- ----------
                                                        ================ ==========

[ 55.30%] ▒▒▒ categoricals.Concat.time_concat                          7.81▒0ms
[ 56.06%] ▒▒▒ categoricals.Concat.time_union                           7.81▒0ms
[ 56.82%] ▒▒▒ categoricals.Constructor.time_all_nan                    31.2▒0ms
[ 57.58%] ▒▒▒ categoricals.Constructor.time_datetimes                1.20▒0.5ms
[ 58.33%] ▒▒▒ ...goricals.Constructor.time_datetimes_with_nat          1.30▒0ms
[ 59.09%] ▒▒▒ ...ricals.Constructor.time_existing_categorical          3.12▒0ms
[ 59.85%] ▒▒▒ categoricals.Constructor.time_existing_series            42.2~0us
[ 60.61%] ▒▒▒ categoricals.Constructor.time_fastpath                    355~0us
[ 61.36%] ▒▒▒ ...oricals.Constructor.time_from_codes_all_int8         446~200us
[ 62.12%] ▒▒▒ categoricals.Constructor.time_regular                    46.9▒6ms
[ 62.88%] ▒▒▒ categoricals.Constructor.time_with_nan                    141▒0ms
[ 63.64%] ▒▒▒ categoricals.Contains.time_categorical_contains          63.3~0us
[ 64.39%] ▒▒▒ ...als.Contains.time_categorical_index_contains          2.72~0us
[ 65.15%] ▒▒▒ ...me_categorical_index_is_monotonic_decreasing         383▒100ns
[ 65.91%] ▒▒▒ ...me_categorical_index_is_monotonic_increasing           323▒0ns
[ 66.67%] ▒▒▒ ...e_categorical_series_is_monotonic_decreasing         51.1~20us
[ 67.42%] ▒▒▒ ...e_categorical_series_is_monotonic_increasing          46.6~0us
[ 68.18%] ▒▒▒ categoricals.Isin.time_isin_categorical                        ok
[ 68.18%] ▒▒▒ ======== ==========
               dtype
              -------- ----------
               object   15.6▒0ms
               int64    15.6▒0ms
              ======== ==========

[ 68.94%] ▒▒▒ categoricals.Rank.time_rank_int                          7.81▒3ms
[ 69.70%] ▒▒▒ categoricals.Rank.time_rank_int_cat                      7.81▒3ms
[ 70.45%] ▒▒▒ categoricals.Rank.time_rank_int_cat_ordered              7.81▒0ms
[ 71.21%] ▒▒▒ categoricals.Rank.time_rank_string                        141▒8ms
[ 71.97%] ▒▒▒ categoricals.Rank.time_rank_string_cat                   15.6▒0ms
[ 72.73%] ▒▒▒ categoricals.Rank.time_rank_string_cat_ordered           7.81▒0ms
[ 73.48%] ▒▒▒ categoricals.Repr.time_rendering                          710~0us
[ 74.24%] ▒▒▒ categoricals.SetCategories.time_set_categories           15.6▒6ms
[ 75.00%] ▒▒▒ categoricals.ValueCounts.time_value_counts                     ok
[ 75.00%] ▒▒▒ ======== ==========
               dropna
              -------- ----------
                True    15.6▒0ms
               False    15.6▒0ms
              ======== ==========

[ 75.00%] ▒ For pandas commit 3e01c384 <master^2> (round 2/2):
[ 75.00%] ▒▒ Building for conda-py3.6-Cython-matplotlib-numexpr-numpy-openpyxl-pytables-pytest-scipy-sqlalchemy-xlrd-xlsxwriter-xlwt
[ 75.00%] ▒▒ Benchmarking conda-py3.6-Cython-matplotlib-numexpr-numpy-openpyxl-pytables-pytest-scipy-sqlalchemy-xlrd-xlsxwriter-xlwt
[ 75.76%] ▒▒▒ Setting up algorithms.py:83                                    ok
[ 75.76%] ▒▒▒ algorithms.Hashing.time_series_categorical               7.81▒0ms
[ 76.52%] ▒▒▒ ...s.CategoricalSlicing.time_getitem_bool_array                ok
[ 76.52%] ▒▒▒ ================ ==========
                   index
              ---------------- ----------
               monotonic_incr   5.21▒2ms
               monotonic_decr   3.91▒0ms
               non_monotonic    7.81▒0ms
              ================ ==========

[ 77.27%] ▒▒▒ ...oricals.CategoricalSlicing.time_getitem_list                ok monotonic_incr   601~200us
 monotonic_decr    539~0us
 non_monotonic    539~200us

[ 77.27%] ▒▒▒ ================ ===========
                   index
              ---------------- -----------
                                                        ================ ===========

[ 78.03%] ▒▒▒ ...ls.CategoricalSlicing.time_getitem_list_like                ok monotonic_incr   11.4~0us
 monotonic_decr   12.5~5us
 non_monotonic    12.7~0us

[ 78.03%] ▒▒▒ ================ ==========
                   index
              ---------------- ----------
                                                        ================ ==========

[ 78.79%] ▒▒▒ ...icals.CategoricalSlicing.time_getitem_scalar                ok monotonic_incr   4.37~0us
 monotonic_decr   4.70~2us
 non_monotonic    4.70~0us

[ 78.79%] ▒▒▒ ================ ==========
                   index
              ---------------- ----------
                                                        ================ ==========

[ 79.55%] ▒▒▒ ...ricals.CategoricalSlicing.time_getitem_slice                ok monotonic_incr   7.23~0us
 monotonic_decr   7.10~0us
 non_monotonic    7.84~0us

[ 79.55%] ▒▒▒ ================ ==========
                   index
              ---------------- ----------
                                                        ================ ==========

[ 80.30%] ▒▒▒ categoricals.Concat.time_concat                          7.81▒0ms
[ 81.06%] ▒▒▒ categoricals.Concat.time_union                           7.81▒0ms
[ 81.82%] ▒▒▒ categoricals.Constructor.time_all_nan                    31.2▒6ms
[ 82.58%] ▒▒▒ categoricals.Constructor.time_datetimes                1.30▒0.5ms
[ 83.33%] ▒▒▒ ...goricals.Constructor.time_datetimes_with_nat          1.30▒0ms
[ 84.09%] ▒▒▒ ...ricals.Constructor.time_existing_categorical          3.12▒0ms
[ 84.85%] ▒▒▒ categoricals.Constructor.time_existing_series            3.12▒2ms
[ 85.61%] ▒▒▒ categoricals.Constructor.time_fastpath                  411~200us
[ 86.36%] ▒▒▒ ...oricals.Constructor.time_from_codes_all_int8           347~0us
[ 87.12%] ▒▒▒ categoricals.Constructor.time_regular                    46.9▒8ms
[ 87.88%] ▒▒▒ categoricals.Constructor.time_with_nan                    141▒0ms
[ 88.64%] ▒▒▒ categoricals.Contains.time_categorical_contains          71.7~0us
[ 89.39%] ▒▒▒ ...als.Contains.time_categorical_index_contains          2.78~1us
[ 90.15%] ▒▒▒ ...me_categorical_index_is_monotonic_decreasing         316▒100ns
[ 90.91%] ▒▒▒ ...me_categorical_index_is_monotonic_increasing         343▒100ns
[ 91.67%] ▒▒▒ ...e_categorical_series_is_monotonic_decreasing          52.1~0us
[ 92.42%] ▒▒▒ ...e_categorical_series_is_monotonic_increasing         46.8~20us
[ 93.18%] ▒▒▒ categoricals.Isin.time_isin_categorical                        ok
[ 93.18%] ▒▒▒ ======== ==========
               dtype
              -------- ----------
               object   15.6▒0ms
               int64    15.6▒6ms
              ======== ==========

[ 93.94%] ▒▒▒ categoricals.Rank.time_rank_int                          7.81▒3ms
[ 94.70%] ▒▒▒ categoricals.Rank.time_rank_int_cat                      7.81▒4ms
[ 95.45%] ▒▒▒ categoricals.Rank.time_rank_int_cat_ordered              7.81▒0ms
[ 96.21%] ▒▒▒ categoricals.Rank.time_rank_string                        141▒8ms
[ 96.97%] ▒▒▒ categoricals.Rank.time_rank_string_cat                   15.6▒0ms
[ 97.73%] ▒▒▒ categoricals.Rank.time_rank_string_cat_ordered           7.81▒3ms
[ 98.48%] ▒▒▒ categoricals.Repr.time_rendering                        679~300us
[ 99.24%] ▒▒▒ categoricals.SetCategories.time_set_categories           31.2▒0ms
[100.00%] ▒▒▒ categoricals.ValueCounts.time_value_counts                     ok
[100.00%] ▒▒▒ ======== ==========
               dropna
              -------- ----------
                True    15.6▒0ms
               False    15.6▒0ms
              ======== ==========


BENCHMARKS NOT SIGNIFICANTLY CHANGED.


@eoveson can you show a before / after using timeit in ipython
> @eoveson can you show a before / after using timeit in ipython

For sure.  Before my change:
```Python
In [2]: s = pd.Series(list('abcd') * 1000000).astype('category')

In [3]: %timeit s == 'a'
25.7 ms ± 409 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [4]: %timeit s.cat.codes == s.cat.categories.get_loc('a')
3.29 ms ± 70.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
```

After change:
```Python
In [6]: s = pd.Series(list('abcd') * 1000000).astype('category')

In [7]: %timeit s == 'a'
5.24 ms ± 97.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [8]: %timeit s.cat.codes == s.cat.categories.get_loc('a')
3.28 ms ± 70 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
```
thanks @eoveson