def fit(self, coordinates, data, weights=None): """ Fit the gridder to the given 2-component vector data. The data region is captured and used as default for the :meth:`~erizo.Elastic2D.grid` and :meth:`~erizo.Elastic2D.scatter` methods. All input arrays must have the same shape. Parameters ---------- coordinates : tuple of arrays Arrays with the coordinates of each data point. Should be in the following order: (easting, northing, vertical, ...). Only easting and northing will be used, all subsequent coordinates will be ignored. data : tuple of array A tuple ``(east_component, north_component)`` of arrays with the vector data values at each point. weights : None or tuple array If not None, then the weights assigned to each data point. Must be one array per data component. Typically, this should be 1 over the data uncertainty squared. Returns ------- self Returns this estimator instance for chaining operations. """ coordinates, data, weights = check_fit_input(coordinates, data, weights, unpack=False) if len(data) != 2: raise ValueError("Need two data components. Only {} given.".format( len(data))) # Capture the data region to use as a default when gridding. self.region_ = get_region(coordinates[:2]) if any(w is not None for w in weights): weights = np.concatenate([i.ravel() for i in weights]) else: weights = None warn_weighted_exact_solution(self, weights) data = np.concatenate([i.ravel() for i in data]) if self.force_coords is None: self.force_coords = tuple(i.copy() for i in n_1d_arrays(coordinates, n=2)) jacobian = self.jacobian(coordinates[:2], self.force_coords) self.force_ = least_squares(jacobian, data, weights, self.damping) return self
def _gradient_boosting(self, coordinates, residue, weights): """ Fit source coefficients through gradient boosting """ # Create rolling windows point_windows, data_windows = self._create_rolling_windows(coordinates) # Get number of windows n_windows = len(point_windows) # Initialize errors array errors = [np.sqrt(np.mean(residue**2))] # Set weights_chunk to None (will be changed unless weights is None) weights_chunk = None predicted = np.empty_like(residue) # Iterate over the windows for window_i in range(n_windows): # Get source and data points indices for current window point_window, data_window = point_windows[window_i], data_windows[ window_i] # Choose source and data points that fall inside the window points_chunk = tuple(p[point_window] for p in self.points_) coords_chunk = tuple(c[data_window] for c in coordinates) # Choose weights for data points inside the window (if not None) if weights is not None: weights_chunk = weights[data_window] # Compute jacobian (for sources and data points in current window) jacobian = self.jacobian(coords_chunk, points_chunk) # Fit coefficients of sources with data points inside window # (we need to copy the jacobian so it doesn't get overwritten) coeffs_chunk = vdb.least_squares( jacobian, residue[data_window], weights_chunk, self.damping, copy_jacobian=True, ) # Predict field of the sources in the window on every data point predicted[:] = 0 predict_numba_parallel( coordinates, points_chunk, coeffs_chunk, predicted, greens_func_cartesian, ) # Update the residue residue -= predicted # Add RMS of the residue errors.append(np.sqrt(np.mean(residue**2))) # Update source coefficients self.coefs_[point_window] += coeffs_chunk self.errors_ = np.array(errors)
def _gradient_boosting(self, coordinates, data, weights): """ Fit source coefficients through gradient boosting """ # Create rolling windows point_windows, data_windows = self._create_windows(coordinates) # Get number of windows n_windows = len(point_windows) # Initialize RMSE array errors = [np.sqrt(np.mean(data ** 2))] # Set weights_chunk to None (will be changed unless weights is None) weights_chunk = None # Initialized the predicted and residue arrays predicted = np.empty_like(data) residue = data.copy() # Iterate over the windows for window in range(n_windows): # Get source and data points indices for current window point_window, data_window = point_windows[window], data_windows[window] # Choose source and data points that fall inside the window points_chunk = tuple(p[point_window] for p in self.points_) coords_chunk = tuple(c[data_window] for c in coordinates) # Choose weights for data points inside the window (if not None) if weights is not None: weights_chunk = weights[data_window] # Compute Jacobian (for sources and data points in current window) jacobian = self.jacobian(coords_chunk, points_chunk) # Fit coefficients of sources with residue points inside window coeffs_chunk = vdb.least_squares( jacobian, residue[data_window], weights_chunk, self.damping, ) # Predict field of the sources in the window on every data point predicted[:] = 0 predict_numba_parallel( coordinates, points_chunk, coeffs_chunk, predicted, self.greens_function, ) # Update the residue residue -= predicted # Add RMS of the residue to the RMSE errors.append(np.sqrt(np.mean(residue ** 2))) # Update source coefficients self.coefs_[point_window] += coeffs_chunk self.rmse_per_iteration_ = np.array(errors)
def fit(self, coordinates, data, weights=None): """ Fit the coefficients of the equivalent layer. The data region is captured and used as default for the :meth:`~harmonica.EQLHarmonic.grid` and :meth:`~harmonica.EQLHarmonic.scatter` methods. All input arrays must have the same shape. Parameters ---------- coordinates : tuple of arrays Arrays with the coordinates of each data point. Should be in the following order: (``easting``, ``northing``, ``upward``, ...). Only ``easting``, ``northing``, and ``upward`` will be used, all subsequent coordinates will be ignored. data : array The data values of each data point. weights : None or array If not None, then the weights assigned to each data point. Typically, this should be 1 over the data uncertainty squared. Returns ------- self Returns this estimator instance for chaining operations. """ coordinates, data, weights = vdb.check_fit_input( coordinates, data, weights) # Capture the data region to use as a default when gridding. self.region_ = vd.get_region(coordinates[:2]) coordinates = vdb.n_1d_arrays(coordinates, 3) if self.points is None: self.points_ = ( coordinates[0], coordinates[1], coordinates[2] - self.relative_depth, ) else: self.points_ = vdb.n_1d_arrays(self.points, 3) jacobian = self.jacobian(coordinates, self.points_) self.coefs_ = vdb.least_squares(jacobian, data, weights, self.damping) return self
def fit(self, coordinates, data, weights=None): """ Fit the gridder to the given 3-component vector data. The data region is captured and used as default for the :meth:`~verde.VectorSpline3D.grid` and :meth:`~verde.VectorSpline3D.scatter` methods. All input arrays must have the same shape. Parameters ---------- coordinates : tuple of arrays Arrays with the coordinates of each data point. Should be in the following order: (easting, northing, vertical, ...). Only easting and northing will be used, all subsequent coordinates will be ignored. data : tuple of array A tuple ``(east_component, north_component, up_component)`` of arrays with the vector data values at each point. weights : None or tuple array If not None, then the weights assigned to each data point. Must be one array per data component. Typically, this should be 1 over the data uncertainty squared. Returns ------- self Returns this estimator instance for chaining operations. """ coordinates, data, weights = check_fit_input(coordinates, data, weights, unpack=False) if len(data) != 3: raise ValueError( "Need three data components. Only {} given.".format(len(data))) # Capture the data region to use as a default when gridding. self.region_ = get_region(coordinates[:2]) if any(w is not None for w in weights): weights = np.concatenate([i.ravel() for i in weights]) else: weights = None data = np.concatenate([i.ravel() for i in data]) if self.force_coords is None: self.force_coords = tuple(i.copy() for i in n_1d_arrays(coordinates, n=2)) else: self.force_coords = n_1d_arrays(self.force_coords, n=2) if self.depth_scale is None: self._depth_scale = np.zeros_like(self.force_coords[0]) elif self.depth_scale == "nearest": points = np.transpose(self.force_coords) nndist = np.median(KDTree(points).query(points, k=20)[0], axis=1) self._depth_scale = nndist - nndist.min() else: self._depth_scale = self.depth_scale jacobian = self.jacobian(coordinates[:2], self.force_coords) self.force_ = least_squares(jacobian, data, weights, self.damping) return self