@@ -34,6 +34,7 @@ class providing the base-class of operations.
3434
3535import numpy as np
3636
37+ from pandas ._config import using_string_dtype
3738from pandas ._config .config import option_context
3839
3940from pandas ._libs import (
@@ -3156,7 +3157,7 @@ def sum(
31563157 npfunc = np .sum ,
31573158 )
31583159
3159- return self ._reindex_output (result , fill_value = 0 )
3160+ return self ._reindex_output (result , fill_value = 0 , method = "sum" )
31603161
31613162 @final
31623163 @doc (
@@ -5574,6 +5575,7 @@ def _reindex_output(
55745575 output : OutputFrameOrSeries ,
55755576 fill_value : Scalar = np .nan ,
55765577 qs : npt .NDArray [np .float64 ] | None = None ,
5578+ method : str | None = None ,
55775579 ) -> OutputFrameOrSeries :
55785580 """
55795581 If we have categorical groupers, then we might want to make sure that
@@ -5634,6 +5636,24 @@ def _reindex_output(
56345636 "copy" : False ,
56355637 "fill_value" : fill_value ,
56365638 }
5639+ if using_string_dtype () and method == "sum" :
5640+ if isinstance (output , Series ) and isinstance (output .dtype , StringDtype ):
5641+ d ["fill_value" ] = ""
5642+ return output .reindex (** d ) # type: ignore[arg-type]
5643+ elif isinstance (output , DataFrame ) and any (
5644+ isinstance (dtype , StringDtype ) for dtype in output .dtypes
5645+ ):
5646+ orig_dtypes = output .dtypes
5647+ indices = np .nonzero (output .dtypes == "string" )[0 ]
5648+ for idx in indices :
5649+ output .isetitem (idx , output .iloc [:, idx ].astype (object ))
5650+ output = output .reindex (** d )
5651+ for idx in indices :
5652+ col = output .iloc [:, idx ]
5653+ output .isetitem (
5654+ idx , col .mask (col == 0 , "" ).astype (orig_dtypes .iloc [idx ])
5655+ )
5656+ return output
56375657 return output .reindex (** d ) # type: ignore[arg-type]
56385658
56395659 # GH 13204
0 commit comments