@@ -100,11 +100,11 @@ def _add_stat_doc(f, name, shortname, na_action=_doc_exclude_na,
100
100
f .__doc__ = doc
101
101
102
102
def _arith_method (func , name , default_axis = 'columns' ):
103
- def f (self , other , axis = default_axis , fill_value = None ):
103
+ def f (self , other , axis = default_axis , level = None , fill_value = None ):
104
104
if isinstance (other , DataFrame ): # Another DataFrame
105
- return self ._combine_frame (other , func , fill_value )
105
+ return self ._combine_frame (other , func , fill_value , level )
106
106
elif isinstance (other , Series ):
107
- return self ._combine_series (other , func , fill_value , axis )
107
+ return self ._combine_series (other , func , fill_value , axis , level )
108
108
else :
109
109
return self ._combine_const (other , func )
110
110
@@ -1258,7 +1258,7 @@ def xs(self, key, axis=0, copy=True):
1258
1258
#----------------------------------------------------------------------
1259
1259
# Reindexing and alignment
1260
1260
1261
- def align (self , other , join = 'outer' , axis = None , copy = True ):
1261
+ def align (self , other , join = 'outer' , axis = None , level = None , copy = True ):
1262
1262
"""
1263
1263
Align two DataFrame object on their index and columns with the specified
1264
1264
join method for each axis Index
@@ -1276,13 +1276,16 @@ def align(self, other, join='outer', axis=None, copy=True):
1276
1276
Aligned Series
1277
1277
"""
1278
1278
if isinstance (other , DataFrame ):
1279
- return self ._align_frame (other , join = join , axis = axis , copy = copy )
1279
+ return self ._align_frame (other , join = join , axis = axis , level = level ,
1280
+ copy = copy )
1280
1281
elif isinstance (other , Series ):
1281
- return self ._align_series (other , join = join , axis = axis , copy = copy )
1282
+ return self ._align_series (other , join = join , axis = axis , level = level ,
1283
+ copy = copy )
1282
1284
else : # pragma: no cover
1283
1285
raise TypeError ('unsupported type: %s' % type (other ))
1284
1286
1285
- def _align_frame (self , other , join = 'outer' , axis = None , copy = True ):
1287
+ def _align_frame (self , other , join = 'outer' , axis = None , level = None ,
1288
+ copy = True ):
1286
1289
# defaults
1287
1290
join_index = self .index
1288
1291
join_columns = self .columns
@@ -1291,14 +1294,14 @@ def _align_frame(self, other, join='outer', axis=None, copy=True):
1291
1294
1292
1295
if axis is None or axis == 0 :
1293
1296
if not self .index .equals (other .index ):
1294
- join_index , ilidx , iridx = self . index . join ( other . index , how = join ,
1295
- return_indexers = True )
1297
+ join_index , ilidx , iridx = \
1298
+ self . index . join ( other . index , how = join , return_indexers = True )
1296
1299
1297
1300
if axis is None or axis == 1 :
1298
1301
if not self .columns .equals (other .columns ):
1299
- join_columns , clidx , cridx = self . columns . join ( other . columns ,
1300
- how = join ,
1301
- return_indexers = True )
1302
+ join_columns , clidx , cridx = \
1303
+ self . columns . join ( other . columns , how = join ,
1304
+ return_indexers = True )
1302
1305
1303
1306
def _align (frame , row_idx , col_idx ):
1304
1307
new_data = frame ._data
@@ -1318,7 +1321,8 @@ def _align(frame, row_idx, col_idx):
1318
1321
right = _align (other , iridx , cridx )
1319
1322
return left , right
1320
1323
1321
- def _align_series (self , other , join = 'outer' , axis = None , copy = True ):
1324
+ def _align_series (self , other , join = 'outer' , axis = None , level = None ,
1325
+ copy = True ):
1322
1326
fdata = self ._data
1323
1327
if axis == 0 :
1324
1328
join_index = self .index
@@ -1348,7 +1352,8 @@ def _align_series(self, other, join='outer', axis=None, copy=True):
1348
1352
right_result = other if ridx is None else other .reindex (join_index )
1349
1353
return left_result , right_result
1350
1354
1351
- def reindex (self , index = None , columns = None , method = None , copy = True ):
1355
+ def reindex (self , index = None , columns = None , method = None , level = None ,
1356
+ copy = True ):
1352
1357
"""Conform Series to new index with optional filling logic, placing
1353
1358
NA/NaN in locations having no value in the previous index. A new object
1354
1359
is produced unless the new index is equivalent to the current one and
@@ -1381,15 +1386,15 @@ def reindex(self, index=None, columns=None, method=None, copy=True):
1381
1386
1382
1387
if index is not None :
1383
1388
index = _ensure_index (index )
1384
- frame = frame ._reindex_index (index , method , copy )
1389
+ frame = frame ._reindex_index (index , method , copy , level )
1385
1390
1386
1391
if columns is not None :
1387
1392
columns = _ensure_index (columns )
1388
- frame = frame ._reindex_columns (columns , copy )
1393
+ frame = frame ._reindex_columns (columns , copy , level )
1389
1394
1390
1395
return frame
1391
1396
1392
- def _reindex_index (self , new_index , method , copy ):
1397
+ def _reindex_index (self , new_index , method , copy , level ):
1393
1398
if new_index .equals (self .index ):
1394
1399
if copy :
1395
1400
result = self .copy ()
@@ -1916,8 +1921,8 @@ def _rename_columns_inplace(self, mapper):
1916
1921
#----------------------------------------------------------------------
1917
1922
# Arithmetic / combination related
1918
1923
1919
- def _combine_frame (self , other , func , fill_value = None ):
1920
- this , other = self .align (other , join = 'outer' , copy = False )
1924
+ def _combine_frame (self , other , func , fill_value = None , level = None ):
1925
+ this , other = self .align (other , join = 'outer' , level = level , copy = False )
1921
1926
new_index , new_columns = this .index , this .columns
1922
1927
1923
1928
this_vals = this .values
@@ -3654,6 +3659,16 @@ def _is_sequence(x):
3654
3659
except Exception :
3655
3660
return False
3656
3661
3662
+ def _align_level (frame , multi_index , level , axis = 0 ):
3663
+ levnum = multi_index ._get_level_number (level )
3664
+
3665
+ data = frame .reindex (multi_index .levels [levnum ], copy = False )._data
3666
+
3667
+ mgr_axis = 0 if axis == 1 else 1
3668
+ new_data = data .reindex_indexer (multi_index , multi_index .labels [levnum ],
3669
+ axis = mgr_axis )
3670
+ return DataFrame (new_data )
3671
+
3657
3672
def install_ipython_completers (): # pragma: no cover
3658
3673
"""Register the DataFrame type with IPython's tab completion machinery, so
3659
3674
that it knows about accessing column names as attributes."""
0 commit comments