Skip to content

Commit 355b462

Browse files
committed
Merge pull request pandas-dev#10632 from JanSchulz/rem_cat_name
Remove Categorical.name
2 parents 30cbb02 + e4639ee commit 355b462

File tree

11 files changed

+65
-94
lines changed

11 files changed

+65
-94
lines changed

doc/source/whatsnew/v0.17.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ Other API Changes
274274
- Enable serialization of lists and dicts to strings in ExcelWriter (:issue:`8188`)
275275
- Allow passing `kwargs` to the interpolation methods (:issue:`10378`).
276276
- Serialize metadata properties of subclasses of pandas objects (:issue:`10553`).
277+
- ``Categorical.name`` was removed to make `Categorical` more ``numpy.ndarray`` like. Use ``Series(cat, name="whatever")`` instead (:issue:`10482`).
277278

278279
- ``NaT``'s methods now either raise ``ValueError``, or return ``np.nan`` or ``NaT`` (:issue:`9513`)
279280
=========================== ==============================================================

pandas/core/categorical.py

+31-45
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,6 @@ class Categorical(PandasObject):
147147
ordered : boolean, (default False)
148148
Whether or not this categorical is treated as a ordered categorical. If not given,
149149
the resulting categorical will not be ordered.
150-
name : str, optional
151-
Name for the Categorical variable. If name is None, will attempt
152-
to infer from values.
153150
154151
Attributes
155152
----------
@@ -159,8 +156,6 @@ class Categorical(PandasObject):
159156
The codes (integer positions, which point to the categories) of this categorical, read only.
160157
ordered : boolean
161158
Whether or not this Categorical is ordered.
162-
name : string
163-
The name of this Categorical.
164159
165160
Raises
166161
------
@@ -205,31 +200,31 @@ class Categorical(PandasObject):
205200
# For comparisons, so that numpy uses our implementation if the compare ops, which raise
206201
__array_priority__ = 1000
207202
_typ = 'categorical'
208-
name = None
209203

210204
def __init__(self, values, categories=None, ordered=False, name=None, fastpath=False,
211205
levels=None):
212206

213207
if fastpath:
214208
# fast path
215209
self._codes = _coerce_indexer_dtype(values, categories)
216-
self.name = name
217210
self.categories = categories
218211
self._ordered = ordered
219212
return
220213

221-
if name is None:
222-
name = getattr(values, 'name', None)
214+
if not name is None:
215+
msg = "the 'name' keyword is removed, use 'name' with consumers of the " \
216+
"categorical instead (e.g. 'Series(cat, name=\"something\")'"
217+
warn(msg, UserWarning, stacklevel=2)
223218

224219
# TODO: Remove after deprecation period in 2017/ after 0.18
225220
if not levels is None:
226221
warn("Creating a 'Categorical' with 'levels' is deprecated, use 'categories' instead",
227-
FutureWarning)
222+
FutureWarning, stacklevel=2)
228223
if categories is None:
229224
categories = levels
230225
else:
231226
raise ValueError("Cannot pass in both 'categories' and (deprecated) 'levels', "
232-
"use only 'categories'")
227+
"use only 'categories'", stacklevel=2)
233228

234229
# sanitize input
235230
if is_categorical_dtype(values):
@@ -293,21 +288,20 @@ def __init__(self, values, categories=None, ordered=False, name=None, fastpath=F
293288
# TODO: check for old style usage. These warnings should be removes after 0.18/ in 2016
294289
if is_integer_dtype(values) and not is_integer_dtype(categories):
295290
warn("Values and categories have different dtypes. Did you mean to use\n"
296-
"'Categorical.from_codes(codes, categories)'?", RuntimeWarning)
291+
"'Categorical.from_codes(codes, categories)'?", RuntimeWarning, stacklevel=2)
297292

