54
54
)
55
55
56
56
if TYPE_CHECKING :
57
- from pandas import DataFrame # noqa:F401
57
+ from pandas import DataFrame , Series # noqa:F401
58
58
59
59
# -----------------------------------------------------------------------------
60
60
# constants
@@ -459,19 +459,7 @@ def _combine_series_frame(left, right, func, axis: int):
459
459
# We assume that self.align(other, ...) has already been called
460
460
461
461
rvalues = right ._values
462
- if isinstance (rvalues , np .ndarray ):
463
- # TODO(EA2D): no need to special-case with 2D EAs
464
- # We can operate block-wise
465
- if axis == 0 :
466
- rvalues = rvalues .reshape (- 1 , 1 )
467
- else :
468
- rvalues = rvalues .reshape (1 , - 1 )
469
-
470
- rvalues = np .broadcast_to (rvalues , left .shape )
471
-
472
- array_op = get_array_op (func )
473
- bm = left ._mgr .apply (array_op , right = rvalues .T , align_keys = ["right" ])
474
- return type (left )(bm )
462
+ assert not isinstance (rvalues , np .ndarray ) # handled by align_series_as_frame
475
463
476
464
if axis == 0 :
477
465
new_data = dispatch_to_series (left , right , func )
@@ -567,6 +555,7 @@ def to_series(right):
567
555
left , right = left .align (
568
556
right , join = "outer" , axis = axis , level = level , copy = False
569
557
)
558
+ right = _maybe_align_series_as_frame (left , right , axis )
570
559
571
560
return left , right
572
561
@@ -627,6 +616,25 @@ def _frame_arith_method_with_reindex(
627
616
return result .reindex (join_columns , axis = 1 )
628
617
629
618
619
+ def _maybe_align_series_as_frame (frame : "DataFrame" , series : "Series" , axis : int ):
620
+ """
621
+ If the Series operand is not EA-dtype, we can broadcast to 2D and operate
622
+ blockwise.
623
+ """
624
+ rvalues = series ._values
625
+ if not isinstance (rvalues , np .ndarray ):
626
+ # TODO(EA2D): no need to special-case with 2D EAs
627
+ return series
628
+
629
+ if axis == 0 :
630
+ rvalues = rvalues .reshape (- 1 , 1 )
631
+ else :
632
+ rvalues = rvalues .reshape (1 , - 1 )
633
+
634
+ rvalues = np .broadcast_to (rvalues , frame .shape )
635
+ return type (frame )(rvalues , index = frame .index , columns = frame .columns )
636
+
637
+
630
638
def _arith_method_FRAME (cls : Type ["DataFrame" ], op , special : bool ):
631
639
# This is the only function where `special` can be either True or False
632
640
op_name = _get_op_name (op , special )
@@ -648,6 +656,11 @@ def f(self, other, axis=default_axis, level=None, fill_value=None):
648
656
):
649
657
return _frame_arith_method_with_reindex (self , other , op )
650
658
659
+ if isinstance (other , ABCSeries ) and fill_value is not None :
660
+ # TODO: We could allow this in cases where we end up going
661
+ # through the DataFrame path
662
+ raise NotImplementedError (f"fill_value { fill_value } not supported." )
663
+
651
664
# TODO: why are we passing flex=True instead of flex=not special?
652
665
# 15 tests fail if we pass flex=not special instead
653
666
self , other = _align_method_FRAME (self , other , axis , flex = True , level = level )
@@ -657,9 +670,6 @@ def f(self, other, axis=default_axis, level=None, fill_value=None):
657
670
new_data = self ._combine_frame (other , na_op , fill_value )
658
671
659
672
elif isinstance (other , ABCSeries ):
660
- if fill_value is not None :
661
- raise NotImplementedError (f"fill_value { fill_value } not supported." )
662
-
663
673
axis = self ._get_axis_number (axis ) if axis is not None else 1
664
674
new_data = _combine_series_frame (self , other , op , axis = axis )
665
675
else :
0 commit comments