<p dir="auto">Currently, <code class="notranslate">Categorical.unique</code> and <code class="notranslate">CategoricalIndex.unique</code> drop unused categories:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&gt;&gt;&gt; categories = ['very good', 'good', 'neutral', 'bad', 'very bad']
&gt;&gt;&gt; cat = pd.Categorical(['good','good', 'bad', 'bad'], categories=categories, ordered=True)
&gt;&gt;&gt; cat
[good, good, bad, bad]
Categories (5, object): [very good &lt; good &lt; neutral &lt; bad &lt; very bad]
&gt;&gt;&gt; cat.unique()
[good, bad]
Categories (2, object): [good &lt; bad]  # unused categories dropped"><pre class="notranslate"><span class="pl-c1">&gt;&gt;</span><span class="pl-c1">&gt;</span> <span class="pl-s1">categories</span> <span class="pl-c1">=</span> [<span class="pl-s">'very good'</span>, <span class="pl-s">'good'</span>, <span class="pl-s">'neutral'</span>, <span class="pl-s">'bad'</span>, <span class="pl-s">'very bad'</span>]
<span class="pl-c1">&gt;&gt;</span><span class="pl-c1">&gt;</span> <span class="pl-s1">cat</span> <span class="pl-c1">=</span> <span class="pl-s1">pd</span>.<span class="pl-v">Categorical</span>([<span class="pl-s">'good'</span>,<span class="pl-s">'good'</span>, <span class="pl-s">'bad'</span>, <span class="pl-s">'bad'</span>], <span class="pl-s1">categories</span><span class="pl-c1">=</span><span class="pl-s1">categories</span>, <span class="pl-s1">ordered</span><span class="pl-c1">=</span><span class="pl-c1">True</span>)
<span class="pl-c1">&gt;&gt;</span><span class="pl-c1">&gt;</span> <span class="pl-s1">cat</span>
[<span class="pl-s1">good</span>, <span class="pl-s1">good</span>, <span class="pl-s1">bad</span>, <span class="pl-s1">bad</span>]
<span class="pl-v">Categories</span> (<span class="pl-c1">5</span>, <span class="pl-s1">object</span>): [<span class="pl-s1">very</span> <span class="pl-s1">good</span> <span class="pl-c1">&lt;</span> <span class="pl-s1">good</span> <span class="pl-c1">&lt;</span> <span class="pl-s1">neutral</span> <span class="pl-c1">&lt;</span> <span class="pl-s1">bad</span> <span class="pl-c1">&lt;</span> <span class="pl-s1">very</span> <span class="pl-s1">bad</span>]
<span class="pl-c1">&gt;&gt;</span><span class="pl-c1">&gt;</span> <span class="pl-s1">cat</span>.<span class="pl-en">unique</span>()
[<span class="pl-s1">good</span>, <span class="pl-s1">bad</span>]
<span class="pl-v">Categories</span> (<span class="pl-c1">2</span>, <span class="pl-s1">object</span>): [<span class="pl-s1">good</span> <span class="pl-c1">&lt;</span> <span class="pl-s1">bad</span>]  <span class="pl-c"># unused categories dropped</span></pre></div>
<p dir="auto">So, <code class="notranslate">.unique()</code> both uniquefies and drops unused categories (does two things in one operation)</p>
<p dir="auto">Often, even if you want to uniquefy values, you still want to control whether to drop unused categories or not. So <code class="notranslate">Categorical/CategoricalIndex.unique</code> should IMO keep all categories, and categories should be dropped in a seperate action. So, this would be a better API:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&gt;&gt;&gt; cat.unique()
[good, bad]
Categories (5, object): [very good &lt; good &lt; neutral &lt; bad &lt; very bad]    # unused not dropped"><pre class="notranslate"><span class="pl-c1">&gt;&gt;</span><span class="pl-c1">&gt;</span> <span class="pl-s1">cat</span>.<span class="pl-en">unique</span>()
[<span class="pl-s1">good</span>, <span class="pl-s1">bad</span>]
<span class="pl-v">Categories</span> (<span class="pl-c1">5</span>, <span class="pl-s1">object</span>): [<span class="pl-s1">very</span> <span class="pl-s1">good</span> <span class="pl-c1">&lt;</span> <span class="pl-s1">good</span> <span class="pl-c1">&lt;</span> <span class="pl-s1">neutral</span> <span class="pl-c1">&lt;</span> <span class="pl-s1">bad</span> <span class="pl-c1">&lt;</span> <span class="pl-s1">very</span> <span class="pl-s1">bad</span>]    <span class="pl-c"># unused not dropped</span></pre></div>
<p dir="auto">If you want to drop unused categories, you should do it explicitly like so: <code class="notranslate">cat.unique().remove_unused_categories()</code>.</p>
<p dir="auto">The proposed API is also faster, as dropping unused categories requires recoding the categories/codes, which is potentially expensive.</p>
<h4 dir="auto">Code Sample, a copy-pastable example if possible</h4>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="In [2]: pd.Categorical([1,3,2,4], categories=[4,2,3,1,5]).unique()
Out[2]: 
[1, 3, 2, 4]
Categories (4, int64): [1, 3, 2, 4]
"><pre class="notranslate"><span class="pl-v">In</span> [<span class="pl-c1">2</span>]: <span class="pl-s1">pd</span>.<span class="pl-v">Categorical</span>([<span class="pl-c1">1</span>,<span class="pl-c1">3</span>,<span class="pl-c1">2</span>,<span class="pl-c1">4</span>], <span class="pl-s1">categories</span><span class="pl-c1">=</span>[<span class="pl-c1">4</span>,<span class="pl-c1">2</span>,<span class="pl-c1">3</span>,<span class="pl-c1">1</span>,<span class="pl-c1">5</span>]).<span class="pl-en">unique</span>()
<span class="pl-v">Out</span>[<span class="pl-c1">2</span>]: 
[<span class="pl-c1">1</span>, <span class="pl-c1">3</span>, <span class="pl-c1">2</span>, <span class="pl-c1">4</span>]
<span class="pl-v">Categories</span> (<span class="pl-c1">4</span>, <span class="pl-s1">int64</span>): [<span class="pl-c1">1</span>, <span class="pl-c1">3</span>, <span class="pl-c1">2</span>, <span class="pl-c1">4</span>]</pre></div>
<p dir="auto">same happens with <code class="notranslate">CategoricalIndex</code> and <code class="notranslate">Series</code> of <code class="notranslate">dtype=category</code> (as long as <code class="notranslate">ordered=False</code>).</p>
<h4 dir="auto">Problem description</h4>
<p dir="auto">The general pandas approach to categoricals seems to change the <code class="notranslate">.categories</code> field as seldom as possible. So I see no reason why <code class="notranslate">unique()</code>, which <em>by definition</em> does not affect the set of distinct values, should change the categories (reordering them based on appearance, and dropping unused ones).</p>
<h4 dir="auto">Expected Output</h4>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="In [2]: pd.Categorical([1,3,2,4], categories=[4,2,3,1,5]).unique()
Out[2]: 
[1, 3, 2, 4]
Categories (4, int64): [4, 2, 3, 1, 5]
"><pre class="notranslate"><span class="pl-v">In</span> [<span class="pl-c1">2</span>]: <span class="pl-s1">pd</span>.<span class="pl-v">Categorical</span>([<span class="pl-c1">1</span>,<span class="pl-c1">3</span>,<span class="pl-c1">2</span>,<span class="pl-c1">4</span>], <span class="pl-s1">categories</span><span class="pl-c1">=</span>[<span class="pl-c1">4</span>,<span class="pl-c1">2</span>,<span class="pl-c1">3</span>,<span class="pl-c1">1</span>,<span class="pl-c1">5</span>]).<span class="pl-en">unique</span>()
<span class="pl-v">Out</span>[<span class="pl-c1">2</span>]: 
[<span class="pl-c1">1</span>, <span class="pl-c1">3</span>, <span class="pl-c1">2</span>, <span class="pl-c1">4</span>]
<span class="pl-v">Categories</span> (<span class="pl-c1">4</span>, <span class="pl-s1">int64</span>): [<span class="pl-c1">4</span>, <span class="pl-c1">2</span>, <span class="pl-c1">3</span>, <span class="pl-c1">1</span>, <span class="pl-c1">5</span>]</pre></div>
<h4 dir="auto">Output of <code class="notranslate">pd.show_versions()</code></h4>
<details>
<p dir="auto">In [3]: pd.show_versions()</p>
<h2 dir="auto">INSTALLED VERSIONS</h2>
<p dir="auto">commit: <a class="commit-link" data-hovercard-type="commit" data-hovercard-url="https://github.com/pandas-dev/pandas/commit/63e8527d32aaf6afe1cd4b2a7b3bfadb088c9a72/hovercard" href="https://github.com/pandas-dev/pandas/commit/63e8527d32aaf6afe1cd4b2a7b3bfadb088c9a72"><tt>63e8527</tt></a><br>
python: 3.5.3.final.0<br>
python-bits: 64<br>
OS: Linux<br>
OS-release: 4.9.0-3-amd64<br>
machine: x86_64<br>
processor:<br>
byteorder: little<br>
LC_ALL: None<br>
LANG: it_IT.UTF-8<br>
LOCALE: it_IT.UTF-8</p>
<p dir="auto">pandas: 0.22.0.dev0+131.g63e8527d3<br>
pytest: 3.2.3<br>
pip: 9.0.1<br>
setuptools: 36.7.0<br>
Cython: 0.25.2<br>
numpy: 1.12.1<br>
scipy: 0.19.0<br>
pyarrow: None<br>
xarray: None<br>
IPython: 6.2.1<br>
sphinx: 1.5.6<br>
patsy: 0.4.1<br>
dateutil: 2.6.1<br>
pytz: 2017.2<br>
blosc: None<br>
bottleneck: 1.2.0dev<br>
tables: 3.3.0<br>
numexpr: 2.6.1<br>
feather: 0.3.1<br>
matplotlib: 2.0.0<br>
openpyxl: None<br>
xlrd: 1.0.0<br>
xlwt: 1.1.2<br>
xlsxwriter: 0.9.6<br>
lxml: None<br>
bs4: 4.5.3<br>
html5lib: 0.999999999<br>
sqlalchemy: 1.0.15<br>
pymysql: None<br>
psycopg2: None<br>
jinja2: 2.10<br>
s3fs: None<br>
fastparquet: None<br>
pandas_gbq: None<br>
pandas_datareader: 0.2.1</p>
</details>