298293
if len(values) and is_integer_dtype(values) and (codes == -1).all():
299294
warn("None of the categories were found in values. Did you mean to use\n"
300-
"'Categorical.from_codes(codes, categories)'?", RuntimeWarning)
295+
"'Categorical.from_codes(codes, categories)'?", RuntimeWarning, stacklevel=2)
301296

302297
self.set_ordered(ordered or False, inplace=True)
303298
self.categories = categories
304-
self.name = name
305299
self._codes = _coerce_indexer_dtype(codes, categories)
306300

307301
def copy(self):
308302
""" Copy constructor. """
309303
return Categorical(values=self._codes.copy(),categories=self.categories,
310-
name=self.name, ordered=self.ordered, fastpath=True)
304+
ordered=self.ordered, fastpath=True)
311305

312306
def astype(self, dtype):
313307
""" coerce this type to another dtype """
@@ -373,9 +367,12 @@ def from_codes(cls, codes, categories, ordered=False, name=None):
373367
ordered : boolean, (default False)
374368
Whether or not this categorical is treated as a ordered categorical. If not given,
375369
the resulting categorical will be unordered.
376-
name : str, optional
377-
Name for the Categorical variable.
378370
"""
371+
if not name is None:
372+
msg = "the 'name' keyword is removed, use 'name' with consumers of the " \
373+
"categorical instead (e.g. 'Series(cat, name=\"something\")'"
374+
warn(msg, UserWarning, stacklevel=2)
375+
379376
try:
380377
codes = np.asarray(codes, np.int64)
381378
except:
@@ -386,7 +383,7 @@ def from_codes(cls, codes, categories, ordered=False, name=None):
386383
if len(codes) and (codes.max() >= len(categories) or codes.min() < -1):
387384
raise ValueError("codes need to be between -1 and len(categories)-1")
388385

389-
return Categorical(codes, categories=categories, ordered=ordered, name=name, fastpath=True)
386+
return Categorical(codes, categories=categories, ordered=ordered, fastpath=True)
390387

391388
_codes = None
392389

@@ -416,8 +413,7 @@ def _get_labels(self):
416413
417414
Deprecated, use .codes!
418415
"""
419-
import warnings
420-
warnings.warn("'labels' is deprecated. Use 'codes' instead", FutureWarning)
416+
warn("'labels' is deprecated. Use 'codes' instead", FutureWarning, stacklevel=3)
421417
return self.codes
422418

423419
labels = property(fget=_get_labels, fset=_set_codes)
@@ -464,12 +460,12 @@ def _get_categories(self):
464460

465461
def _set_levels(self, levels):
466462
""" set new levels (deprecated, use "categories") """
467-
warn("Assigning to 'levels' is deprecated, use 'categories'", FutureWarning)
463+
warn("Assigning to 'levels' is deprecated, use 'categories'", FutureWarning, stacklevel=3)
468464
self.categories = levels
469465

470466
def _get_levels(self):
471467
""" Gets the levels (deprecated, use "categories") """
472-
warn("Accessing 'levels' is deprecated, use 'categories'", FutureWarning)
468+
warn("Accessing 'levels' is deprecated, use 'categories'", FutureWarning, stacklevel=3)
473469
return self.categories
474470

475471
# TODO: Remove after deprecation period in 2017/ after 0.18
@@ -479,7 +475,8 @@ def _get_levels(self):
479475

480476
def _set_ordered(self, value):
481477
""" Sets the ordered attribute to the boolean value """
482-
warn("Setting 'ordered' directly is deprecated, use 'set_ordered'", FutureWarning)
478+
warn("Setting 'ordered' directly is deprecated, use 'set_ordered'", FutureWarning,
479+
stacklevel=3)
483480
self.set_ordered(value, inplace=True)
484481

485482
def set_ordered(self, value, inplace=False):
@@ -1140,7 +1137,7 @@ def order(self, inplace=False, ascending=True, na_position='last'):
11401137
return
11411138
else:
11421139
return Categorical(values=codes,categories=self.categories, ordered=self.ordered,
1143-
name=self.name, fastpath=True)
1140+
fastpath=True)
11441141

