@@ -327,7 +327,7 @@ def _aggregate_multiple_funcs(self, arg):
327
327
# let higher level handle
328
328
return results
329
329
330
- return DataFrame (results , columns = columns )
330
+ return self . obj . _constructor_expanddim (results , columns = columns )
331
331
332
332
def _wrap_series_output (
333
333
self , output : Mapping [base .OutputKey , Union [Series , np .ndarray ]], index : Index ,
@@ -356,10 +356,12 @@ def _wrap_series_output(
356
356
357
357
result : Union [Series , DataFrame ]
358
358
if len (output ) > 1 :
359
- result = DataFrame (indexed_output , index = index )
359
+ result = self . obj . _constructor_expanddim (indexed_output , index = index )
360
360
result .columns = columns
361
361
else :
362
- result = Series (indexed_output [0 ], index = index , name = columns [0 ])
362
+ result = self .obj ._constructor (
363
+ indexed_output [0 ], index = index , name = columns [0 ]
364
+ )
363
365
364
366
return result
365
367
@@ -418,7 +420,9 @@ def _wrap_transformed_output(
418
420
def _wrap_applied_output (self , keys , values , not_indexed_same = False ):
419
421
if len (keys ) == 0 :
420
422
# GH #6265
421
- return Series ([], name = self ._selection_name , index = keys , dtype = np .float64 )
423
+ return self .obj ._constructor (
424
+ [], name = self ._selection_name , index = keys , dtype = np .float64
425
+ )
422
426
423
427
def _get_index () -> Index :
424
428
if self .grouper .nkeys > 1 :
@@ -430,7 +434,9 @@ def _get_index() -> Index:
430
434
if isinstance (values [0 ], dict ):
431
435
# GH #823 #24880
432
436
index = _get_index ()
433
- result = self ._reindex_output (DataFrame (values , index = index ))
437
+ result = self ._reindex_output (
438
+ self .obj ._constructor_expanddim (values , index = index )
439
+ )
434
440
# if self.observed is False,
435
441
# keep all-NaN rows created while re-indexing
436
442
result = result .stack (dropna = self .observed )
@@ -444,7 +450,9 @@ def _get_index() -> Index:
444
450
return self ._concat_objects (keys , values , not_indexed_same = not_indexed_same )
445
451
else :
446
452
# GH #6265 #24880
447
- result = Series (data = values , index = _get_index (), name = self ._selection_name )
453
+ result = self .obj ._constructor (
454
+ data = values , index = _get_index (), name = self ._selection_name
455
+ )
448
456
return self ._reindex_output (result )
449
457
450
458
def _aggregate_named (self , func , * args , ** kwargs ):
@@ -520,7 +528,7 @@ def _transform_general(
520
528
521
529
result = concat (results ).sort_index ()
522
530
else :
523
- result = Series (dtype = np .float64 )
531
+ result = self . obj . _constructor (dtype = np .float64 )
524
532
525
533
# we will only try to coerce the result type if
526
534
# we have a numeric dtype, as these are *always* user-defined funcs
@@ -543,7 +551,7 @@ def _transform_fast(self, result, func_nm: str) -> Series:
543
551
out = algorithms .take_1d (result ._values , ids )
544
552
if cast :
545
553
out = maybe_cast_result (out , self .obj , how = func_nm )
546
- return Series (out , index = self .obj .index , name = self .obj .name )
554
+ return self . obj . _constructor (out , index = self .obj .index , name = self .obj .name )
547
555
548
556
def filter (self , func , dropna = True , * args , ** kwargs ):
549
557
"""
@@ -644,7 +652,7 @@ def nunique(self, dropna: bool = True) -> Series:
644
652
res , out = np .zeros (len (ri ), dtype = out .dtype ), res
645
653
res [ids [idx ]] = out
646
654
647
- result = Series (res , index = ri , name = self ._selection_name )
655
+ result = self . obj . _constructor (res , index = ri , name = self ._selection_name )
648
656
return self ._reindex_output (result , fill_value = 0 )
649
657
650
658
@doc (Series .describe )
@@ -746,7 +754,7 @@ def value_counts(
746
754
747
755
if is_integer_dtype (out ):
748
756
out = ensure_int64 (out )
749
- return Series (out , index = mi , name = self ._selection_name )
757
+ return self . obj . _constructor (out , index = mi , name = self ._selection_name )
750
758
751
759
# for compat. with libgroupby.value_counts need to ensure every
752
760
# bin is present at every index level, null filled with zeros
@@ -778,7 +786,7 @@ def build_codes(lev_codes: np.ndarray) -> np.ndarray:
778
786
779
787
if is_integer_dtype (out ):
780
788
out = ensure_int64 (out )
781
- return Series (out , index = mi , name = self ._selection_name )
789
+ return self . obj . _constructor (out , index = mi , name = self ._selection_name )
782
790
783
791
def count (self ) -> Series :
784
792
"""
@@ -797,7 +805,7 @@ def count(self) -> Series:
797
805
minlength = ngroups or 0
798
806
out = np .bincount (ids [mask ], minlength = minlength )
799
807
800
- result = Series (
808
+ result = self . obj . _constructor (
801
809
out ,
802
810
index = self .grouper .result_index ,
803
811
name = self ._selection_name ,
@@ -1195,11 +1203,11 @@ def _aggregate_item_by_item(self, func, *args, **kwargs) -> DataFrame:
1195
1203
if cannot_agg :
1196
1204
result_columns = result_columns .drop (cannot_agg )
1197
1205
1198
- return DataFrame (result , columns = result_columns )
1206
+ return self . obj . _constructor (result , columns = result_columns )
1199
1207
1200
1208
def _wrap_applied_output (self , keys , values , not_indexed_same = False ):
1201
1209
if len (keys ) == 0 :
1202
- return DataFrame (index = keys )
1210
+ return self . obj . _constructor (index = keys )
1203
1211
1204
1212
key_names = self .grouper .names
1205
1213
@@ -1209,7 +1217,7 @@ def _wrap_applied_output(self, keys, values, not_indexed_same=False):
1209
1217
if first_not_none is None :
1210
1218
# GH9684. If all values are None, then this will throw an error.
1211
1219
# We'd prefer it return an empty dataframe.
1212
- return DataFrame ()
1220
+ return self . obj . _constructor ()
1213
1221
elif isinstance (first_not_none , DataFrame ):
1214
1222
return self ._concat_objects (keys , values , not_indexed_same = not_indexed_same )
1215
1223
elif self .grouper .groupings is not None :
@@ -1240,13 +1248,13 @@ def _wrap_applied_output(self, keys, values, not_indexed_same=False):
1240
1248
1241
1249
# make Nones an empty object
1242
1250
if first_not_none is None :
1243
- return DataFrame ()
1251
+ return self . obj . _constructor ()
1244
1252
elif isinstance (first_not_none , NDFrame ):
1245
1253
1246
1254
# this is to silence a DeprecationWarning
1247
1255
# TODO: Remove when default dtype of empty Series is object
1248
1256
kwargs = first_not_none ._construct_axes_dict ()
1249
- if first_not_none . _constructor is Series :
1257
+ if isinstance ( first_not_none , Series ) :
1250
1258
backup = create_series_with_explicit_dtype (
1251
1259
** kwargs , dtype_if_empty = object
1252
1260
)
@@ -1313,7 +1321,7 @@ def _wrap_applied_output(self, keys, values, not_indexed_same=False):
1313
1321
or isinstance (key_index , MultiIndex )
1314
1322
):
1315
1323
stacked_values = np .vstack ([np .asarray (v ) for v in values ])
1316
- result = DataFrame (
1324
+ result = self . obj . _constructor (
1317
1325
stacked_values , index = key_index , columns = index
1318
1326
)
1319
1327
else :
@@ -1330,15 +1338,17 @@ def _wrap_applied_output(self, keys, values, not_indexed_same=False):
1330
1338
result .columns = index
1331
1339
elif isinstance (v , ABCSeries ):
1332
1340
stacked_values = np .vstack ([np .asarray (v ) for v in values ])
1333
- result = DataFrame (
1341
+ result = self . obj . _constructor (
1334
1342
stacked_values .T , index = v .index , columns = key_index
1335
1343
)
1336
1344
else :
1337
1345
# GH#1738: values is list of arrays of unequal lengths
1338
1346
# fall through to the outer else clause
1339
1347
# TODO: sure this is right? we used to do this
1340
1348
# after raising AttributeError above
1341
- return Series (values , index = key_index , name = self ._selection_name )
1349
+ return self .obj ._constructor_sliced (
1350
+ values , index = key_index , name = self ._selection_name
1351
+ )
1342
1352
1343
1353
# if we have date/time like in the original, then coerce dates
1344
1354
# as we are stacking can easily have object dtypes here
@@ -1355,7 +1365,7 @@ def _wrap_applied_output(self, keys, values, not_indexed_same=False):
1355
1365
# self._selection_name not passed through to Series as the
1356
1366
# result should not take the name of original selection
1357
1367
# of columns
1358
- return Series (values , index = key_index )
1368
+ return self . obj . _constructor_sliced (values , index = key_index )
1359
1369
1360
1370
else :
1361
1371
# Handle cases like BinGrouper
@@ -1385,7 +1395,9 @@ def _transform_general(
1385
1395
if cache_key not in NUMBA_FUNC_CACHE :
1386
1396
NUMBA_FUNC_CACHE [cache_key ] = numba_func
1387
1397
# Return the result as a DataFrame for concatenation later
1388
- res = DataFrame (res , index = group .index , columns = group .columns )
1398
+ res = self .obj ._constructor (
1399
+ res , index = group .index , columns = group .columns
1400
+ )
1389
1401
else :
1390
1402
# Try slow path and fast path.
1391
1403
try :
@@ -1408,7 +1420,7 @@ def _transform_general(
1408
1420
r .columns = group .columns
1409
1421
r .index = group .index
1410
1422
else :
1411
- r = DataFrame (
1423
+ r = self . obj . _constructor (
1412
1424
np .concatenate ([res .values ] * len (group .index )).reshape (
1413
1425
group .shape
1414
1426
),
@@ -1484,7 +1496,9 @@ def _transform_fast(self, result: DataFrame, func_nm: str) -> DataFrame:
1484
1496
res = maybe_cast_result (res , obj .iloc [:, i ], how = func_nm )
1485
1497
output .append (res )
1486
1498
1487
- return DataFrame ._from_arrays (output , columns = result .columns , index = obj .index )
1499
+ return self .obj ._constructor ._from_arrays (
1500
+ output , columns = result .columns , index = obj .index
1501
+ )
1488
1502
1489
1503
def _define_paths (self , func , * args , ** kwargs ):
1490
1504
if isinstance (func , str ):
@@ -1546,7 +1560,7 @@ def _transform_item_by_item(self, obj: DataFrame, wrapper) -> DataFrame:
1546
1560
if len (output ) < len (obj .columns ):
1547
1561
columns = columns .take (inds )
1548
1562
1549
- return DataFrame (output , index = obj .index , columns = columns )
1563
+ return self . obj . _constructor (output , index = obj .index , columns = columns )
1550
1564
1551
1565
def filter (self , func , dropna = True , * args , ** kwargs ):
1552
1566
"""
@@ -1661,9 +1675,11 @@ def _wrap_frame_output(self, result, obj) -> DataFrame:
1661
1675
result_index = self .grouper .levels [0 ]
1662
1676
1663
1677
if self .axis == 0 :
1664
- return DataFrame (result , index = obj .columns , columns = result_index ).T
1678
+ return self .obj ._constructor (
1679
+ result , index = obj .columns , columns = result_index
1680
+ ).T
1665
1681
else :
1666
- return DataFrame (result , index = obj .index , columns = result_index )
1682
+ return self . obj . _constructor (result , index = obj .index , columns = result_index )
1667
1683
1668
1684
def _get_data_to_aggregate (self ) -> BlockManager :
1669
1685
obj = self ._obj_with_exclusions
@@ -1707,7 +1723,7 @@ def _wrap_aggregated_output(
1707
1723
indexed_output = {key .position : val for key , val in output .items ()}
1708
1724
columns = Index (key .label for key in output )
1709
1725
1710
- result = DataFrame (indexed_output )
1726
+ result = self . obj . _constructor (indexed_output )
1711
1727
result .columns = columns
1712
1728
1713
1729
if not self .as_index :
@@ -1740,7 +1756,7 @@ def _wrap_transformed_output(
1740
1756
indexed_output = {key .position : val for key , val in output .items ()}
1741
1757
columns = Index (key .label for key in output )
1742
1758
1743
- result = DataFrame (indexed_output )
1759
+ result = self . obj . _constructor (indexed_output )
1744
1760
result .columns = columns
1745
1761
result .index = self .obj .index
1746
1762
@@ -1750,14 +1766,14 @@ def _wrap_agged_blocks(self, blocks: "Sequence[Block]", items: Index) -> DataFra
1750
1766
if not self .as_index :
1751
1767
index = np .arange (blocks [0 ].values .shape [- 1 ])
1752
1768
mgr = BlockManager (blocks , axes = [items , index ])
1753
- result = DataFrame (mgr )
1769
+ result = self . obj . _constructor (mgr )
1754
1770
1755
1771
self ._insert_inaxis_grouper_inplace (result )
1756
1772
result = result ._consolidate ()
1757
1773
else :
1758
1774
index = self .grouper .result_index
1759
1775
mgr = BlockManager (blocks , axes = [items , index ])
1760
- result = DataFrame (mgr )
1776
+ result = self . obj . _constructor (mgr )
1761
1777
1762
1778
if self .axis == 1 :
1763
1779
result = result .T
0 commit comments