From 95c1ef722e0a11f4af33ef9172947d4cf7ed1ebb Mon Sep 17 00:00:00 2001 From: Mark Harfouche Date: Sun, 19 May 2024 11:55:29 -0400 Subject: [PATCH 01/18] conda instead of mamba --- asv_bench/asv.conf.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asv_bench/asv.conf.json b/asv_bench/asv.conf.json index 9dc86df712d..4c717b7dcc4 100644 --- a/asv_bench/asv.conf.json +++ b/asv_bench/asv.conf.json @@ -29,7 +29,7 @@ // If missing or the empty string, the tool will be automatically // determined by looking for tools on the PATH environment // variable. - "environment_type": "mamba", + "environment_type": "conda", "conda_channels": ["conda-forge"], // timeout in seconds for installing any dependencies in environment From 53c06036769f79c95481c7c5f7851e3f26d08fe7 Mon Sep 17 00:00:00 2001 From: Mark Harfouche Date: Sat, 18 May 2024 14:56:37 -0400 Subject: [PATCH 02/18] Make speedups using fastpath --- xarray/core/indexes.py | 38 ++++++++++++++++++++++++++++---------- xarray/core/indexing.py | 39 ++++++++++++++++++++++++++------------- xarray/core/variable.py | 2 +- 3 files changed, 55 insertions(+), 24 deletions(-) diff --git a/xarray/core/indexes.py b/xarray/core/indexes.py index a005e1ebfe2..635fc7fdfbb 100644 --- a/xarray/core/indexes.py +++ b/xarray/core/indexes.py @@ -161,7 +161,10 @@ def unstack(self) -> tuple[dict[Hashable, Index], pd.MultiIndex]: raise NotImplementedError() def create_variables( - self, variables: Mapping[Any, Variable] | None = None + self, + variables: Mapping[Any, Variable] | None = None, + *, + fastpath: bool = False, ) -> IndexVars: """Maybe create new coordinate variables from this index. @@ -575,13 +578,24 @@ class PandasIndex(Index): __slots__ = ("index", "dim", "coord_dtype") - def __init__(self, array: Any, dim: Hashable, coord_dtype: Any = None): - # make a shallow copy: cheap and because the index name may be updated - # here or in other constructors (cannot use pd.Index.rename as this - # constructor is also called from PandasMultiIndex) - index = safe_cast_to_index(array).copy() + def __init__( + self, + array: Any, + dim: Hashable, + coord_dtype: Any = None, + *, + fastpath: bool = False, + ): + if fastpath: + index = array + else: + index = safe_cast_to_index(array) if index.name is None: + # make a shallow copy: cheap and because the index name may be updated + # here or in other constructors (cannot use pd.Index.rename as this + # constructor is also called from PandasMultiIndex) + index = index.copy() index.name = dim self.index = index @@ -596,7 +610,7 @@ def _replace(self, index, dim=None, coord_dtype=None): dim = self.dim if coord_dtype is None: coord_dtype = self.coord_dtype - return type(self)(index, dim, coord_dtype) + return type(self)(index, dim, coord_dtype, fastpath=True) @classmethod def from_variables( @@ -642,6 +656,8 @@ def from_variables( obj = cls(data, dim, coord_dtype=var.dtype) assert not isinstance(obj.index, pd.MultiIndex) + # Rename safely + obj.index = obj.index.copy() obj.index.name = name return obj @@ -685,7 +701,7 @@ def concat( return cls(new_pd_index, dim=dim, coord_dtype=coord_dtype) def create_variables( - self, variables: Mapping[Any, Variable] | None = None + self, variables: Mapping[Any, Variable] | None = None, *, fastpath: bool = False ) -> IndexVars: from xarray.core.variable import IndexVariable @@ -702,7 +718,9 @@ def create_variables( encoding = None data = PandasIndexingAdapter(self.index, dtype=self.coord_dtype) - var = IndexVariable(self.dim, data, attrs=attrs, encoding=encoding) + var = IndexVariable( + self.dim, data, attrs=attrs, encoding=encoding, fastpath=fastpath + ) return {name: var} def to_pandas_index(self) -> pd.Index: @@ -1123,7 +1141,7 @@ def reorder_levels( return self._replace(index, level_coords_dtype=level_coords_dtype) def create_variables( - self, variables: Mapping[Any, Variable] | None = None + self, variables: Mapping[Any, Variable] | None = None, *, fastpath: bool = False ) -> IndexVars: from xarray.core.variable import IndexVariable diff --git a/xarray/core/indexing.py b/xarray/core/indexing.py index 0926da6fd80..e29d77da2c4 100644 --- a/xarray/core/indexing.py +++ b/xarray/core/indexing.py @@ -296,15 +296,16 @@ def slice_slice(old_slice: slice, applied_slice: slice, size: int) -> slice: def _index_indexer_1d(old_indexer, applied_indexer, size: int): - assert isinstance(applied_indexer, integer_types + (slice, np.ndarray)) if isinstance(applied_indexer, slice) and applied_indexer == slice(None): # shortcut for the usual case return old_indexer if isinstance(old_indexer, slice): if isinstance(applied_indexer, slice): indexer = slice_slice(old_indexer, applied_indexer, size) + elif isinstance(applied_indexer, integer_types): + indexer = range(*old_indexer.indices(size))[applied_indexer] # type: ignore[assignment] else: - indexer = _expand_slice(old_indexer, size)[applied_indexer] # type: ignore[assignment] + indexer = _expand_slice(old_indexer, size)[applied_indexer] else: indexer = old_indexer[applied_indexer] return indexer @@ -383,7 +384,12 @@ class BasicIndexer(ExplicitIndexer): __slots__ = () - def __init__(self, key: tuple[int | np.integer | slice, ...]): + def __init__( + self, key: tuple[int | np.integer | slice, ...], *, fastpath: bool = False + ): + if fastpath: + super().__init__(key) + return if not isinstance(key, tuple): raise TypeError(f"key must be a tuple: {key!r}") @@ -591,7 +597,7 @@ def __getitem__(self, key: Any): class LazilyIndexedArray(ExplicitlyIndexedNDArrayMixin): """Wrap an array to make basic and outer indexing lazy.""" - __slots__ = ("array", "key") + __slots__ = ("array", "key", "_shape") def __init__(self, array: Any, key: ExplicitIndexer | None = None): """ @@ -614,6 +620,14 @@ def __init__(self, array: Any, key: ExplicitIndexer | None = None): self.array = as_indexable(array) self.key = key + shape: _Shape = () + for size, k in zip(self.array.shape, self.key.tuple): + if isinstance(k, slice): + shape += (len(range(*k.indices(size))),) + elif isinstance(k, np.ndarray): + shape += (k.size,) + self._shape = shape + def _updated_key(self, new_key: ExplicitIndexer) -> BasicIndexer | OuterIndexer: iter_new_key = iter(expanded_indexer(new_key.tuple, self.ndim)) full_key = [] @@ -630,13 +644,7 @@ def _updated_key(self, new_key: ExplicitIndexer) -> BasicIndexer | OuterIndexer: @property def shape(self) -> _Shape: - shape = [] - for size, k in zip(self.array.shape, self.key.tuple): - if isinstance(k, slice): - shape.append(len(range(*k.indices(size)))) - elif isinstance(k, np.ndarray): - shape.append(k.size) - return tuple(shape) + return self._shape def get_duck_array(self): if isinstance(self.array, ExplicitlyIndexedNDArrayMixin): @@ -1653,10 +1661,15 @@ class PandasIndexingAdapter(ExplicitlyIndexedNDArrayMixin): __slots__ = ("array", "_dtype") - def __init__(self, array: pd.Index, dtype: DTypeLike = None): + def __init__( + self, array: pd.Index, dtype: DTypeLike = None, *, fastpath: bool = False + ): from xarray.core.indexes import safe_cast_to_index - self.array = safe_cast_to_index(array) + if fastpath: + self.array = array + else: + self.array = safe_cast_to_index(array) if dtype is None: self._dtype = get_valid_numpy_dtype(array) diff --git a/xarray/core/variable.py b/xarray/core/variable.py index f0685882595..d4a05785de7 100644 --- a/xarray/core/variable.py +++ b/xarray/core/variable.py @@ -660,7 +660,7 @@ def _broadcast_indexes_basic(self, key): dims = tuple( dim for k, dim in zip(key, self.dims) if not isinstance(k, integer_types) ) - return dims, BasicIndexer(key), None + return dims, BasicIndexer(key, fastpath=True), None def _validate_indexers(self, key): """Make sanity checks""" From 9d50a39e2a3e890c3785c9ef637c7077c332d896 Mon Sep 17 00:00:00 2001 From: Mark Harfouche Date: Sat, 18 May 2024 14:57:10 -0400 Subject: [PATCH 03/18] Change core logic to apply_indexes_fast --- xarray/core/indexes.py | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/xarray/core/indexes.py b/xarray/core/indexes.py index 635fc7fdfbb..2b92edfac35 100644 --- a/xarray/core/indexes.py +++ b/xarray/core/indexes.py @@ -1791,6 +1791,37 @@ def check_variables(): return not not_equal +def _apply_indexes_fast(indexes: Indexes[Index], args: Mapping[Any, Any], func: str): + # This function avoids the call to indexes.group_by_index + # which is really slow when repeatidly iterating through + # an array. However, it fails to return the correct ID for + # multi-index arrays + indexes_fast, coords = indexes._indexes, indexes._variables + + new_indexes: dict[Hashable, Index] = {k: v for k, v in indexes_fast.items()} + new_index_variables: dict[Hashable, Variable] = {} + for name, index in indexes_fast.items(): + coord = coords[name] + if hasattr(coord, "_indexes"): + index_vars = {n: coords[n] for n in coord._indexes} + else: + index_vars = {name: coord} + index_dims = {d for var in index_vars.values() for d in var.dims} + index_args = {k: v for k, v in args.items() if k in index_dims} + + if index_args: + new_index = getattr(index, func)(index_args) + if new_index is not None: + new_indexes.update({k: new_index for k in index_vars}) + new_index_vars = new_index.create_variables(index_vars, fastpath=True) + new_index_variables.update(new_index_vars) + new_index_variables.update(new_index_vars) + else: + for k in index_vars: + new_indexes.pop(k, None) + return new_indexes, new_index_variables + + def _apply_indexes( indexes: Indexes[Index], args: Mapping[Any, Any], @@ -1819,7 +1850,10 @@ def isel_indexes( indexes: Indexes[Index], indexers: Mapping[Any, Any], ) -> tuple[dict[Hashable, Index], dict[Hashable, Variable]]: - return _apply_indexes(indexes, indexers, "isel") + if any(isinstance(v, PandasMultiIndex) for v in indexes._indexes.values()): + return _apply_indexes(indexes, indexers, "isel") + else: + return _apply_indexes_fast(indexes, indexers, "isel") def roll_indexes( From 20f250d079f99d36fd8700cbdd858474e46c7c92 Mon Sep 17 00:00:00 2001 From: Mark Harfouche Date: Mon, 10 Jun 2024 17:08:48 -0400 Subject: [PATCH 04/18] Always have fastpath=True in one path --- xarray/core/indexes.py | 12 +++++++----- xarray/core/variable.py | 4 ++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/xarray/core/indexes.py b/xarray/core/indexes.py index 2b92edfac35..10fae6b5af7 100644 --- a/xarray/core/indexes.py +++ b/xarray/core/indexes.py @@ -163,8 +163,6 @@ def unstack(self) -> tuple[dict[Hashable, Index], pd.MultiIndex]: def create_variables( self, variables: Mapping[Any, Variable] | None = None, - *, - fastpath: bool = False, ) -> IndexVars: """Maybe create new coordinate variables from this index. @@ -701,7 +699,7 @@ def concat( return cls(new_pd_index, dim=dim, coord_dtype=coord_dtype) def create_variables( - self, variables: Mapping[Any, Variable] | None = None, *, fastpath: bool = False + self, variables: Mapping[Any, Variable] | None = None ) -> IndexVars: from xarray.core.variable import IndexVariable @@ -718,8 +716,12 @@ def create_variables( encoding = None data = PandasIndexingAdapter(self.index, dtype=self.coord_dtype) + + # dcherian / hmaarrfk - June 2024 + # we can get away fastpath=True this since we know that data is already + # wrapped and can be stuck in an IndexVariable. var = IndexVariable( - self.dim, data, attrs=attrs, encoding=encoding, fastpath=fastpath + self.dim, data, attrs=attrs, encoding=encoding, fastpath=True ) return {name: var} @@ -1141,7 +1143,7 @@ def reorder_levels( return self._replace(index, level_coords_dtype=level_coords_dtype) def create_variables( - self, variables: Mapping[Any, Variable] | None = None, *, fastpath: bool = False + self, variables: Mapping[Any, Variable] | None = None ) -> IndexVars: from xarray.core.variable import IndexVariable diff --git a/xarray/core/variable.py b/xarray/core/variable.py index d4a05785de7..7fd5e81f070 100644 --- a/xarray/core/variable.py +++ b/xarray/core/variable.py @@ -2624,6 +2624,10 @@ def __init__(self, dims, data, attrs=None, encoding=None, fastpath=False): if self.ndim != 1: raise ValueError(f"{type(self).__name__} objects must be 1-dimensional") + # Avoid further checks if fastpath is True + if fastpath: + return + # Unlike in Variable, always eagerly load values into memory if not isinstance(self._data, PandasIndexingAdapter): self._data = PandasIndexingAdapter(self._data) From de6e4c3ed555a4ea9ae497b6bc36afa6aad9d4b0 Mon Sep 17 00:00:00 2001 From: Mark Harfouche Date: Mon, 10 Jun 2024 17:11:09 -0400 Subject: [PATCH 05/18] Remove basicindexer fastpath=True --- xarray/core/variable.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/core/variable.py b/xarray/core/variable.py index 7fd5e81f070..fb3265a61a8 100644 --- a/xarray/core/variable.py +++ b/xarray/core/variable.py @@ -660,7 +660,7 @@ def _broadcast_indexes_basic(self, key): dims = tuple( dim for k, dim in zip(key, self.dims) if not isinstance(k, integer_types) ) - return dims, BasicIndexer(key, fastpath=True), None + return dims, BasicIndexer(key), None def _validate_indexers(self, key): """Make sanity checks""" From e6c53d2211e14e1e857262db07ee53f06397dd68 Mon Sep 17 00:00:00 2001 From: Mark Harfouche Date: Mon, 10 Jun 2024 17:12:33 -0400 Subject: [PATCH 06/18] Duplicate a comment --- xarray/core/indexes.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/xarray/core/indexes.py b/xarray/core/indexes.py index 10fae6b5af7..e2c01bfb5bb 100644 --- a/xarray/core/indexes.py +++ b/xarray/core/indexes.py @@ -655,6 +655,9 @@ def from_variables( obj = cls(data, dim, coord_dtype=var.dtype) assert not isinstance(obj.index, pd.MultiIndex) # Rename safely + # make a shallow copy: cheap and because the index name may be updated + # here or in other constructors (cannot use pd.Index.rename as this + # constructor is also called from PandasMultiIndex) obj.index = obj.index.copy() obj.index.name = name From 04b08e144c02495aa00f39de6d766fbbec846fc0 Mon Sep 17 00:00:00 2001 From: Mark Harfouche Date: Mon, 10 Jun 2024 17:14:25 -0400 Subject: [PATCH 07/18] Add comments --- xarray/core/indexes.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/xarray/core/indexes.py b/xarray/core/indexes.py index e2c01bfb5bb..8aab7179ce5 100644 --- a/xarray/core/indexes.py +++ b/xarray/core/indexes.py @@ -1855,6 +1855,9 @@ def isel_indexes( indexes: Indexes[Index], indexers: Mapping[Any, Any], ) -> tuple[dict[Hashable, Index], dict[Hashable, Variable]]: + # TODO: remove if clause in the future. It should be unnecessary. + # See failure introduced when removed + # https://github.com/pydata/xarray/pull/9002#discussion_r1590443756 if any(isinstance(v, PandasMultiIndex) for v in indexes._indexes.values()): return _apply_indexes(indexes, indexers, "isel") else: From 28983f5217717a1c89395b728530fce607917cbc Mon Sep 17 00:00:00 2001 From: Mark Harfouche Date: Mon, 10 Jun 2024 17:14:39 -0400 Subject: [PATCH 08/18] revert asv changes --- asv_bench/asv.conf.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asv_bench/asv.conf.json b/asv_bench/asv.conf.json index 4c717b7dcc4..9dc86df712d 100644 --- a/asv_bench/asv.conf.json +++ b/asv_bench/asv.conf.json @@ -29,7 +29,7 @@ // If missing or the empty string, the tool will be automatically // determined by looking for tools on the PATH environment // variable. - "environment_type": "conda", + "environment_type": "mamba", "conda_channels": ["conda-forge"], // timeout in seconds for installing any dependencies in environment From 1cc75cff1195f2270b14bc792f0e9b74690fc43b Mon Sep 17 00:00:00 2001 From: Mark Harfouche Date: Mon, 10 Jun 2024 17:18:22 -0400 Subject: [PATCH 09/18] Avoid fastpath=True assignment --- xarray/core/indexes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/core/indexes.py b/xarray/core/indexes.py index 8aab7179ce5..a8205d17e8e 100644 --- a/xarray/core/indexes.py +++ b/xarray/core/indexes.py @@ -1818,7 +1818,7 @@ def _apply_indexes_fast(indexes: Indexes[Index], args: Mapping[Any, Any], func: new_index = getattr(index, func)(index_args) if new_index is not None: new_indexes.update({k: new_index for k in index_vars}) - new_index_vars = new_index.create_variables(index_vars, fastpath=True) + new_index_vars = new_index.create_variables(index_vars) new_index_variables.update(new_index_vars) new_index_variables.update(new_index_vars) else: From f2494d6bc8f6e3d15734092b89866c0290b5a86a Mon Sep 17 00:00:00 2001 From: Mark Harfouche Date: Mon, 10 Jun 2024 17:27:33 -0400 Subject: [PATCH 10/18] Remove changes to basicindexer --- xarray/core/indexing.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/xarray/core/indexing.py b/xarray/core/indexing.py index e29d77da2c4..ef3a86e83b0 100644 --- a/xarray/core/indexing.py +++ b/xarray/core/indexing.py @@ -384,12 +384,7 @@ class BasicIndexer(ExplicitIndexer): __slots__ = () - def __init__( - self, key: tuple[int | np.integer | slice, ...], *, fastpath: bool = False - ): - if fastpath: - super().__init__(key) - return + def __init__(self, key: tuple[int | np.integer | slice, ...]): if not isinstance(key, tuple): raise TypeError(f"key must be a tuple: {key!r}") From 5bd48fdd690c531c6b42769dbd32b96dd39f1975 Mon Sep 17 00:00:00 2001 From: Mark Harfouche Date: Mon, 10 Jun 2024 17:30:32 -0400 Subject: [PATCH 11/18] Do not do fast fastpath for IndexVariable --- xarray/core/variable.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/xarray/core/variable.py b/xarray/core/variable.py index fb3265a61a8..f0685882595 100644 --- a/xarray/core/variable.py +++ b/xarray/core/variable.py @@ -2624,10 +2624,6 @@ def __init__(self, dims, data, attrs=None, encoding=None, fastpath=False): if self.ndim != 1: raise ValueError(f"{type(self).__name__} objects must be 1-dimensional") - # Avoid further checks if fastpath is True - if fastpath: - return - # Unlike in Variable, always eagerly load values into memory if not isinstance(self._data, PandasIndexingAdapter): self._data = PandasIndexingAdapter(self._data) From 4a7411b963259ae6d0e0d52fb3b3ad85d99ae29d Mon Sep 17 00:00:00 2001 From: Mark Harfouche Date: Mon, 10 Jun 2024 17:31:58 -0400 Subject: [PATCH 12/18] Remove one unecessary change --- xarray/core/indexes.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/xarray/core/indexes.py b/xarray/core/indexes.py index a8205d17e8e..92e5ea9b725 100644 --- a/xarray/core/indexes.py +++ b/xarray/core/indexes.py @@ -161,8 +161,7 @@ def unstack(self) -> tuple[dict[Hashable, Index], pd.MultiIndex]: raise NotImplementedError() def create_variables( - self, - variables: Mapping[Any, Variable] | None = None, + self, variables: Mapping[Any, Variable] | None = None ) -> IndexVars: """Maybe create new coordinate variables from this index. From d526ae43c80c4f1739f7dc674398d0914c9937cc Mon Sep 17 00:00:00 2001 From: Mark Harfouche Date: Mon, 10 Jun 2024 22:59:09 -0400 Subject: [PATCH 13/18] Remove one more fastpath --- xarray/core/indexes.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/xarray/core/indexes.py b/xarray/core/indexes.py index 92e5ea9b725..8f9c6091b90 100644 --- a/xarray/core/indexes.py +++ b/xarray/core/indexes.py @@ -718,13 +718,7 @@ def create_variables( encoding = None data = PandasIndexingAdapter(self.index, dtype=self.coord_dtype) - - # dcherian / hmaarrfk - June 2024 - # we can get away fastpath=True this since we know that data is already - # wrapped and can be stuck in an IndexVariable. - var = IndexVariable( - self.dim, data, attrs=attrs, encoding=encoding, fastpath=True - ) + var = IndexVariable(self.dim, data, attrs=attrs, encoding=encoding) return {name: var} def to_pandas_index(self) -> pd.Index: From f44253220486ad4c96223fd5186dd119275f92da Mon Sep 17 00:00:00 2001 From: Mark Harfouche Date: Tue, 11 Jun 2024 10:26:38 -0400 Subject: [PATCH 14/18] Revert uneeded change to PandasIndexingAdapter --- xarray/core/indexing.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/xarray/core/indexing.py b/xarray/core/indexing.py index ef3a86e83b0..06e7efdbb48 100644 --- a/xarray/core/indexing.py +++ b/xarray/core/indexing.py @@ -1656,15 +1656,10 @@ class PandasIndexingAdapter(ExplicitlyIndexedNDArrayMixin): __slots__ = ("array", "_dtype") - def __init__( - self, array: pd.Index, dtype: DTypeLike = None, *, fastpath: bool = False - ): + def __init__(self, array: pd.Index, dtype: DTypeLike = None): from xarray.core.indexes import safe_cast_to_index - if fastpath: - self.array = array - else: - self.array = safe_cast_to_index(array) + self.array = safe_cast_to_index(array) if dtype is None: self._dtype = get_valid_numpy_dtype(array) From 904de4f915ebf798bf8046337d6669180156afe4 Mon Sep 17 00:00:00 2001 From: Deepak Cherian Date: Tue, 11 Jun 2024 09:42:01 -0600 Subject: [PATCH 15/18] Update xarray/core/indexes.py --- xarray/core/indexes.py | 1 - 1 file changed, 1 deletion(-) diff --git a/xarray/core/indexes.py b/xarray/core/indexes.py index 8f9c6091b90..f25c0ecf936 100644 --- a/xarray/core/indexes.py +++ b/xarray/core/indexes.py @@ -1813,7 +1813,6 @@ def _apply_indexes_fast(indexes: Indexes[Index], args: Mapping[Any, Any], func: new_indexes.update({k: new_index for k in index_vars}) new_index_vars = new_index.create_variables(index_vars) new_index_variables.update(new_index_vars) - new_index_variables.update(new_index_vars) else: for k in index_vars: new_indexes.pop(k, None) From 57c5bd225f327c0343a0191fef6f6cb6276ecd07 Mon Sep 17 00:00:00 2001 From: Mark Harfouche Date: Tue, 11 Jun 2024 14:50:53 -0400 Subject: [PATCH 16/18] Update whats-new.rst --- doc/whats-new.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 96005e17f78..2419cb8dbb4 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -28,6 +28,8 @@ Performance - Small optimization to the netCDF4 and h5netcdf backends (:issue:`9058`, :pull:`9067`). By `Deepak Cherian `_. +- Small optimizations to help with indexing speeds of datasets (:pull:`9002`). + By `Mark Harfouche `_. Breaking changes From 4edd8cc9dfb964c1216dd239c3b9c24b9a2e6eaf Mon Sep 17 00:00:00 2001 From: Mark Harfouche Date: Tue, 11 Jun 2024 14:51:11 -0400 Subject: [PATCH 17/18] Update whats-new.rst --- doc/whats-new.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 2419cb8dbb4..6d08f8cc314 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -28,7 +28,7 @@ Performance - Small optimization to the netCDF4 and h5netcdf backends (:issue:`9058`, :pull:`9067`). By `Deepak Cherian `_. -- Small optimizations to help with indexing speeds of datasets (:pull:`9002`). +- Small optimizations to help reduce indexing speed of datasets (:pull:`9002`). By `Mark Harfouche `_. From 7f7b69105fba87c181f2d7873dd9accc89f27894 Mon Sep 17 00:00:00 2001 From: Deepak Cherian Date: Tue, 11 Jun 2024 14:54:07 -0600 Subject: [PATCH 18/18] fix whats-new --- doc/whats-new.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 6d08f8cc314..d82c065d6f4 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -2905,7 +2905,7 @@ Bug fixes process (:issue:`4045`, :pull:`4684`). It also enables encoding and decoding standard calendar dates with time units of nanoseconds (:pull:`4400`). By `Spencer Clark `_ and `Mark Harfouche - `_. + `_. - :py:meth:`DataArray.astype`, :py:meth:`Dataset.astype` and :py:meth:`Variable.astype` support the ``order`` and ``subok`` parameters again. This fixes a regression introduced in version 0.16.1 (:issue:`4644`, :pull:`4683`).