5
5
"""
6
6
import datetime
7
7
import operator
8
- from typing import Optional , Set , Tuple , Union
8
+ from typing import TYPE_CHECKING , Optional , Set , Tuple , Union
9
9
10
10
import numpy as np
11
11
61
61
rxor ,
62
62
)
63
63
64
+ if TYPE_CHECKING :
65
+ from pandas import DataFrame # noqa:F401
66
+
64
67
# -----------------------------------------------------------------------------
65
68
# constants
66
69
ARITHMETIC_BINOPS : Set [str ] = {
@@ -703,6 +706,58 @@ def to_series(right):
703
706
return left , right
704
707
705
708
709
+ def _should_reindex_frame_op (
710
+ left : "DataFrame" , right , axis , default_axis : int , fill_value , level
711
+ ) -> bool :
712
+ """
713
+ Check if this is an operation between DataFrames that will need to reindex.
714
+ """
715
+ assert isinstance (left , ABCDataFrame )
716
+
717
+ if not isinstance (right , ABCDataFrame ):
718
+ return False
719
+
720
+ if fill_value is None and level is None and axis is default_axis :
721
+ # TODO: any other cases we should handle here?
722
+ cols = left .columns .intersection (right .columns )
723
+ if not (cols .equals (left .columns ) and cols .equals (right .columns )):
724
+ return True
725
+
726
+ return False
727
+
728
+
729
+ def _frame_arith_method_with_reindex (
730
+ left : "DataFrame" , right : "DataFrame" , op
731
+ ) -> "DataFrame" :
732
+ """
733
+ For DataFrame-with-DataFrame operations that require reindexing,
734
+ operate only on shared columns, then reindex.
735
+
736
+ Parameters
737
+ ----------
738
+ left : DataFrame
739
+ right : DataFrame
740
+ op : binary operator
741
+
742
+ Returns
743
+ -------
744
+ DataFrame
745
+ """
746
+ # GH#31623, only operate on shared columns
747
+ cols = left .columns .intersection (right .columns )
748
+
749
+ new_left = left [cols ]
750
+ new_right = right [cols ]
751
+ result = op (new_left , new_right )
752
+
753
+ # Do the join on the columns instead of using _align_method_FRAME
754
+ # to avoid constructing two potentially large/sparse DataFrames
755
+ join_columns , _ , _ = left .columns .join (
756
+ right .columns , how = "outer" , level = None , return_indexers = True
757
+ )
758
+ return result .reindex (join_columns , axis = 1 )
759
+
760
+
706
761
def _arith_method_FRAME (cls , op , special ):
707
762
str_rep = _get_opstr (op )
708
763
op_name = _get_op_name (op , special )
@@ -720,6 +775,9 @@ def _arith_method_FRAME(cls, op, special):
720
775
@Appender (doc )
721
776
def f (self , other , axis = default_axis , level = None , fill_value = None ):
722
777
778
+ if _should_reindex_frame_op (self , other , axis , default_axis , fill_value , level ):
779
+ return _frame_arith_method_with_reindex (self , other , op )
780
+
723
781
self , other = _align_method_FRAME (self , other , axis , flex = True , level = level )
724
782
725
783
if isinstance (other , ABCDataFrame ):
0 commit comments