Skip to content

Commit 5ed4be7

Browse files
committed
copy
1 parent e692e32 commit 5ed4be7

File tree

3 files changed

+54
-14
lines changed

3 files changed

+54
-14
lines changed

pandas/core/categorical.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,8 @@ def _codes_for_groupby(self, sort):
616616
return self.reorder_categories(cat.categories)
617617

618618
def _set_dtype(self, dtype):
619-
return type(self)(self, dtype=dtype, fastpath=True)
619+
# TODO: this could go fast from codes maybe?
620+
return type(self)(self.codes, dtype=dtype, fastpath=True)
620621

621622
def set_ordered(self, value, inplace=False):
622623
"""

pandas/core/indexes/category.py

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,18 @@ def __new__(cls, data=None, categories=None, ordered=None, dtype=None,
6060
copy=False, name=None, fastpath=False, **kwargs):
6161

6262
if fastpath:
63-
return cls._simple_new(data, name=name)
63+
return cls._simple_new(data, name=name, dtype=dtype)
6464

6565
if name is None and hasattr(data, 'name'):
6666
name = data.name
6767

6868
if isinstance(data, ABCCategorical):
69-
data = cls._create_categorical(cls, data, categories, ordered)
69+
data = cls._create_categorical(cls, data, categories, ordered,
70+
dtype)
7071
elif isinstance(data, CategoricalIndex):
7172
data = data._data
72-
data = cls._create_categorical(cls, data, categories, ordered)
73+
data = cls._create_categorical(cls, data, categories, ordered,
74+
dtype)
7375
else:
7476

7577
# don't allow scalars
@@ -116,7 +118,8 @@ def _create_from_codes(self, codes, categories=None, ordered=None,
116118
return CategoricalIndex(cat, name=name)
117119

118120
@staticmethod
119-
def _create_categorical(self, data, categories=None, ordered=None):
121+
def _create_categorical(self, data, categories=None, ordered=None,
122+
dtype=None):
120123
"""
121124
*this is an internal non-public method*
122125
@@ -127,28 +130,34 @@ def _create_categorical(self, data, categories=None, ordered=None):
127130
data : data for new Categorical
128131
categories : optional categories, defaults to existing
129132
ordered : optional ordered attribute, defaults to existing
133+
dtype : CategoricalDtype, defaults to existing
130134
131135
Returns
132136
-------
133137
Categorical
134138
"""
135139
if not isinstance(data, ABCCategorical):
136-
ordered = False if ordered is None else ordered
140+
if ordered is None and dtype is None:
141+
ordered = False
137142
from pandas.core.categorical import Categorical
138-
data = Categorical(data, categories=categories, ordered=ordered)
143+
data = Categorical(data, categories=categories, ordered=ordered,
144+
dtype=dtype)
139145
else:
140146
if categories is not None:
141-
data = data.set_categories(categories)
142-
if ordered is not None:
147+
data = data.set_categories(categories, ordered=ordered)
148+
elif ordered is not None and ordered != data.ordered:
143149
data = data.set_ordered(ordered)
150+
elif dtype is not None:
151+
data = data._set_dtype(dtype)
144152
return data
145153

146154
@classmethod
147155
def _simple_new(cls, values, name=None, categories=None, ordered=None,
148-
**kwargs):
156+
dtype=None, **kwargs):
149157
result = object.__new__(cls)
150158

151-
values = cls._create_categorical(cls, values, categories, ordered)
159+
values = cls._create_categorical(cls, values, categories, ordered,
160+
dtype=dtype)
152161
result._data = values
153162
result.name = name
154163
for k, v in compat.iteritems(kwargs):
@@ -162,15 +171,24 @@ def _shallow_copy(self, values=None, categories=None, ordered=None,
162171
dtype=None, **kwargs):
163172
# categories and ordered can't be part of attributes,
164173
# as these are properties
174+
# we want to reuse self.dtype if possible, i.e. neither are
175+
# overridden.
176+
if dtype is not None and (categories is not None or
177+
ordered is not None):
178+
raise TypeError
179+
180+
if categories is None and ordered is None:
181+
dtype = self.dtype if dtype is None else dtype
182+
return super(CategoricalIndex, self)._shallow_copy(
183+
values=values, dtype=dtype, **kwargs)
165184
if categories is None:
166185
categories = self.categories
167186
if ordered is None:
168187
ordered = self.ordered
169-
if dtype is None:
170-
dtype = self.dtype
188+
171189
return super(CategoricalIndex, self)._shallow_copy(
172190
values=values, categories=categories,
173-
ordered=ordered, dtype=dtype, **kwargs)
191+
ordered=ordered, **kwargs)
174192

175193
def _is_dtype_compat(self, other):
176194
"""

pandas/tests/test_categorical.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,27 @@ def test_constructor_invariant(self):
432432
c2 = Categorical(c)
433433
tm.assert_categorical_equal(c, c2)
434434

435+
@pytest.mark.parametrize('ordered', [True, False])
436+
def test_constructor_with_dtype(self, ordered):
437+
categories = ['b', 'a', 'c']
438+
dtype = CategoricalDtype(categories, ordered=ordered)
439+
result = pd.Categorical(['a', 'b', 'a', 'c'], dtype=dtype)
440+
expected = pd.Categorical(['a', 'b', 'a', 'c'], categories=categories,
441+
ordered=ordered)
442+
tm.assert_categorical_equal(result, expected)
443+
assert result.ordered is ordered
444+
445+
def test_constructor_dtype_and_others_raises(self):
446+
dtype = CategoricalDtype(['a', 'b'], ordered=True)
447+
with tm.assert_raises_regex(ValueError, "Cannot"):
448+
Categorical(['a', 'b'], categories=['a', 'b'], dtype=dtype)
449+
450+
with tm.assert_raises_regex(ValueError, "Cannot"):
451+
Categorical(['a', 'b'], ordered=True, dtype=dtype)
452+
453+
with tm.assert_raises_regex(ValueError, "Cannot"):
454+
Categorical(['a', 'b'], ordered=False, dtype=dtype)
455+
435456
def test_from_codes(self):
436457

437458
# too few categories

0 commit comments

Comments
 (0)