@@ -1295,12 +1295,13 @@ def _align_frame(self, other, join='outer', axis=None, level=None,
1295
1295
if axis is None or axis == 0 :
1296
1296
if not self .index .equals (other .index ):
1297
1297
join_index , ilidx , iridx = \
1298
- self .index .join (other .index , how = join , return_indexers = True )
1298
+ self .index .join (other .index , how = join , level = level ,
1299
+ return_indexers = True )
1299
1300
1300
1301
if axis is None or axis == 1 :
1301
1302
if not self .columns .equals (other .columns ):
1302
1303
join_columns , clidx , cridx = \
1303
- self .columns .join (other .columns , how = join ,
1304
+ self .columns .join (other .columns , how = join , level = level ,
1304
1305
return_indexers = True )
1305
1306
1306
1307
def _align (frame , row_idx , col_idx ):
@@ -1310,7 +1311,8 @@ def _align(frame, row_idx, col_idx):
1310
1311
1311
1312
if col_idx is not None :
1312
1313
# TODO: speed up on homogeneous DataFrame objects
1313
- new_data = new_data .reindex_items (join_columns )
1314
+ new_data = new_data .reindex_indexer (join_columns , col_idx ,
1315
+ axis = 0 )
1314
1316
1315
1317
if copy and new_data is frame ._data :
1316
1318
new_data = new_data .copy ()
@@ -1321,6 +1323,15 @@ def _align(frame, row_idx, col_idx):
1321
1323
right = _align (other , iridx , cridx )
1322
1324
return left , right
1323
1325
1326
+ def _align_level (self , multi_index , level , axis = 0 , copy = True ):
1327
+ levnum = multi_index ._get_level_number (level )
1328
+ data = self .reindex_axis (multi_index .levels [levnum ], axis = axis ,
1329
+ copy = False )._data
1330
+ mgr_axis = 0 if axis == 1 else 1
1331
+ new_data = data .reindex_indexer (multi_index , multi_index .labels [levnum ],
1332
+ axis = mgr_axis )
1333
+ return DataFrame (new_data )
1334
+
1324
1335
def _align_series (self , other , join = 'outer' , axis = None , level = None ,
1325
1336
copy = True ):
1326
1337
fdata = self ._data
@@ -1337,11 +1348,12 @@ def _align_series(self, other, join='outer', axis=None, level=None,
1337
1348
join_index = self .columns
1338
1349
lidx , ridx = None , None
1339
1350
if not self .columns .equals (other .index ):
1340
- join_index , lidx , ridx = self .columns .join (other .index , how = join ,
1341
- return_indexers = True )
1351
+ join_index , lidx , ridx = \
1352
+ self .columns .join (other .index , how = join ,
1353
+ return_indexers = True )
1342
1354
1343
1355
if lidx is not None :
1344
- fdata = fdata .reindex_items (join_index )
1356
+ fdata = fdata .reindex_indexer (join_index , lidx , axis = 0 )
1345
1357
else :
1346
1358
raise ValueError ('Must specify axis=0 or 1' )
1347
1359
@@ -1354,7 +1366,7 @@ def _align_series(self, other, join='outer', axis=None, level=None,
1354
1366
1355
1367
def reindex (self , index = None , columns = None , method = None , level = None ,
1356
1368
copy = True ):
1357
- """Conform Series to new index with optional filling logic, placing
1369
+ """Conform DataFrame to new index with optional filling logic, placing
1358
1370
NA/NaN in locations having no value in the previous index. A new object
1359
1371
is produced unless the new index is equivalent to the current one and
1360
1372
copy=False
@@ -1385,33 +1397,65 @@ def reindex(self, index=None, columns=None, method=None, level=None,
1385
1397
frame = self
1386
1398
1387
1399
if index is not None :
1388
- index = _ensure_index (index )
1389
1400
frame = frame ._reindex_index (index , method , copy , level )
1390
1401
1391
1402
if columns is not None :
1392
- columns = _ensure_index (columns )
1393
1403
frame = frame ._reindex_columns (columns , copy , level )
1394
1404
1395
1405
return frame
1396
1406
1407
+ def reindex_axis (self , labels , axis = 0 , method = None , level = None , copy = True ):
1408
+ """Conform DataFrame to new index with optional filling logic, placing
1409
+ NA/NaN in locations having no value in the previous index. A new object
1410
+ is produced unless the new index is equivalent to the current one and
1411
+ copy=False
1412
+
1413
+ Parameters
1414
+ ----------
1415
+ index : array-like, optional
1416
+ New labels / index to conform to. Preferably an Index object to
1417
+ avoid duplicating data
1418
+ axis : {0, 1}
1419
+ 0 -> index (rows)
1420
+ 1 -> columns
1421
+ method : {'backfill', 'bfill', 'pad', 'ffill', None}, default None
1422
+ Method to use for filling holes in reindexed DataFrame
1423
+ pad / ffill: propagate last valid observation forward to next valid
1424
+ backfill / bfill: use NEXT valid observation to fill gap
1425
+ copy : boolean, default True
1426
+ Return a new object, even if the passed indexes are the same
1427
+
1428
+ Examples
1429
+ --------
1430
+ >>> df.reindex(['A', 'B', 'C'], axis=1)
1431
+
1432
+ See also
1433
+ --------
1434
+ DataFrame.reindex, DataFrame.reindex_like
1435
+
1436
+ Returns
1437
+ -------
1438
+ reindexed : same type as calling instance
1439
+ """
1440
+ self ._consolidate_inplace ()
1441
+ if axis == 0 :
1442
+ return self ._reindex_index (labels , method , copy , level )
1443
+ elif axis == 1 :
1444
+ return self ._reindex_columns (labels , copy , level )
1445
+ else : # pragma: no cover
1446
+ raise ValueError ('Must specify axis=0 or 1' )
1447
+
1397
1448
def _reindex_index (self , new_index , method , copy , level ):
1398
- if new_index .equals (self .index ):
1399
- if copy :
1400
- result = self .copy ()
1401
- result .index = new_index
1402
- return result
1403
- else :
1404
- return self
1405
- new_data = self ._data .reindex_axis (new_index , method , axis = 1 )
1449
+ if level is not None :
1450
+ return self ._align_level (new_index , level , axis = 0 , copy = copy )
1451
+ new_data = self ._data .reindex_axis (new_index , method , axis = 1 ,
1452
+ copy = copy )
1406
1453
return self ._constructor (new_data )
1407
1454
1408
- def _reindex_columns (self , new_columns , copy ):
1409
- if new_columns .equals (self .columns ):
1410
- if copy :
1411
- return self .copy ()
1412
- else :
1413
- return self
1414
- new_data = self ._data .reindex_axis (new_columns , axis = 0 )
1455
+ def _reindex_columns (self , new_columns , copy , level ):
1456
+ if level is not None :
1457
+ return self ._align_level (new_columns , level , axis = 1 , copy = copy )
1458
+ new_data = self ._data .reindex_axis (new_columns , axis = 0 , copy = copy )
1415
1459
return self ._constructor (new_data )
1416
1460
1417
1461
def reindex_like (self , other , method = None , copy = True ):
@@ -1948,7 +1992,8 @@ def _indexed_same(self, other):
1948
1992
same_columns = self .columns .equals (other .columns )
1949
1993
return same_index and same_columns
1950
1994
1951
- def _combine_series (self , other , func , fill_value = None , axis = None ):
1995
+ def _combine_series (self , other , func , fill_value = None , axis = None ,
1996
+ level = None ):
1952
1997
if axis is not None :
1953
1998
axis = self ._get_axis_name (axis )
1954
1999
if axis == 'index' :
@@ -3659,16 +3704,6 @@ def _is_sequence(x):
3659
3704
except Exception :
3660
3705
return False
3661
3706
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
-
3672
3707
def install_ipython_completers (): # pragma: no cover
3673
3708
"""Register the DataFrame type with IPython's tab completion machinery, so
3674
3709
that it knows about accessing column names as attributes."""
0 commit comments