11451142

11461143
def sort(self, inplace=True, ascending=True, na_position='last'):
@@ -1266,7 +1263,7 @@ def fillna(self, value=None, method=None, limit=None):
12661263
values[mask] = self.categories.get_loc(value)
12671264

12681265
return Categorical(values, categories=self.categories, ordered=self.ordered,
1269-
name=self.name, fastpath=True)
1266+
fastpath=True)
12701267

12711268
def take_nd(self, indexer, allow_fill=True, fill_value=None):
12721269
""" Take the codes by the indexer, fill with the fill_value.
@@ -1280,7 +1277,7 @@ def take_nd(self, indexer, allow_fill=True, fill_value=None):
12801277

12811278
codes = take_1d(self._codes, indexer, allow_fill=True, fill_value=-1)
12821279
result = Categorical(codes, categories=self.categories, ordered=self.ordered,
1283-
name=self.name, fastpath=True)
1280+
fastpath=True)
12841281
return result
12851282

12861283
take = take_nd
@@ -1300,7 +1297,7 @@ def _slice(self, slicer):
13001297

13011298
_codes = self._codes[slicer]
13021299
return Categorical(values=_codes,categories=self.categories, ordered=self.ordered,
1303-
name=self.name, fastpath=True)
1300+
fastpath=True)
13041301

13051302
def __len__(self):
13061303
"""The length of this Categorical."""
@@ -1313,9 +1310,8 @@ def __iter__(self):
13131310
def _tidy_repr(self, max_vals=10, footer=True):
13141311
""" a short repr displaying only max_vals and an optional (but default footer) """
13151312
num = max_vals // 2
1316-
head = self[:num]._get_repr(length=False, name=False, footer=False)
1313+
head = self[:num]._get_repr(length=False, footer=False)
13171314
tail = self[-(max_vals - num):]._get_repr(length=False,
1318-
name=False,
13191315
footer=False)
13201316

13211317
result = '%s, ..., %s' % (head[:-1], tail[1:])
@@ -1369,14 +1365,11 @@ def _repr_categories_info(self):
13691365

13701366
def _repr_footer(self):
13711367

1372-
namestr = "Name: %s, " % self.name if self.name is not None else ""
1373-
return u('%sLength: %d\n%s') % (namestr,
1374-
len(self), self._repr_categories_info())
1368+
return u('Length: %d\n%s') % (len(self), self._repr_categories_info())
13751369

1376-
def _get_repr(self, name=False, length=True, na_rep='NaN', footer=True):
1370+
def _get_repr(self, length=True, na_rep='NaN', footer=True):
13771371
from pandas.core import format as fmt
13781372
formatter = fmt.CategoricalFormatter(self,
1379-
name=name,
13801373
length=length,
13811374
na_rep=na_rep,
13821375
footer=footer)
@@ -1389,11 +1382,9 @@ def __unicode__(self):
13891382
if len(self._codes) > _maxlen:
13901383
result = self._tidy_repr(_maxlen)
13911384
elif len(self._codes) > 0:
1392-
result = self._get_repr(length=len(self) > _maxlen,
1393-
name=True)
1385+
result = self._get_repr(length=len(self) > _maxlen)
13941386
else:
1395-
result = '[], %s' % self._get_repr(name=True,
1396-
length=False,
1387+
result = '[], %s' % self._get_repr(length=False,
13971388
footer=True,
13981389
).replace("\n",", ")
13991390

@@ -1562,8 +1553,7 @@ def mode(self):
15621553
import pandas.hashtable as htable
15631554
good = self._codes != -1
15641555
result = Categorical(sorted(htable.mode_int64(_ensure_int64(self._codes[good]))),
1565-
categories=self.categories,ordered=self.ordered, name=self.name,
1566-
fastpath=True)
1556+
categories=self.categories,ordered=self.ordered, fastpath=True)
15671557
return result
15681558

15691559
def unique(self):
@@ -1586,8 +1576,6 @@ def equals(self, other):
15861576
"""
15871577
Returns True if categorical arrays are equal.
15881578
1589-
The name of the `Categorical` is not compared!
1590-
15911579
Parameters
15921580
----------
15931581
other : `Categorical`
@@ -1596,7 +1584,6 @@ def equals(self, other):
15961584
-------
15971585
are_equal : boolean
15981586
"""
1599-
# TODO: should this also test if name is equal?
16001587
return self.is_dtype_equal(other) and np.array_equal(self._codes, other._codes)
16011588

16021589
def is_dtype_equal(self, other):
@@ -1647,7 +1634,7 @@ def repeat(self, repeats):
16471634
"""
16481635
codes = self._codes.repeat(repeats)
16491636
return Categorical(values=codes, categories=self.categories,
1650-
ordered=self.ordered, name=self.name, fastpath=True)
1637+
ordered=self.ordered, fastpath=True)
16511638

