|
2 | 2 |
|
3 | 3 | import numpy as np
|
4 | 4 | from warnings import warn
|
| 5 | +import textwrap |
5 | 6 | import types
|
6 | 7 |
|
7 | 8 | from pandas import compat
|
|
29 | 30 | is_scalar,
|
30 | 31 | is_dict_like)
|
31 | 32 |
|
32 |
| -from pandas.core.algorithms import factorize, take_1d, unique1d |
| 33 | +from pandas.core.algorithms import factorize, take_1d, unique1d, take |
33 | 34 | from pandas.core.accessor import PandasDelegate
|
34 | 35 | from pandas.core.base import (PandasObject,
|
35 | 36 | NoNewAttributesMixin, _shared_docs)
|
|
48 | 49 | from .base import ExtensionArray
|
49 | 50 |
|
50 | 51 |
|
| 52 | +_take_msg = textwrap.dedent("""\ |
| 53 | + Interpreting negative values in 'indexer' as missing values. |
| 54 | + In the future, this will change to meaning positional indicies |
| 55 | + from the right. |
| 56 | +
|
| 57 | + Use 'allow_fill=True' to retain the previous behavior and silence this |
| 58 | + warning. |
| 59 | +
|
| 60 | + Use 'allow_fill=False' to accept the new behavior.""") |
| 61 | + |
| 62 | + |
51 | 63 | def _cat_compare_op(op):
|
52 | 64 | def f(self, other):
|
53 | 65 | # On python2, you can usually compare any type to any type, and
|
@@ -1732,17 +1744,49 @@ def fillna(self, value=None, method=None, limit=None):
|
1732 | 1744 | return self._constructor(values, categories=self.categories,
|
1733 | 1745 | ordered=self.ordered, fastpath=True)
|
1734 | 1746 |
|
1735 |
| - def take_nd(self, indexer, allow_fill=True, fill_value=None): |
1736 |
| - """ Take the codes by the indexer, fill with the fill_value. |
1737 |
| -
|
1738 |
| - For internal compatibility with numpy arrays. |
| 1747 | + def take_nd(self, indexer, allow_fill=None, fill_value=None): |
1739 | 1748 | """
|
| 1749 | + Take elements from the Categorical. |
1740 | 1750 |
|
1741 |
| - # filling must always be None/nan here |
1742 |
| - # but is passed thru internally |
1743 |
| - assert isna(fill_value) |
| 1751 | + Parameters |
| 1752 | + ---------- |
| 1753 | + indexer : sequence of integers |
| 1754 | + allow_fill : bool, default None. |
| 1755 | + How to handle negative values in `indexer`. |
1744 | 1756 |
|
1745 |
| - codes = take_1d(self._codes, indexer, allow_fill=True, fill_value=-1) |
| 1757 | + * False: negative values in `indices` indicate positional indices |
| 1758 | + from the right. This is similar to |
| 1759 | + :func:`numpy.take`. |
| 1760 | +
|
| 1761 | + * True: negative values in `indices` indicate missing values |
| 1762 | + (the default). These values are set to `fill_value`. Any other |
| 1763 | + other negative values raise a ``ValueError``. |
| 1764 | +
|
| 1765 | + .. versionchanged:: 0.23.0 |
| 1766 | +
|
| 1767 | + Deprecated the default value of `allow_fill`. The deprecated |
| 1768 | + default is ``True``. In the future, this will change to |
| 1769 | + ``False``. |
| 1770 | +
|
| 1771 | + Returns |
| 1772 | + ------- |
| 1773 | + Categorical |
| 1774 | + This Categorical will have the same categories and ordered as |
| 1775 | + `self`. |
| 1776 | + """ |
| 1777 | + indexer = np.asarray(indexer, dtype=np.intp) |
| 1778 | + if allow_fill is None: |
| 1779 | + if (indexer < 0).any(): |
| 1780 | + warn(_take_msg, FutureWarning, stacklevel=2) |
| 1781 | + allow_fill = True |
| 1782 | + |
| 1783 | + if isna(fill_value): |
| 1784 | + # For categorical, any NA value is considered a user-facing |
| 1785 | + # NA value. Our storage NA value is -1. |
| 1786 | + fill_value = -1 |
| 1787 | + |
| 1788 | + codes = take(self._codes, indexer, allow_fill=allow_fill, |
| 1789 | + fill_value=fill_value) |
1746 | 1790 | result = self._constructor(codes, categories=self.categories,
|
1747 | 1791 | ordered=self.ordered, fastpath=True)
|
1748 | 1792 | return result
|
|
0 commit comments