@@ -575,13 +575,24 @@ class PandasIndex(Index):
575
575
576
576
__slots__ = ("index" , "dim" , "coord_dtype" )
577
577
578
- def __init__ (self , array : Any , dim : Hashable , coord_dtype : Any = None ):
579
- # make a shallow copy: cheap and because the index name may be updated
580
- # here or in other constructors (cannot use pd.Index.rename as this
581
- # constructor is also called from PandasMultiIndex)
582
- index = safe_cast_to_index (array ).copy ()
578
+ def __init__ (
579
+ self ,
580
+ array : Any ,
581
+ dim : Hashable ,
582
+ coord_dtype : Any = None ,
583
+ * ,
584
+ fastpath : bool = False ,
585
+ ):
586
+ if fastpath :
587
+ index = array
588
+ else :
589
+ index = safe_cast_to_index (array )
583
590
584
591
if index .name is None :
592
+ # make a shallow copy: cheap and because the index name may be updated
593
+ # here or in other constructors (cannot use pd.Index.rename as this
594
+ # constructor is also called from PandasMultiIndex)
595
+ index = index .copy ()
585
596
index .name = dim
586
597
587
598
self .index = index
@@ -596,7 +607,7 @@ def _replace(self, index, dim=None, coord_dtype=None):
596
607
dim = self .dim
597
608
if coord_dtype is None :
598
609
coord_dtype = self .coord_dtype
599
- return type (self )(index , dim , coord_dtype )
610
+ return type (self )(index , dim , coord_dtype , fastpath = True )
600
611
601
612
@classmethod
602
613
def from_variables (
@@ -642,6 +653,11 @@ def from_variables(
642
653
643
654
obj = cls (data , dim , coord_dtype = var .dtype )
644
655
assert not isinstance (obj .index , pd .MultiIndex )
656
+ # Rename safely
657
+ # make a shallow copy: cheap and because the index name may be updated
658
+ # here or in other constructors (cannot use pd.Index.rename as this
659
+ # constructor is also called from PandasMultiIndex)
660
+ obj .index = obj .index .copy ()
645
661
obj .index .name = name
646
662
647
663
return obj
@@ -1773,6 +1789,36 @@ def check_variables():
1773
1789
return not not_equal
1774
1790
1775
1791
1792
+ def _apply_indexes_fast (indexes : Indexes [Index ], args : Mapping [Any , Any ], func : str ):
1793
+ # This function avoids the call to indexes.group_by_index
1794
+ # which is really slow when repeatidly iterating through
1795
+ # an array. However, it fails to return the correct ID for
1796
+ # multi-index arrays
1797
+ indexes_fast , coords = indexes ._indexes , indexes ._variables
1798
+
1799
+ new_indexes : dict [Hashable , Index ] = {k : v for k , v in indexes_fast .items ()}
1800
+ new_index_variables : dict [Hashable , Variable ] = {}
1801
+ for name , index in indexes_fast .items ():
1802
+ coord = coords [name ]
1803
+ if hasattr (coord , "_indexes" ):
1804
+ index_vars = {n : coords [n ] for n in coord ._indexes }
1805
+ else :
1806
+ index_vars = {name : coord }
1807
+ index_dims = {d for var in index_vars .values () for d in var .dims }
1808
+ index_args = {k : v for k , v in args .items () if k in index_dims }
1809
+
1810
+ if index_args :
1811
+ new_index = getattr (index , func )(index_args )
1812
+ if new_index is not None :
1813
+ new_indexes .update ({k : new_index for k in index_vars })
1814
+ new_index_vars = new_index .create_variables (index_vars )
1815
+ new_index_variables .update (new_index_vars )
1816
+ else :
1817
+ for k in index_vars :
1818
+ new_indexes .pop (k , None )
1819
+ return new_indexes , new_index_variables
1820
+
1821
+
1776
1822
def _apply_indexes (
1777
1823
indexes : Indexes [Index ],
1778
1824
args : Mapping [Any , Any ],
@@ -1801,7 +1847,13 @@ def isel_indexes(
1801
1847
indexes : Indexes [Index ],
1802
1848
indexers : Mapping [Any , Any ],
1803
1849
) -> tuple [dict [Hashable , Index ], dict [Hashable , Variable ]]:
1804
- return _apply_indexes (indexes , indexers , "isel" )
1850
+ # TODO: remove if clause in the future. It should be unnecessary.
1851
+ # See failure introduced when removed
1852
+ # https://github.com/pydata/xarray/pull/9002#discussion_r1590443756
1853
+ if any (isinstance (v , PandasMultiIndex ) for v in indexes ._indexes .values ()):
1854
+ return _apply_indexes (indexes , indexers , "isel" )
1855
+ else :
1856
+ return _apply_indexes_fast (indexes , indexers , "isel" )
1805
1857
1806
1858
1807
1859
def roll_indexes (
0 commit comments