10
10
import pandas .core .common as com
11
11
import pandas .algos as algos
12
12
import pandas .hashtable as htable
13
+ from pandas .types import api as gt
13
14
from pandas .compat import string_types
14
15
from pandas .tslib import iNaT
15
16
@@ -253,27 +254,28 @@ def value_counts(values, sort=True, ascending=False, normalize=False,
253
254
254
255
"""
255
256
from pandas .core .series import Series
256
- from pandas .tools .tile import cut
257
-
258
257
name = getattr (values , 'name' , None )
259
- values = Series (values ).values
260
258
261
259
if bins is not None :
262
260
try :
261
+ from pandas .tools .tile import cut
262
+ values = Series (values ).values
263
263
cat , bins = cut (values , bins , retbins = True )
264
264
except TypeError :
265
265
raise TypeError ("bins argument only works with numeric data." )
266
266
values = cat .codes
267
267
268
- if com .is_extension_type (values ):
269
- result = values .value_counts (dropna = dropna )
268
+ if com .is_extension_type (values ) and not com .is_datetimetz (values ):
269
+ # handle Categorical and sparse,
270
+ # datetime tz can be handeled in ndarray path
271
+ result = Series (values ).values .value_counts (dropna = dropna )
270
272
result .name = name
271
273
counts = result .values
272
274
else :
273
- # ndarray path
275
+ # ndarray path. pass original to handle DatetimeTzBlock
274
276
keys , counts = _value_counts_arraylike (values , dropna = dropna )
275
277
276
- from pandas import Index
278
+ from pandas import Index , Series
277
279
if not isinstance (keys , Index ):
278
280
keys = Index (keys )
279
281
result = Series (counts , index = keys , name = name )
@@ -294,20 +296,23 @@ def value_counts(values, sort=True, ascending=False, normalize=False,
294
296
295
297
296
298
def _value_counts_arraylike (values , dropna = True ):
297
- from pandas import PeriodIndex , DatetimeIndex
299
+ is_datetimetz = com .is_datetimetz (values )
300
+ is_period = (isinstance (values , gt .ABCPeriodIndex ) or
301
+ com .is_period_arraylike (values ))
302
+
303
+ orig = values
298
304
305
+ from pandas .core .series import Series
306
+ values = Series (values ).values
299
307
dtype = values .dtype
300
- is_period = com .is_period_arraylike (values )
301
- is_datetimetz = com .is_datetimetz (values )
302
308
303
- if com .is_datetime_or_timedelta_dtype (dtype ) or is_period or \
304
- is_datetimetz :
309
+ if com .is_datetime_or_timedelta_dtype (dtype ) or is_period :
310
+ from pandas .tseries .index import DatetimeIndex
311
+ from pandas .tseries .period import PeriodIndex
305
312
306
313
if is_period :
307
314
values = PeriodIndex (values )
308
- elif is_datetimetz :
309
- tz = getattr (values , 'tz' , None )
310
- values = DatetimeIndex (values ).tz_localize (None )
315
+ freq = values .freq
311
316
312
317
values = values .view (np .int64 )
313
318
keys , counts = htable .value_count_scalar64 (values , dropna )
@@ -316,21 +321,25 @@ def _value_counts_arraylike(values, dropna=True):
316
321
msk = keys != iNaT
317
322
keys , counts = keys [msk ], counts [msk ]
318
323
319
- # localize to the original tz if necessary
320
- if is_datetimetz :
321
- keys = DatetimeIndex (keys ).tz_localize (tz )
322
-
323
324
# convert the keys back to the dtype we came in
324
- else :
325
- keys = keys .astype (dtype )
325
+ keys = keys .astype (dtype )
326
+
327
+ # dtype handling
328
+ if is_datetimetz :
329
+ if isinstance (orig , gt .ABCDatetimeIndex ):
330
+ tz = orig .tz
331
+ else :
332
+ tz = orig .dt .tz
333
+ keys = DatetimeIndex ._simple_new (keys , tz = tz )
334
+ if is_period :
335
+ keys = PeriodIndex ._simple_new (keys , freq = freq )
326
336
327
337
elif com .is_integer_dtype (dtype ):
328
338
values = com ._ensure_int64 (values )
329
339
keys , counts = htable .value_count_scalar64 (values , dropna )
330
340
elif com .is_float_dtype (dtype ):
331
341
values = com ._ensure_float64 (values )
332
342
keys , counts = htable .value_count_scalar64 (values , dropna )
333
-
334
343
else :
335
344
values = com ._ensure_object (values )
336
345
mask = com .isnull (values )
0 commit comments