55"""
66import datetime
77import operator
8- from typing import Optional , Set , Tuple , Union
8+ from typing import TYPE_CHECKING , Optional , Set , Tuple , Union
99
1010import numpy as np
1111
6161 rxor ,
6262)
6363
64+ if TYPE_CHECKING :
65+ from pandas import DataFrame # noqa:F401
66+
6467# -----------------------------------------------------------------------------
6568# constants
6669ARITHMETIC_BINOPS : Set [str ] = {
@@ -703,6 +706,58 @@ def to_series(right):
703706 return left , right
704707
705708
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+
706761def _arith_method_FRAME (cls , op , special ):
707762 str_rep = _get_opstr (op )
708763 op_name = _get_op_name (op , special )
@@ -720,6 +775,9 @@ def _arith_method_FRAME(cls, op, special):
720775 @Appender (doc )
721776 def f (self , other , axis = default_axis , level = None , fill_value = None ):
722777
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+
723781 self , other = _align_method_FRAME (self , other , axis , flex = True , level = level )
724782
725783 if isinstance (other , ABCDataFrame ):
0 commit comments