16521639

16531640
##### The Series.cat accessor #####
@@ -1696,7 +1683,6 @@ def _delegate_method(self, name, *args, **kwargs):
16961683
if not res is None:
16971684
return Series(res, index=self.index)
16981685

1699-
# TODO: remove levels after the deprecation period
17001686
CategoricalAccessor._add_delegate_accessors(delegate=Categorical,
17011687
accessors=["categories", "ordered"],
17021688
typ='property')

pandas/core/format.py

+1-8
Original file line numberDiff line numberDiff line change
@@ -68,23 +68,16 @@
6868
class CategoricalFormatter(object):
6969

7070
def __init__(self, categorical, buf=None, length=True,
71-
na_rep='NaN', name=False, footer=True):
71+
na_rep='NaN', footer=True):
7272
self.categorical = categorical
7373
self.buf = buf if buf is not None else StringIO(u(""))
74-
self.name = name
7574
self.na_rep = na_rep
7675
self.length = length
7776
self.footer = footer
7877

7978
def _get_footer(self):
8079
footer = ''
8180

82-
if self.name:
83-
name = com.pprint_thing(self.categorical.name,
84-
escape_chars=('\t', '\r', '\n'))
85-
footer += ('Name: %s' % name if self.categorical.name is not None
86-
else '')
87-
8881
if self.length:
8982
if footer:
9083
footer += ', '

pandas/core/groupby.py

-2
Original file line numberDiff line numberDiff line change
@@ -1969,8 +1969,6 @@ def __init__(self, index, grouper=None, obj=None, name=None, level=None,
19691969
self._group_index = CategoricalIndex(Categorical.from_codes(np.arange(len(c)),
19701970
categories=c,
19711971
ordered=self.grouper.ordered))
1972-
if self.name is None:
1973-
self.name = self.grouper.name
19741972

19751973
# a passed Grouper like
19761974
elif isinstance(self.grouper, Grouper):

pandas/core/index.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4418,7 +4418,7 @@ def from_arrays(cls, arrays, sortorder=None, names=None):
44184418
levels = [c.categories for c in cats]
44194419
labels = [c.codes for c in cats]
44204420
if names is None:
4421-
names = [c.name for c in cats]
4421+
names = [getattr(arr, "name", None) for arr in arrays]
44224422

44234423
return MultiIndex(levels=levels, labels=labels,
44244424
sortorder=sortorder, names=names,

pandas/core/series.py

-2
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,6 @@ def __init__(self, data=None, index=None, dtype=None, name=None,
189189
elif isinstance(data, Categorical):
190190
if dtype is not None:
191191
raise ValueError("cannot specify a dtype with a Categorical")
192-
if name is None:
193-
name = data.name
194192
elif (isinstance(data, types.GeneratorType) or
195193
(compat.PY3 and isinstance(data, map))):
196194
data = list(data)

0 commit comments

Comments
 (0)