Skip to content

Commit 9d86247

Browse files
committed
API: rename Categorical.levels to .categories
The name 'levels' was already used by a much different concept in MultiIndex and this was too confusing, so change the name to 'categories'. Add deprecation warning if the old name is used (in constructor or the public 'levels' attribute). The old name 'levels' is not anymore exposed unter Series.cat as it was never part of a stable release. See the discussion in pandas-dev#8074 This rename was done by search&replace in categorical.py and the corresponding tests_categorical.py, implementing the deprecation accessor (with a temporary 'raise Exception') and then run the the unittests and change code until all tests pass.
1 parent b74e0a3 commit 9d86247

17 files changed

+618
-590
lines changed

doc/source/api.rst

+3-3
Original file line numberDiff line numberDiff line change
@@ -562,10 +562,10 @@ following usable methods and properties (all available as ``Series.cat.<method_o
562562
.. autosummary::
563563
:toctree: generated/
564564

565-
Categorical.levels
565+
Categorical.categories
566566
Categorical.ordered
567-
Categorical.reorder_levels
568-
Categorical.remove_unused_levels
567+
Categorical.reorder_categories
568+
Categorical.remove_unused_categories
569569

570570
The following methods are considered API when using ``Categorical`` directly:
571571

pandas/core/algorithms.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ def value_counts(values, sort=True, ascending=False, normalize=False,
213213
raise TypeError("bins argument only works with numeric data.")
214214
values = cat.codes
215215
elif is_category:
216-
bins = values.levels
216+
bins = values.categories
217217
cat = values
218218
values = cat.codes
219219

@@ -248,11 +248,11 @@ def value_counts(values, sort=True, ascending=False, normalize=False,
248248
result = Series(counts, index=com._values_from_object(keys))
249249
if bins is not None:
250250
# TODO: This next line should be more efficient
251-
result = result.reindex(np.arange(len(cat.levels)), fill_value=0)
251+
result = result.reindex(np.arange(len(cat.categories)), fill_value=0)
252252
if not is_category:
253253
result.index = bins[:-1]
254254
else:
255-
result.index = cat.levels
255+
result.index = cat.categories
256256

257257
if sort:
258258
result.sort()

pandas/core/categorical.py

+241-224
Large diffs are not rendered by default.

pandas/core/config_init.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,10 @@
5959
correct auto-detection.
6060
"""
6161

62-
pc_max_levels_doc = """
62+
pc_max_categories_doc = """
6363
: int
64-
This sets the maximum number of levels pandas should output when printing
65-
out a `Categorical`.
64+
This sets the maximum number of categories pandas should output when printing
65+
out a `Categorical` or a Series of dtype "category".
6666
"""
6767

6868
pc_max_info_cols_doc = """
@@ -237,7 +237,7 @@ def mpl_style_cb(key):
237237
validator=is_instance_factory((int, type(None))))
238238
cf.register_option('max_rows', 60, pc_max_rows_doc,
239239
validator=is_instance_factory([type(None), int]))
240-
cf.register_option('max_levels', 8, pc_max_levels_doc, validator=is_int)
240+
cf.register_option('max_categories', 8, pc_max_categories_doc, validator=is_int)
241241
cf.register_option('max_colwidth', 50, max_colwidth_doc, validator=is_int)
242242
cf.register_option('max_columns', 20, pc_max_cols_doc,
243243
validator=is_instance_factory([type(None), int]))

pandas/core/format.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def _get_footer(self):
9090
footer += ', '
9191
footer += "Length: %d" % len(self.categorical)
9292

93-
level_info = self.categorical._repr_level_info()
93+
level_info = self.categorical._repr_categories_info()
9494

9595
# Levels are added in a newline
9696
if footer:
@@ -176,7 +176,7 @@ def _get_footer(self):
176176
# level infos are added to the end and in a new line, like it is done for Categoricals
177177
# Only added when we request a name
178178
if self.name and com.is_categorical_dtype(self.series.dtype):
179-
level_info = self.series.values._repr_level_info()
179+
level_info = self.series.values._repr_categories_info()
180180
if footer:
181181
footer += "\n"
182182
footer += level_info

pandas/core/groupby.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1924,7 +1924,7 @@ def __init__(self, index, grouper=None, obj=None, name=None, level=None,
19241924
self.grouper = np.asarray(factor)
19251925

19261926
self._labels = factor.codes
1927-
self._group_index = factor.levels
1927+
self._group_index = factor.categories
19281928
if self.name is None:
19291929
self.name = factor.name
19301930

@@ -3545,7 +3545,7 @@ def _lexsort_indexer(keys, orders=None, na_position='last'):
35453545
if na_position not in ['last','first']:
35463546
raise ValueError('invalid na_position: {!r}'.format(na_position))
35473547

3548-
n = len(c.levels)
3548+
n = len(c.categories)
35493549
codes = c.codes.copy()
35503550

35513551
mask = (c.codes == -1)

pandas/core/index.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -3206,7 +3206,7 @@ def from_arrays(cls, arrays, sortorder=None, names=None):
32063206
return Index(arrays[0], name=name)
32073207

32083208
cats = [Categorical.from_array(arr) for arr in arrays]
3209-
levels = [c.levels for c in cats]
3209+
levels = [c.categories for c in cats]
32103210
labels = [c.codes for c in cats]
32113211
if names is None:
32123212
names = [c.name for c in cats]
@@ -3301,7 +3301,7 @@ def from_product(cls, iterables, sortorder=None, names=None):
33013301
categoricals = [Categorical.from_array(it) for it in iterables]
33023302
labels = cartesian_product([c.codes for c in categoricals])
33033303

3304-
return MultiIndex(levels=[c.levels for c in categoricals],
3304+
return MultiIndex(levels=[c.categories for c in categoricals],
33053305
labels=labels, sortorder=sortorder, names=names)
33063306

33073307
@property

pandas/core/internals.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1698,12 +1698,12 @@ def _concat_blocks(self, blocks, values):
16981698
return the block concatenation
16991699
"""
17001700

1701-
levels = self.values.levels
1701+
categories = self.values.categories
17021702
for b in blocks:
1703-
if not levels.equals(b.values.levels):
1703+
if not categories.equals(b.values.categories):
17041704
raise ValueError("incompatible levels in categorical block merge")
17051705

1706-
return self._holder(values[0], levels=levels)
1706+
return self._holder(values[0], categories=categories)
17071707

17081708
def to_native_types(self, slicer=None, na_rep='', **kwargs):
17091709
""" convert to our native types format, slicing if desired """

pandas/core/panel.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def panel_index(time, panels, names=['time', 'panel']):
9999
panel_factor = Categorical.from_array(panels)
100100

101101
labels = [time_factor.codes, panel_factor.codes]
102-
levels = [time_factor.levels, panel_factor.levels]
102+
levels = [time_factor.categories, panel_factor.categories]
103103
return MultiIndex(levels, labels, sortorder=None, names=names,
104104
verify_integrity=False)
105105

pandas/core/reshape.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1113,7 +1113,7 @@ def check_len(item, name):
11131113
def _get_dummies_1d(data, prefix, prefix_sep='_', dummy_na=False):
11141114
# Series avoids inconsistent NaN handling
11151115
cat = Categorical.from_array(Series(data))
1116-
levels = cat.levels
1116+
levels = cat.categories
11171117

11181118
# if all NaN
11191119
if not dummy_na and len(levels) == 0:
@@ -1130,7 +1130,7 @@ def _get_dummies_1d(data, prefix, prefix_sep='_', dummy_na=False):
11301130
dummy_mat = np.eye(number_of_cols).take(cat.codes, axis=0)
11311131

11321132
if dummy_na:
1133-
levels = np.append(cat.levels, np.nan)
1133+
levels = np.append(cat.categories, np.nan)
11341134
else:
11351135
# reset NaN GH4446
11361136
dummy_mat[cat.codes == -1] = 0
@@ -1182,7 +1182,7 @@ def make_axis_dummies(frame, axis='minor', transform=None):
11821182
mapped_items = items.map(transform)
11831183
cat = Categorical.from_array(mapped_items.take(labels))
11841184
labels = cat.codes
1185-
items = cat.levels
1185+
items = cat.categories
11861186

11871187
values = np.eye(len(items), dtype=float)
11881188
values = values.take(labels, axis=0)

pandas/core/series.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -922,7 +922,7 @@ def _repr_footer(self):
922922

923923
# Categorical
924924
if com.is_categorical_dtype(self.dtype):
925-
level_info = self.values._repr_level_info()
925+
level_info = self.values._repr_categories_info()
926926
return u('%sLength: %d, dtype: %s\n%s') % (namestr,
927927
len(self),
928928
str(self.dtype.name),

pandas/io/pytables.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -3522,8 +3522,8 @@ def read(self, where=None, columns=None, **kwargs):
35223522
return None
35233523

35243524
factors = [Categorical.from_array(a.values) for a in self.index_axes]
3525-
levels = [f.levels for f in factors]
3526-
N = [len(f.levels) for f in factors]
3525+
levels = [f.categories for f in factors]
3526+
N = [len(f.categories) for f in factors]
35273527
labels = [f.codes for f in factors]
35283528

35293529
# compute the key

pandas/io/tests/test_pytables.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4541,7 +4541,7 @@ def test_categorical(self):
45414541

45424542
with ensure_clean_store(self.path) as store:
45434543

4544-
s = Series(Categorical(['a', 'b', 'b', 'a', 'a', 'c'], levels=['a','b','c','d']))
4544+
s = Series(Categorical(['a', 'b', 'b', 'a', 'a', 'c'], categories=['a','b','c','d']))
45454545

45464546
self.assertRaises(NotImplementedError, store.put, 's_fixed', s, format='fixed')
45474547
self.assertRaises(NotImplementedError, store.append, 's_table', s, format='table')

0 commit comments

Comments
 (0)