@@ -1170,37 +1170,49 @@ def xs(self, key, axis=0, copy=True):
1170
1170
#----------------------------------------------------------------------
1171
1171
# Reindexing and alignment
1172
1172
1173
- def align (self , other , join = 'outer' , copy = True ):
1173
+ def align (self , other , join = 'outer' , axis = None , copy = True ):
1174
1174
"""
1175
1175
Align two DataFrame object on their index and columns with the specified
1176
1176
join method for each axis Index
1177
1177
1178
1178
Parameters
1179
1179
----------
1180
- other : DataFrame
1180
+ other : DataFrame or Series
1181
1181
join : {'outer', 'inner', 'left', 'right'}, default 'outer'
1182
+ axis : {0, 1, None}, default None
1183
+ Align on index (0), columns (1), or both (None)
1182
1184
1183
1185
Returns
1184
1186
-------
1185
1187
(left, right) : (Series, Series)
1186
1188
Aligned Series
1187
1189
"""
1188
- if self .index .equals (other .index ):
1189
- join_index = self .index
1190
- ilidx , iridx = None , None
1191
- else :
1192
- join_index , ilidx , iridx = self .index .join (other .index , how = join ,
1193
- return_indexers = True )
1194
-
1195
- if self .columns .equals (other .columns ):
1196
- join_columns = self .columns
1197
- clidx , cridx = None , None
1198
- else :
1199
- join_columns , clidx , cridx = self .columns .join (other .columns ,
1200
- how = join ,
1190
+ if isinstance (other , DataFrame ):
1191
+ return self ._align_frame (other , join = join , axis = axis , copy = copy )
1192
+ elif isinstance (other , Series ):
1193
+ return self ._align_series (other , join = join , axis = axis , copy = copy )
1194
+ else : # pragma: no cover
1195
+ raise TypeError ('unsupported type: %s' % type (other ))
1196
+
1197
+ def _align_frame (self , other , join = 'outer' , axis = None , copy = True ):
1198
+ # defaults
1199
+ join_index = self .index
1200
+ join_columns = self .columns
1201
+ ilidx , iridx = None , None
1202
+ clidx , cridx = None , None
1203
+
1204
+ if axis is None or axis == 0 :
1205
+ if not self .index .equals (other .index ):
1206
+ join_index , ilidx , iridx = self .index .join (other .index , how = join ,
1201
1207
return_indexers = True )
1202
1208
1203
- def _align_frame (frame , row_idx , col_idx ):
1209
+ if axis is None or axis == 1 :
1210
+ if not self .columns .equals (other .columns ):
1211
+ join_columns , clidx , cridx = self .columns .join (other .columns ,
1212
+ how = join ,
1213
+ return_indexers = True )
1214
+
1215
+ def _align (frame , row_idx , col_idx ):
1204
1216
new_data = frame ._data
1205
1217
if row_idx is not None :
1206
1218
new_data = new_data .reindex_indexer (join_index , row_idx , axis = 1 )
@@ -1214,10 +1226,40 @@ def _align_frame(frame, row_idx, col_idx):
1214
1226
1215
1227
return DataFrame (new_data )
1216
1228
1217
- left = _align_frame (self , ilidx , clidx )
1218
- right = _align_frame (other , iridx , cridx )
1229
+ left = _align (self , ilidx , clidx )
1230
+ right = _align (other , iridx , cridx )
1219
1231
return left , right
1220
1232
1233
+ def _align_series (self , other , join = 'outer' , axis = None , copy = True ):
1234
+ fdata = self ._data
1235
+ if axis == 0 :
1236
+ join_index = self .index
1237
+ lidx , ridx = None , None
1238
+ if not self .index .equals (other .index ):
1239
+ join_index , lidx , ridx = self .index .join (other .index , how = join ,
1240
+ return_indexers = True )
1241
+
1242
+ if lidx is not None :
1243
+ fdata = fdata .reindex_indexer (join_index , lidx , axis = 1 )
1244
+ elif axis == 1 :
1245
+ join_index = self .columns
1246
+ lidx , ridx = None , None
1247
+ if not self .columns .equals (other .index ):
1248
+ join_index , lidx , ridx = self .columns .join (other .index , how = join ,
1249
+ return_indexers = True )
1250
+
1251
+ if lidx is not None :
1252
+ fdata = fdata .reindex_items (join_index )
1253
+ else :
1254
+ raise ValueError ('Must specify axis=0 or 1' )
1255
+
1256
+ if copy and fdata is self ._data :
1257
+ fdata = fdata .copy ()
1258
+
1259
+ left_result = DataFrame (fdata )
1260
+ right_result = other if ridx is None else other .reindex (join_index )
1261
+ return left_result , right_result
1262
+
1221
1263
def reindex (self , index = None , columns = None , method = None , copy = True ):
1222
1264
"""Conform Series to new index with optional filling logic, placing
1223
1265
NA/NaN in locations having no value in the previous index. A new object
@@ -1776,35 +1818,21 @@ def _combine_series_infer(self, other, func, fill_value=None):
1776
1818
return self ._combine_match_columns (other , func , fill_value )
1777
1819
1778
1820
def _combine_match_index (self , other , func , fill_value = None ):
1779
- new_index = self .index .union (other .index )
1780
- values = self .values
1781
- other_vals = other .values
1782
-
1783
- # Operate row-wise
1784
- if not other .index .equals (new_index ):
1785
- other_vals = other .reindex (new_index ).values
1786
-
1787
- if not self .index .equals (new_index ):
1788
- values = self .reindex (new_index ).values
1789
-
1821
+ left , right = self .align (other , join = 'outer' , axis = 0 , copy = False )
1790
1822
if fill_value is not None :
1791
1823
raise NotImplementedError
1792
-
1793
- return self . _constructor ( func ( values . T , other_vals ). T , index = new_index ,
1824
+ return self . _constructor ( func ( left . values . T , right . values ). T ,
1825
+ index = left . index ,
1794
1826
columns = self .columns , copy = False )
1795
1827
1796
1828
def _combine_match_columns (self , other , func , fill_value = None ):
1797
- newCols = self .columns .union (other .index )
1798
-
1799
- # Operate column-wise
1800
- this = self .reindex (columns = newCols )
1801
- other = other .reindex (newCols ).values
1802
-
1829
+ left , right = self .align (other , join = 'outer' , axis = 1 , copy = False )
1803
1830
if fill_value is not None :
1804
1831
raise NotImplementedError
1805
1832
1806
- return self ._constructor (func (this .values , other ), index = self .index ,
1807
- columns = newCols , copy = False )
1833
+ return self ._constructor (func (left .values , right .values ),
1834
+ index = self .index ,
1835
+ columns = left .columns , copy = False )
1808
1836
1809
1837
def _combine_const (self , other , func ):
1810
1838
if not self :
@@ -1847,13 +1875,8 @@ def combine(self, other, func, fill_value=None):
1847
1875
if not self :
1848
1876
return other .copy ()
1849
1877
1850
- new_index = self .index
1851
- this = self
1852
-
1853
- if not self .index .equals (other .index ):
1854
- new_index = self .index + other .index
1855
- this = self .reindex (new_index )
1856
- other = other .reindex (new_index )
1878
+ this , other = self .align (other , axis = 0 , copy = False )
1879
+ new_index = this .index
1857
1880
1858
1881
# sorts if possible
1859
1882
new_columns = this .columns .union (other .columns )
0 commit comments