@@ -534,19 +534,13 @@ def _set_value(self, index, col, value, takeable=False):
534
534
# Arithmetic-related methods
535
535
536
536
def _combine_frame (self , other , func , fill_value = None , level = None ):
537
- if level is not None :
538
- raise NotImplementedError ("'level' argument is not supported" )
539
-
540
537
this , other = self .align (other , join = "outer" , level = level , copy = False )
541
- new_index , new_columns = this .index , this .columns
542
-
543
- if self .empty and other .empty :
544
- return self ._constructor (index = new_index ).__finalize__ (self )
538
+ this ._default_fill_value = self ._default_fill_value
545
539
546
540
new_data = {}
547
541
if fill_value is not None :
548
542
# TODO: be a bit more intelligent here
549
- for col in new_columns :
543
+ for col in this . columns :
550
544
if col in this and col in other :
551
545
dleft = this [col ].to_dense ()
552
546
dright = other [col ].to_dense ()
@@ -555,66 +549,62 @@ def _combine_frame(self, other, func, fill_value=None, level=None):
555
549
new_data [col ] = result
556
550
else :
557
551
558
- for col in new_columns :
552
+ for col in this . columns :
559
553
if col in this and col in other :
560
554
new_data [col ] = func (this [col ], other [col ])
561
555
562
- new_fill_value = self ._get_op_result_fill_value (other , func )
563
-
564
- return self ._constructor (
565
- data = new_data ,
566
- index = new_index ,
567
- columns = new_columns ,
568
- default_fill_value = new_fill_value ,
569
- ).__finalize__ (self )
556
+ return this ._construct_result (other , new_data , func )
570
557
571
558
def _combine_match_index (self , other , func , level = None ):
572
-
573
- if level is not None :
574
- raise NotImplementedError ("'level' argument is not supported" )
575
-
576
559
this , other = self .align (other , join = "outer" , axis = 0 , level = level , copy = False )
560
+ this ._default_fill_value = self ._default_fill_value
577
561
578
562
new_data = {}
579
563
for col in this .columns :
580
564
new_data [col ] = func (this [col ], other )
581
565
582
- fill_value = self ._get_op_result_fill_value (other , func )
583
-
584
- return self ._constructor (
585
- new_data ,
586
- index = this .index ,
587
- columns = self .columns ,
588
- default_fill_value = fill_value ,
589
- ).__finalize__ (self )
566
+ return this ._construct_result (other , new_data , func )
590
567
591
568
def _combine_match_columns (self , other , func , level = None ):
592
569
# patched version of DataFrame._combine_match_columns to account for
593
570
# NumPy circumventing __rsub__ with float64 types, e.g.: 3.0 - series,
594
571
# where 3.0 is numpy.float64 and series is a SparseSeries. Still
595
572
# possible for this to happen, which is bothersome
596
573
597
- if level is not None :
598
- raise NotImplementedError ("'level' argument is not supported" )
599
-
600
574
left , right = self .align (other , join = "outer" , axis = 1 , level = level , copy = False )
601
575
assert left .columns .equals (right .index )
576
+ left ._default_fill_value = self ._default_fill_value
602
577
603
578
new_data = {}
604
-
605
579
for col in left .columns :
606
580
new_data [col ] = func (left [col ], right [col ])
607
581
608
- return self ._constructor (
609
- new_data ,
610
- index = left .index ,
611
- columns = left .columns ,
612
- default_fill_value = self .default_fill_value ,
613
- ).__finalize__ (self )
582
+ # TODO: using this changed some behavior, see GH#28025
583
+ return left ._construct_result (other , new_data , func )
614
584
615
585
def _combine_const (self , other , func ):
616
586
return self ._apply_columns (lambda x : func (x , other ))
617
587
588
+ def _construct_result (self , other , result , func ):
589
+ """
590
+ Wrap the result of an arithmetic, comparison, or logical operation.
591
+
592
+ Parameters
593
+ ----------
594
+ other : object
595
+ result : SparseDataFrame
596
+ func : binary operator
597
+
598
+ Returns
599
+ -------
600
+ SparseDataFrame
601
+ """
602
+ fill_value = self ._get_op_result_fill_value (other , func )
603
+
604
+ out = self ._constructor (result , index = self .index , default_fill_value = fill_value )
605
+ out .columns = self .columns
606
+ return out .__finalize__ (self )
607
+
618
608
def _get_op_result_fill_value (self , other , func ):
619
609
own_default = self .default_fill_value
620
610
@@ -643,6 +633,11 @@ def _get_op_result_fill_value(self, other, func):
643
633
else :
644
634
fill_value = func (np .float64 (own_default ), np .float64 (other .fill_value ))
645
635
fill_value = item_from_zerodim (fill_value )
636
+
637
+ elif isinstance (other , Series ):
638
+ # reached via _combine_match_columns
639
+ fill_value = self .default_fill_value
640
+
646
641
else :
647
642
raise NotImplementedError (type (other ))
648
643
0 commit comments