@@ -9086,15 +9086,14 @@ def polyfit(
9086
9086
numpy.polyval
9087
9087
xarray.polyval
9088
9088
"""
9089
- from xarray .core .dataarray import DataArray
9090
-
9091
- variables = {}
9089
+ variables : dict [Hashable , Variable ] = {}
9092
9090
skipna_da = skipna
9093
9091
9094
9092
x = np .asarray (_ensure_numeric (self .coords [dim ]).astype (np .float64 ))
9095
9093
9096
9094
xname = f"{ self [dim ].name } _"
9097
9095
order = int (deg ) + 1
9096
+ degree_coord_values = np .arange (order )[::- 1 ]
9098
9097
lhs = np .vander (x , order )
9099
9098
9100
9099
if rcond is None :
@@ -9120,46 +9119,48 @@ def polyfit(
9120
9119
rank = np .linalg .matrix_rank (lhs )
9121
9120
9122
9121
if full :
9123
- rank = DataArray ( rank , name = xname + "matrix_rank" )
9124
- variables [rank . name ] = rank
9122
+ rank = Variable ( dims = (), data = rank )
9123
+ variables [xname + "matrix_rank" ] = rank
9125
9124
_sing = np .linalg .svd (lhs , compute_uv = False )
9126
- sing = DataArray (
9127
- _sing ,
9125
+ variables [xname + "singular_values" ] = Variable (
9128
9126
dims = (degree_dim ,),
9129
- coords = {degree_dim : np .arange (rank - 1 , - 1 , - 1 )},
9130
- name = xname + "singular_values" ,
9127
+ data = np .concatenate ([np .full ((order - rank .data ,), np .nan ), _sing ]),
9131
9128
)
9132
- variables [sing .name ] = sing
9133
9129
9134
9130
# If we have a coordinate get its underlying dimension.
9135
- true_dim = self .coords [dim ].dims [ 0 ]
9131
+ ( true_dim ,) = self .coords [dim ].dims
9136
9132
9137
- for name , da in self .data_vars .items ():
9138
- if true_dim not in da .dims :
9133
+ other_coords = {
9134
+ dim : self ._variables [dim ]
9135
+ for dim in set (self .dims ) - {true_dim }
9136
+ if dim in self ._variables
9137
+ }
9138
+ present_dims : set [Hashable ] = set ()
9139
+ for name , var in self ._variables .items ():
9140
+ if name in self ._coord_names or name in self .dims :
9141
+ continue
9142
+ if true_dim not in var .dims :
9139
9143
continue
9140
9144
9141
- if is_duck_dask_array (da . data ) and (
9145
+ if is_duck_dask_array (var . _data ) and (
9142
9146
rank != order or full or skipna is None
9143
9147
):
9144
9148
# Current algorithm with dask and skipna=False neither supports
9145
9149
# deficient ranks nor does it output the "full" info (issue dask/dask#6516)
9146
9150
skipna_da = True
9147
9151
elif skipna is None :
9148
- skipna_da = bool (np .any (da .isnull ()))
9149
-
9150
- dims_to_stack = [dimname for dimname in da .dims if dimname != true_dim ]
9151
- stacked_coords : dict [Hashable , DataArray ] = {}
9152
- if dims_to_stack :
9153
- stacked_dim = utils .get_temp_dimname (dims_to_stack , "stacked" )
9154
- rhs = da .transpose (true_dim , * dims_to_stack ).stack (
9155
- {stacked_dim : dims_to_stack }
9156
- )
9157
- stacked_coords = {stacked_dim : rhs [stacked_dim ]}
9158
- scale_da = scale [:, np .newaxis ]
9152
+ skipna_da = bool (np .any (var .isnull ()))
9153
+
9154
+ if var .ndim > 1 :
9155
+ rhs = var .transpose (true_dim , ...)
9156
+ other_dims = rhs .dims [1 :]
9157
+ scale_da = scale .reshape (- 1 , * ((1 ,) * len (other_dims )))
9159
9158
else :
9160
- rhs = da
9159
+ rhs = var
9161
9160
scale_da = scale
9161
+ other_dims = ()
9162
9162
9163
+ present_dims .update (other_dims )
9163
9164
if w is not None :
9164
9165
rhs = rhs * w [:, np .newaxis ]
9165
9166
@@ -9179,42 +9180,45 @@ def polyfit(
9179
9180
# Thus a ReprObject => polyfit was called on a DataArray
9180
9181
name = ""
9181
9182
9182
- coeffs = DataArray (
9183
- coeffs / scale_da ,
9184
- dims = [degree_dim ] + list (stacked_coords .keys ()),
9185
- coords = {degree_dim : np .arange (order )[::- 1 ], ** stacked_coords },
9186
- name = name + "polyfit_coefficients" ,
9183
+ variables [name + "polyfit_coefficients" ] = Variable (
9184
+ data = coeffs / scale_da , dims = (degree_dim ,) + other_dims
9187
9185
)
9188
- if dims_to_stack :
9189
- coeffs = coeffs .unstack (stacked_dim )
9190
- variables [coeffs .name ] = coeffs
9191
9186
9192
9187
if full or (cov is True ):
9193
- residuals = DataArray (
9194
- residuals if dims_to_stack else residuals .squeeze (),
9195
- dims = list (stacked_coords .keys ()),
9196
- coords = stacked_coords ,
9197
- name = name + "polyfit_residuals" ,
9188
+ variables [name + "polyfit_residuals" ] = Variable (
9189
+ data = residuals if var .ndim > 1 else residuals .squeeze (),
9190
+ dims = other_dims ,
9198
9191
)
9199
- if dims_to_stack :
9200
- residuals = residuals .unstack (stacked_dim )
9201
- variables [residuals .name ] = residuals
9202
9192
9203
9193
if cov :
9204
9194
Vbase = np .linalg .inv (np .dot (lhs .T , lhs ))
9205
9195
Vbase /= np .outer (scale , scale )
9196
+ if TYPE_CHECKING :
9197
+ fac : int | Variable
9206
9198
if cov == "unscaled" :
9207
9199
fac = 1
9208
9200
else :
9209
9201
if x .shape [0 ] <= order :
9210
9202
raise ValueError (
9211
9203
"The number of data points must exceed order to scale the covariance matrix."
9212
9204
)
9213
- fac = residuals / (x .shape [0 ] - order )
9214
- covariance = DataArray (Vbase , dims = ("cov_i" , "cov_j" )) * fac
9215
- variables [name + "polyfit_covariance" ] = covariance
9205
+ fac = variables [name + "polyfit_residuals" ] / (x .shape [0 ] - order )
9206
+ variables [name + "polyfit_covariance" ] = (
9207
+ Variable (data = Vbase , dims = ("cov_i" , "cov_j" )) * fac
9208
+ )
9216
9209
9217
- return type (self )(data_vars = variables , attrs = self .attrs .copy ())
9210
+ return type (self )(
9211
+ data_vars = variables ,
9212
+ coords = {
9213
+ degree_dim : degree_coord_values ,
9214
+ ** {
9215
+ name : coord
9216
+ for name , coord in other_coords .items ()
9217
+ if name in present_dims
9218
+ },
9219
+ },
9220
+ attrs = self .attrs .copy (),
9221
+ )
9218
9222
9219
9223
def pad (
9220
9224
self ,
0 commit comments