diff --git a/bluemath_tk/core/decorators.py b/bluemath_tk/core/decorators.py index 47a6ba2..3fd3189 100644 --- a/bluemath_tk/core/decorators.py +++ b/bluemath_tk/core/decorators.py @@ -513,3 +513,77 @@ def wrapper( ) return wrapper + + +def validate_gp_data(func): + """ + Validate data in ExactGPInterpolation class fit method. + + Parameters + ---------- + func : callable + The function to be decorated + + Returns + ------- + callable + The decorated function + """ + + @functools.wraps(func) + def wrapper( + self, + subset_data: pd.DataFrame, + target_data: pd.DataFrame, + subset_directional_variables: list[str] = [], + target_directional_variables: list[str] = [], + subset_custom_scale_factor: dict = {}, + normalize_target_data: bool = True, + target_custom_scale_factor: dict = {}, + verbose: int = 1, + ): + if subset_data is None: + raise ValueError("Subset data cannot be None") + elif not isinstance(subset_data, pd.DataFrame): + raise TypeError("Subset data must be a pandas DataFrame") + if target_data is None: + raise ValueError("Target data cannot be None") + elif not isinstance(target_data, pd.DataFrame): + raise TypeError("Target data must be a pandas DataFrame") + if not isinstance(subset_directional_variables, list): + raise TypeError("Subset directional variables must be a list") + for directional_variable in subset_directional_variables: + if directional_variable not in subset_data.columns: + raise ValueError( + f"Directional variable {directional_variable} " + f"not found in subset data" + ) + if not isinstance(target_directional_variables, list): + raise TypeError("Target directional variables must be a list") + for directional_variable in target_directional_variables: + if directional_variable not in target_data.columns: + raise ValueError( + f"Directional variable {directional_variable} " + f"not found in target data" + ) + if not isinstance(subset_custom_scale_factor, dict): + raise TypeError("Subset custom scale factor must be a dict") + if not isinstance(normalize_target_data, bool): + raise TypeError("Normalize target data must be a bool") + if not isinstance(target_custom_scale_factor, dict): + raise TypeError("Target custom scale factor must be a dict") + if not isinstance(verbose, int) or verbose < 0: + raise ValueError("Verbose must be an integer >= 0") + return func( + self, + subset_data, + target_data, + subset_directional_variables, + target_directional_variables, + subset_custom_scale_factor, + normalize_target_data, + target_custom_scale_factor, + verbose, + ) + + return wrapper diff --git a/bluemath_tk/datamining/__init__.py b/bluemath_tk/datamining/__init__.py index 9d805c3..068d499 100644 --- a/bluemath_tk/datamining/__init__.py +++ b/bluemath_tk/datamining/__init__.py @@ -13,5 +13,6 @@ from .pca import PCA from .som import SOM -# Optionally, define the module's `__all__` variable to control what gets imported when using `from module import *`. +# Optionally, define the module's `__all__` variable to control what gets imported +# when using `from module import *`. __all__ = ["KMA", "LHS", "MDA", "PCA", "SOM"] diff --git a/bluemath_tk/datamining/kma.py b/bluemath_tk/datamining/kma.py index e689a3a..e243497 100644 --- a/bluemath_tk/datamining/kma.py +++ b/bluemath_tk/datamining/kma.py @@ -7,6 +7,8 @@ Status: Under development (Working) """ +import platform + import numpy as np import pandas as pd from scipy.spatial.distance import cdist @@ -269,12 +271,17 @@ def _create_pyclustering_model( # Build kwargs for pyclustering kwargs = {} + # Use Python implementation (ccore=False) on macOS to avoid architecture + # compatibility issues with the native C++ library (x86_64 vs arm64) + # On other platforms, use the faster C++ implementation (ccore=True, default) + if platform.system() == "Darwin": # macOS + kwargs["ccore"] = False if self.distance_metric is not None: # Map common metric names to pyclustering format if needed - kwargs["ccore"] = False # Use Python implementation # Note: pyclustering's distance metric handling varies by algorithm # For simplicity, we'll let pyclustering use defaults # Advanced users can modify the model directly if needed + pass # Import and create the appropriate algorithm if self.algorithm_name == "kmeans": diff --git a/bluemath_tk/deeplearning/gp_models.py b/bluemath_tk/deeplearning/gp_models.py deleted file mode 100644 index 8c8c44d..0000000 --- a/bluemath_tk/deeplearning/gp_models.py +++ /dev/null @@ -1,667 +0,0 @@ -""" -Gaussian Process models module. - -This module contains Gaussian Process Regression models using GPyTorch. - -Classes: -- BaseGPRModel: Base class for all GP models -- ExactGPModel: Exact Gaussian Process Regression model - -1. Wang, Z., Leung, M., Mukhopadhyay, S., et al. (2024). "A hybrid statistical–dynamical framework for compound coastal flooding analysis." *Environmental Research Letters*, 20(1), 014005. -2. Wang, Z., Leung, M., Mukhopadhyay, S., et al. (2025). "Compound coastal flooding in San Francisco Bay under climate change." *npj Natural Hazards*, 2(1), 3. -""" - -from abc import abstractmethod -from typing import Dict, Optional, Tuple, Union - -import gpytorch -import numpy as np -import torch -from gpytorch.kernels import Kernel, MaternKernel, RBFKernel, ScaleKernel -from gpytorch.likelihoods import GaussianLikelihood -from gpytorch.means import ConstantMean -from gpytorch.mlls import ExactMarginalLogLikelihood -from gpytorch.models import ExactGP -from tqdm import tqdm - -from ..core.models import BlueMathModel - - -class BaseGPRModel(BlueMathModel): - """ - Base class for Gaussian Process Regression models. - - This class provides common functionality for all GP models, including: - - GP-specific training with marginal log likelihood - - Prediction with uncertainty quantification - - Model save/load with likelihood handling - - GP models differ from standard deep learning models in several ways: - - Use marginal log likelihood (MLL) instead of standard loss functions - - Require explicit training data setting via set_train_data() - - Return distributions (mean + variance) rather than point estimates - - Typically train on full dataset (no batching during training) - - GP models inherit directly from BlueMathModel (not BaseDeepLearningModel) - because their training and prediction workflows are fundamentally different - from standard neural networks. - - Attributes - ---------- - model : gpytorch.models.GP - The GPyTorch model. - device : torch.device - The device (CPU/GPU) the model is on. - is_fitted : bool - Whether the model has been fitted. - likelihood : gpytorch.likelihoods.Likelihood - The GP likelihood module. - mll : gpytorch.mlls.MarginalLogLikelihood - The marginal log likelihood objective. - """ - - def __init__( - self, - device: Optional[Union[str, torch.device]] = None, - **kwargs, - ): - """ - Initialize the base GP model. - - Parameters - ---------- - device : str or torch.device, optional - Device to run the model on. Default is None (auto-detect GPU/CPU). - **kwargs - Additional keyword arguments passed to BlueMathModel. - """ - super().__init__(**kwargs) - - # Device management (similar to BaseDeepLearningModel but GP-specific) - if device is None: - self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu") - elif isinstance(device, str): - self.device = torch.device(device) - else: - self.device = device - - # GP-specific attributes - self.model: Optional[gpytorch.models.GP] = None - self.is_fitted = False - self.likelihood: Optional[gpytorch.likelihoods.Likelihood] = None - self.mll: Optional[gpytorch.mlls.MarginalLogLikelihood] = None - - # Exclude from pickling (GPyTorch objects need special handling) - self._exclude_attributes = [ - "model", - "likelihood", - "mll", - ] - - @abstractmethod - def _build_kernel(self, input_dim: int) -> Kernel: - """ - Build the covariance kernel. - - Parameters - ---------- - input_dim : int - Number of input dimensions. - - Returns - ------- - gpytorch.kernels.Kernel - The covariance kernel. - """ - - pass - - @abstractmethod - def _build_model(self, input_shape: Tuple, **kwargs) -> gpytorch.models.GP: - """ - Build the GPyTorch model. - - Parameters - ---------- - input_shape : Tuple - Shape of input data. - - Returns - ------- - gpytorch.models.GP - The GPyTorch model. - """ - - pass - - def fit( - self, - X: np.ndarray, - y: np.ndarray, - epochs: int = 200, - learning_rate: float = 0.1, - optimizer: Optional[torch.optim.Optimizer] = None, - patience: int = 30, - verbose: int = 1, - **kwargs, - ) -> Dict[str, list]: - """ - Fit the Gaussian Process model. - - GP models use marginal log likelihood (MLL) optimization, which is - fundamentally different from standard deep learning training. - - Parameters - ---------- - X : np.ndarray - Training input data with shape (n_samples, n_features). - y : np.ndarray - Training target data with shape (n_samples,) or (n_samples, 1). - epochs : int, optional - Maximum number of training epochs. Default is 200. - learning_rate : float, optional - Learning rate for optimizer. Default is 0.1. - optimizer : torch.optim.Optimizer, optional - Optimizer to use. If None, uses Adam. Default is None. - patience : int, optional - Early stopping patience. Default is 30. - verbose : int, optional - Verbosity level. Default is 1. - **kwargs - Additional keyword arguments passed to _build_model. - - Returns - ------- - Dict[str, list] - Training history with 'train_loss' key (negative MLL). - """ - - # Reshape y if needed - if y.ndim > 1: - y = y.ravel() - - # Convert to tensors - X_tensor = torch.FloatTensor(X).to(self.device) - y_tensor = torch.FloatTensor(y).to(self.device) - - # Build model if not already built - if self.model is None: - self.model = self._build_model(X.shape, **kwargs) - # Initialize likelihood if not set - if self.likelihood is None: - self.likelihood = GaussianLikelihood().to(self.device) - # Initialize MLL - self.mll = self._build_mll(self.likelihood, self.model) - - # Always update training data (allows retraining with new data) - # This is GP-specific: we need to explicitly set training data - self._set_train_data(X_tensor, y_tensor) - - # Rebuild MLL after setting training data - self.mll = self._build_mll(self.likelihood, self.model) - - # Setup optimizer - if optimizer is None: - optimizer = torch.optim.Adam( - list(self.model.parameters()) + list(self.likelihood.parameters()), - lr=learning_rate, - ) - - # Setup learning rate scheduler - scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau( - optimizer, mode="min", factor=0.8, patience=10 - ) - - history = {"train_loss": []} - best_loss = float("inf") - patience_counter = 0 - best_model_state = None - best_likelihood_state = None - - # Training loop - use_progress_bar = verbose > 0 - epoch_range = range(epochs) - pbar = None - if use_progress_bar: - pbar = tqdm(epoch_range, desc="Training GP", unit="epoch") - epoch_range = pbar - - self.model.train() - self.likelihood.train() - - for epoch in epoch_range: - optimizer.zero_grad() - - # Forward pass: compute negative marginal log likelihood - # This is the GP-specific loss function - loss = self._compute_loss(X_tensor, y_tensor) - - # Backward pass - loss.backward() - torch.nn.utils.clip_grad_norm_( - list(self.model.parameters()) + list(self.likelihood.parameters()), - max_norm=1.0, - ) - optimizer.step() - - loss_value = loss.item() - history["train_loss"].append(loss_value) - scheduler.step(loss_value) - - # Early stopping - if loss_value < best_loss - 1e-4: - best_loss = loss_value - patience_counter = 0 - best_model_state = self.model.state_dict().copy() - best_likelihood_state = self.likelihood.state_dict().copy() - else: - patience_counter += 1 - if patience_counter >= patience: - if verbose > 0: - if pbar is not None: - pbar.set_postfix_str(f"Early stopping at epoch {epoch + 1}") - self.logger.info(f"Early stopping at epoch {epoch + 1}") - break - - # Update progress bar - if pbar is not None: - pbar.set_postfix_str(f"Loss: {loss_value:.4f}") - elif verbose > 0 and (epoch + 1) % max(1, epochs // 10) == 0: - self.logger.info(f"Epoch {epoch + 1}/{epochs} - Loss: {loss_value:.4f}") - - # Restore best model - if best_model_state is not None: - self.model.load_state_dict(best_model_state) - self.likelihood.load_state_dict(best_likelihood_state) - - self.is_fitted = True - - return history - - def predict( - self, - X: np.ndarray, - batch_size: Optional[int] = None, - return_std: bool = False, - verbose: int = 1, - ) -> Union[np.ndarray, Tuple[np.ndarray, np.ndarray]]: - """ - Make predictions with the Gaussian Process model. - - GP models return distributions, so predictions include uncertainty - estimates (standard deviation) by default. - - Parameters - ---------- - X : np.ndarray - Input data with shape (n_samples, n_features). - batch_size : int, optional - Batch size for prediction. If None, processes all at once. - Default is None. - return_std : bool, optional - If True, returns both mean and standard deviation. - Default is False. - verbose : int, optional - Verbosity level. Default is 1. - - Returns - ------- - np.ndarray or tuple - If return_std=False: predictions (mean) with shape (n_samples,). - If return_std=True: tuple of (mean, std) both with shape (n_samples,). - - Raises - ------ - ValueError - If model is not fitted. - """ - - if not self.is_fitted or self.model is None: - raise ValueError("Model must be fitted before prediction.") - - self.model.eval() - self.likelihood.eval() - - X_tensor = torch.FloatTensor(X).to(self.device) - - # Process in batches if batch_size is specified - if batch_size is None: - batch_size = len(X) - - predictions = [] - stds = [] - - n_batches = (len(X) + batch_size - 1) // batch_size - batch_range = range(0, len(X), batch_size) - - if verbose > 0 and n_batches > 1: - batch_range = tqdm( - batch_range, desc="Predicting", unit="batch", total=n_batches - ) - - with ( - torch.no_grad(), - gpytorch.settings.fast_pred_var(), - gpytorch.settings.cholesky_jitter(1e-1), - ): - for i in batch_range: - batch_X = X_tensor[i : i + batch_size] - pred_dist = self._predict_batch(batch_X) - predictions.append(pred_dist.mean.cpu().numpy()) - if return_std: - stds.append(pred_dist.stddev.cpu().numpy()) - - mean_pred = np.concatenate(predictions, axis=0) - - if return_std: - std_pred = np.concatenate(stds, axis=0) - return mean_pred, std_pred - else: - return mean_pred - - def _set_train_data(self, X: torch.Tensor, y: torch.Tensor): - """ - Set training data for the GP model. - - This is GP-specific: GP models need explicit training data setting. - - Parameters - ---------- - X : torch.Tensor - Training inputs. - y : torch.Tensor - Training targets. - """ - - if hasattr(self.model, "set_train_data"): - self.model.set_train_data(X, y, strict=False) - else: - raise AttributeError( - f"Model {type(self.model)} does not support set_train_data(). " - "This is required for GP models." - ) - - def _build_mll( - self, - likelihood: gpytorch.likelihoods.Likelihood, - model: gpytorch.models.GP, - ) -> gpytorch.mlls.MarginalLogLikelihood: - """ - Build the marginal log likelihood objective. - - Parameters - ---------- - likelihood : gpytorch.likelihoods.Likelihood - The likelihood module. - model : gpytorch.models.GP - The GP model. - - Returns - ------- - gpytorch.mlls.MarginalLogLikelihood - The MLL objective. - """ - - return ExactMarginalLogLikelihood(likelihood, model) - - def _compute_loss(self, X: torch.Tensor, y: torch.Tensor) -> torch.Tensor: - """ - Compute the training loss (negative MLL). - - Parameters - ---------- - X : torch.Tensor - Training inputs. - y : torch.Tensor - Training targets. - - Returns - ------- - torch.Tensor - Negative marginal log likelihood. - """ - - with gpytorch.settings.cholesky_jitter(1e-1): - output = self.model(X) - loss = -self.mll(output, y) - - return loss - - def _predict_batch(self, X: torch.Tensor) -> gpytorch.distributions.Distribution: - """ - Make predictions for a batch of inputs. - - Parameters - ---------- - X : torch.Tensor - Input batch. - - Returns - ------- - gpytorch.distributions.Distribution - Predictive distribution. - """ - - return self.likelihood(self.model(X)) - - def save_pytorch_model(self, model_path: str, **kwargs): - """ - Save the GP model to a file. - - GP models require saving both the model and likelihood state dicts. - - Parameters - ---------- - model_path : str - Path to the file where the model will be saved. - **kwargs - Additional arguments for torch.save. - """ - - if self.model is None or self.likelihood is None: - raise ValueError("Model must be built before saving.") - - # Get model-specific metadata - metadata = self._get_model_metadata() - - torch.save( - { - "model_state_dict": self.model.state_dict(), - "likelihood_state_dict": self.likelihood.state_dict(), - "is_fitted": self.is_fitted, - "model_class": self.__class__.__name__, - **metadata, - }, - model_path, - **kwargs, - ) - self.logger.info(f"GP model saved to {model_path}") - - def load_pytorch_model(self, model_path: str, **kwargs): - """ - Load a GP model from a file. - - Parameters - ---------- - model_path : str - Path to the file where the model is saved. - **kwargs - Additional arguments for torch.load. - """ - - checkpoint = torch.load(model_path, **kwargs) - - # Restore model-specific attributes - self._restore_model_metadata(checkpoint) - - # Build model first if needed - if self.model is None: - # Need input shape to build model - use dummy data - # In practice, you should save/load the training data shape - dummy_shape = (10, 10) # Default, user should provide actual shape - self.model = self._build_model(dummy_shape) - # Initialize likelihood if not set (should be set by _build_model, but check anyway) - if self.likelihood is None: - self.likelihood = GaussianLikelihood().to(self.device) - - self.model.load_state_dict(checkpoint["model_state_dict"]) - self.likelihood.load_state_dict(checkpoint["likelihood_state_dict"]) - self.is_fitted = checkpoint.get("is_fitted", False) - self.logger.info(f"GP model loaded from {model_path}") - - def _get_model_metadata(self) -> Dict: - """ - Get model-specific metadata for saving. - - Override this method in subclasses to save additional metadata. - - Returns - ------- - Dict - Metadata dictionary. - """ - - return {} - - def _restore_model_metadata(self, checkpoint: Dict): - """ - Restore model-specific metadata from checkpoint. - - Override this method in subclasses to restore additional metadata. - - Parameters - ---------- - checkpoint : Dict - Checkpoint dictionary. - """ - - pass - - -class ExactGPModel(BaseGPRModel): - """ - Exact Gaussian Process Regression model using GPyTorch. - - This model implements exact GP inference, suitable for datasets up to - several thousand samples. For larger datasets, consider using approximate - GP methods. - - Parameters - ---------- - kernel : str, optional - Type of kernel to use. Options: 'rbf', 'matern', 'rbf+matern'. - Default is 'rbf+matern'. - ard_num_dims : int, optional - Number of input dimensions for ARD (Automatic Relevance Determination). - If None, will be inferred from data. Default is None. - device : str or torch.device, optional - Device to run the model on. Default is None (auto-detect). - **kwargs - Additional keyword arguments passed to BaseGPRModel. - - Examples - -------- - >>> import numpy as np - >>> from bluemath_tk.deeplearning import ExactGPModel - >>> - >>> # Generate sample data - >>> X = np.random.randn(100, 5) - >>> y = np.random.randn(100) - >>> - >>> # Create and fit model - >>> gp = ExactGPModel(kernel='rbf+matern') - >>> history = gp.fit(X, y, epochs=100, learning_rate=0.1) - >>> - >>> # Make predictions - >>> X_test = np.random.randn(50, 5) - >>> y_pred, y_std = gp.predict(X_test, return_std=True) - """ - - def __init__( - self, - kernel: str = "rbf+matern", - ard_num_dims: Optional[int] = None, - device: Optional[torch.device] = None, - **kwargs, - ): - super().__init__(device=device, **kwargs) - self.kernel_type = kernel.lower() - self.ard_num_dims = ard_num_dims - - def _build_kernel(self, input_dim: int) -> Kernel: - """ - Build the covariance kernel. - """ - - if self.ard_num_dims is None: - ard_num_dims = input_dim - else: - ard_num_dims = self.ard_num_dims - - if self.kernel_type == "rbf": - base_kernel = RBFKernel(ard_num_dims=ard_num_dims) - elif self.kernel_type == "matern": - base_kernel = MaternKernel(nu=2.5, ard_num_dims=ard_num_dims) - elif self.kernel_type == "rbf+matern": - base_kernel = RBFKernel(ard_num_dims=ard_num_dims) + MaternKernel( - nu=2.5, ard_num_dims=ard_num_dims - ) - else: - raise ValueError( - f"Unknown kernel type: {self.kernel_type}. " - "Options: 'rbf', 'matern', 'rbf+matern'" - ) - - return ScaleKernel(base_kernel) - - def _build_model(self, input_shape: Tuple, **kwargs) -> ExactGP: - """ - Build the GPyTorch ExactGP model. - """ - - if len(input_shape) == 1: - input_dim = input_shape[0] - else: - input_dim = input_shape[-1] - - kernel = self._build_kernel(input_dim) - - class GPModel(ExactGP): - def __init__(self, train_x, train_y, likelihood, kernel): - super().__init__(train_x, train_y, likelihood) - self.mean_module = ConstantMean() - self.covar_module = kernel - - def forward(self, x): - mean_x = self.mean_module(x) - covar_x = self.covar_module(x) - return gpytorch.distributions.MultivariateNormal(mean_x, covar_x) - - # Create dummy data for initialization - dummy_x = torch.randn(10, input_dim).to(self.device) - dummy_y = torch.randn(10).to(self.device) - - # Initialize likelihood and model - if self.likelihood is None: - self.likelihood = GaussianLikelihood().to(self.device) - model = GPModel(dummy_x, dummy_y, self.likelihood, kernel.to(self.device)) - - return model.to(self.device) - - def _get_model_metadata(self) -> Dict: - """ - Get model-specific metadata for saving. - """ - - return { - "kernel_type": self.kernel_type, - "ard_num_dims": self.ard_num_dims, - } - - def _restore_model_metadata(self, checkpoint: Dict): - """ - Restore model-specific metadata from checkpoint. - """ - - self.kernel_type = checkpoint.get("kernel_type", "rbf+matern") - self.ard_num_dims = checkpoint.get("ard_num_dims", None) diff --git a/bluemath_tk/interpolation/__init__.py b/bluemath_tk/interpolation/__init__.py index 504f6df..351805c 100644 --- a/bluemath_tk/interpolation/__init__.py +++ b/bluemath_tk/interpolation/__init__.py @@ -9,5 +9,6 @@ # Import essential functions/classes to be available at the package level. from .rbf import RBF -# Optionally, define the module's `__all__` variable to control what gets imported when using `from module import *`. +# Optionally, define the module's `__all__` variable to control what gets imported +# when using `from module import *`. __all__ = ["RBF"] diff --git a/bluemath_tk/interpolation/_base_interpolation.py b/bluemath_tk/interpolation/_base_interpolation.py index 7dc944d..da184f2 100644 --- a/bluemath_tk/interpolation/_base_interpolation.py +++ b/bluemath_tk/interpolation/_base_interpolation.py @@ -1,9 +1,14 @@ from abc import abstractmethod -from typing import List +import matplotlib.pyplot as plt +import numpy as np import pandas as pd +from matplotlib.axes import Axes +from matplotlib.colors import Normalize +from matplotlib.figure import Figure from ..core.models import BlueMathModel +from ..core.plotting.base_plotting import DefaultStaticPlotting class BaseInterpolation(BlueMathModel): @@ -67,15 +72,325 @@ def fit_predict(self, *args, **kwargs): pass + def explain_with_mendezf( + self, + target_variable: str = None, + dataset: pd.DataFrame | None = None, + vmin: float | None = None, + vmax: float | None = None, + **kwargs, + ) -> tuple[Figure, np.ndarray]: + """ + Explain model predictions with scatter plots colored by target variable. + + Creates triangle scatter plots showing input feature relationships, + with points colored by the predicted target variable values. This provides + visual insight into how the target variable varies across the input space. + + Parameters + ---------- + target_variable : str, optional + The target variable to visualize. If None, uses the first target variable. + Default is None. + dataset : pd.DataFrame, optional + Dataset to plot. If None, uses the training subset data. + Default is None. + vmin : float, optional + Minimum value for color scale. If None, uses data minimum. + Default is None. + vmax : float, optional + Maximum value for color scale. If None, uses data maximum. + Default is None. + **kwargs : dict, optional + Additional keyword arguments for scatter plot (e.g., s, alpha, marker). + + Returns + ------- + Tuple[Figure, np.ndarray] + A tuple containing: + - Figure object + - 2D array of Axes objects + + Raises + ------ + ValueError + If the model is not fitted or target_variable is invalid. + """ + + if not self.is_fitted: + raise ValueError("Model must be fitted before explaining.") + + # Select target variable + if target_variable is None: + target_variable = self.target_processed_variables[0] + elif target_variable not in self.target_processed_variables: + raise ValueError( + f"target_variable '{target_variable}' not found in " + f"target_processed_variables: {self.target_processed_variables}" + ) + + # Use provided dataset or training data + if dataset is None: + dataset = self._original_subset_data.copy() + else: + dataset = dataset.copy() + + # Ensure dataset has the same columns as training data + if not all( + col in dataset.columns for col in self._original_subset_data.columns + ): + raise ValueError( + f"Dataset must contain the same columns as subset_data: " + f"{self._original_subset_data.columns.tolist()}" + ) + + # Predict target variable for the dataset + self.logger.info(f"Predicting {target_variable} for visualization dataset") + try: + predictions = self.predict(dataset=dataset, verbose=0) + except TypeError: + predictions = self.predict(dataset=dataset) + + target_values = predictions[target_variable].values + + # Get variable names from dataset + variables_names = list(dataset.columns) + num_variables = len(variables_names) + + if num_variables < 2: + raise ValueError( + "Dataset must have at least 2 variables for triangle plot." + ) + + # Create figure and axes in triangle arrangement + default_static_plot = DefaultStaticPlotting() + fig, axes = default_static_plot.get_subplots( + nrows=num_variables - 1, + ncols=num_variables - 1, + sharex=False, + sharey=False, + ) + if isinstance(axes, Axes): + axes = np.array([[axes]]) + elif axes.ndim == 1: + axes = axes.reshape(-1, 1) + + # Set color scale limits + if vmin is None: + vmin = target_values.min() + if vmax is None: + vmax = target_values.max() + + # Create scatter plots in triangle arrangement + # c1 indexes variables_names[1:] (x-axis variables) + # c2 indexes variables_names[:-1] (y-axis variables) + for c1, v1 in enumerate(variables_names[1:]): + for c2, v2 in enumerate(variables_names[:-1]): + if c1 == c2: + # Diagonal: set labels + default_static_plot.plot_scatter( + ax=axes[c2, c1], + x=dataset[v1], + y=dataset[v2], + c=target_values, + alpha=0.6, + cmap="bwr", + vmin=vmin, + vmax=vmax, + **kwargs, + ) + axes[c2, c1].set_xlabel(variables_names[c1 + 1]) + axes[c2, c1].set_ylabel(variables_names[c2]) + elif c1 > c2: + # Lower triangle: hide tick labels + default_static_plot.plot_scatter( + ax=axes[c2, c1], + x=dataset[v1], + y=dataset[v2], + c=target_values, + alpha=0.6, + cmap="bwr", + vmin=vmin, + vmax=vmax, + **kwargs, + ) + axes[c2, c1].xaxis.set_ticklabels([]) + axes[c2, c1].yaxis.set_ticklabels([]) + else: + # Upper triangle: remove axes + fig.delaxes(axes[c2, c1]) + + fig.suptitle(f"Input Features Colored by {target_variable}", fontsize=14) + + # Create a custom axis for the colorbar at the bottom right + cbar_ax = fig.add_axes([0.15, 0.05, 0.4, 0.02]) + # Create colorbar with proper normalization + norm = Normalize(vmin=vmin, vmax=vmax) + sm = plt.cm.ScalarMappable(cmap="bwr", norm=norm) + + cbar = fig.colorbar(sm, cax=cbar_ax, orientation="horizontal") + cbar.set_label(target_variable, fontsize=12, fontweight="bold") + cbar.ax.tick_params(labelsize=10) + + plt.tight_layout() + plt.show() + + return fig, axes + + def explain_with_shap( + self, + dataset: pd.DataFrame, + target_variable: str = None, + num_samples: int = 100, + max_background_samples: int = 100, + ) -> None: + """ + Explain model predictions using SHAP (SHapley Additive exPlanations) values. + + This method provides comprehensive model interpretability by automatically + generating interactive SHAP visualizations for each target variable. It uses + the training subset data as background. + + Parameters + ---------- + dataset : pd.DataFrame + The test dataset to explain predictions for. Must have the same variables + as the subset_data used for fitting. + target_variable : str, optional + The target variable to explain. If None, explains all target variables. + Default is None. + num_samples : int, optional + Number of samples to use for SHAP approximation. Higher values give + more accurate results but are slower. Default is 100. + Recommended: 100-500 for good balance between speed and accuracy. + max_background_samples : int, optional + Maximum number of background samples to use. The subset data will be + automatically summarized using k-means if it exceeds this value. + Default is 100. + + Raises + ------ + ImportError + If SHAP is not installed. + ValueError + If the model is not fitted or target_variable is invalid. + """ + + try: + import logging + + import shap + + # Suppress SHAP INFO logs (keep progress bars) + shap_logger = logging.getLogger("shap") + shap_logger.setLevel(logging.WARNING) + + shap.initjs() # Initialize JavaScript for interactive plots + except ImportError: + raise ImportError( + "SHAP is required for explain method. Install with: pip install shap" + ) + + if not self.is_fitted: + raise ValueError("Model must be fitted before explaining.") + + # Determine which target variables to explain + if target_variable is None: + target_vars = self.target_processed_variables + else: + if target_variable not in self.target_processed_variables: + raise ValueError( + f"target_variable '{target_variable}' not found in " + f"target_processed_variables: {self.target_processed_variables}" + ) + target_vars = [target_variable] + + # Prepare background data from subset (raw data, not preprocessed) + # SHAP will normalize it internally, and predict will handle preprocessing + background = self._original_subset_data.copy() + + # Summarize background data for efficiency if it's too large + if len(background) > max_background_samples: + self.logger.info( + f"Summarizing background data from {len(background)} " + f"to {max_background_samples} samples using k-means" + ) + n_clusters = min(max_background_samples, len(background)) + background_summary = shap.kmeans(background.values, n_clusters) + else: + n_clusters = len(background) + background_summary = background.values + + for target_var in target_vars: + self.logger.info( + f"Explaining predictions for target variable: {target_var}" + ) + + # Create a prediction function for this specific target variable + # SHAP normalizes the background internally, so X is normalized + # We convert back to DataFrame with original column names (matching + # subset_data), then predict handles preprocessing + def predict_fn(X): + """ + Predict the target variable for SHAP explanation. + + Parameters + ---------- + X : np.ndarray + Input features normalized by SHAP (shape: n_samples, n_features) + + Returns + ------- + np.ndarray + Predictions for the target variable (shape: n_samples,) + """ + # Convert normalized array to DataFrame with original column names + # (matching self._original_subset_data.columns, not processed columns) + # SHAP normalizes based on background, so X is in normalized space + # but we need original column structure for predict + dataset_df = pd.DataFrame(X, columns=self._original_subset_data.columns) + + # Use predict to get all target variables, then extract the one we want + # This handles preprocessing internally (Dir -> Dir_u/Dir_v, normalize) + # and returns denormalized values + # Try to call predict with verbose=0, fallback if not supported + try: + predictions = self.predict(dataset=dataset_df, verbose=0) + except TypeError: + # Some models might not support verbose parameter + predictions = self.predict(dataset=dataset_df) + return predictions[target_var].values + + # Create SHAP explainer + self.logger.info( + f"Creating SHAP KernelExplainer with {n_clusters} " + f"background samples and {num_samples} evaluation samples" + ) + explainer = shap.KernelExplainer(predict_fn, background_summary) + + # Calculate SHAP values using original dataset + # SHAP will normalize internally, but we use original for plotting + self.logger.info(f"Calculating SHAP values for {len(dataset)} samples...") + shap_values = explainer.shap_values(dataset.values, nsamples=num_samples) + + # Ensure shap_values is 2D (handle both single and multiple samples) + shap_values = np.array(shap_values) + if shap_values.ndim == 1: + shap_values = shap_values.reshape(1, -1) + + # Generate SHAP summary plot using original dataset (good magnitudes) + self.logger.info(f"Generating SHAP summary plot for {target_var}") + shap.summary_plot(shap_values, dataset, show=True) + class InterpolationComparator: """ Class for comparing interpolation models. """ - def __init__(self, list_of_models: List[BaseInterpolation]) -> None: + def __init__(self, list_of_models: list[BaseInterpolation]) -> None: """ - Initializes the InterpolationComparator class. + Initialize the InterpolationComparator class. """ self.list_of_models = list_of_models diff --git a/bluemath_tk/interpolation/analogs.py b/bluemath_tk/interpolation/analogs.py deleted file mode 100644 index e69de29..0000000 diff --git a/bluemath_tk/interpolation/gps.py b/bluemath_tk/interpolation/gps.py index e69de29..79e51f8 100644 --- a/bluemath_tk/interpolation/gps.py +++ b/bluemath_tk/interpolation/gps.py @@ -0,0 +1,824 @@ +""" +Package: BlueMath_tk +Module: interpolation +File: gps.py +Author: GeoOcean Research Group, Universidad de Cantabria +Repository: https://github.com/GeoOcean/BlueMath_tk.git +Status: Under development (Working) + +Gaussian Process interpolation models using GPyTorch. + +This module provides Gaussian Process interpolation following the same +interface pattern as RBF interpolation, with support for: +- Multiple target variables +- Directional variables (wind direction, wave direction, etc.) +- Data normalization +- Uncertainty quantification + +References +---------- +1. Wang, Z., Leung, M., Mukhopadhyay, S., et al. (2024). + "A hybrid statistical–dynamical framework for compound coastal flooding analysis." + *Environmental Research Letters*, 20(1), 014005. +2. Wang, Z., Leung, M., Mukhopadhyay, S., et al. (2025). + "Compound coastal flooding in San Francisco Bay under climate change." + *npj Natural Hazards*, 2(1), 3. +3. GPyTorch Documentation: https://docs.gpytorch.ai/ +""" + +import gpytorch +import numpy as np +import pandas as pd +import torch +from gpytorch.constraints import GreaterThan +from gpytorch.kernels import Kernel, MaternKernel, RBFKernel, ScaleKernel +from gpytorch.likelihoods import GaussianLikelihood +from gpytorch.means import ConstantMean +from gpytorch.mlls import ExactMarginalLogLikelihood +from gpytorch.models import ExactGP +from tqdm import tqdm + +from ..core.decorators import validate_gp_data +from ._base_interpolation import BaseInterpolation + + +class GPError(Exception): + """ + Custom exception for Gaussian Process interpolation model. + """ + + def __init__(self, message: str = "GP error occurred."): + self.message = message + super().__init__(self.message) + + +class ExactGPInterpolation(BaseInterpolation): + """ + Exact Gaussian Process interpolation model using GPyTorch. + + This model implements exact GP inference for interpolation tasks, + following the same interface pattern as RBF interpolation. Suitable + for datasets up to several thousand samples. + + Examples + -------- + .. jupyter-execute:: + + import numpy as np + import pandas as pd + from bluemath_tk.interpolation.gps import ExactGPInterpolation + + dataset = pd.DataFrame({ + "Hs": np.random.rand(1000) * 7, + "Tp": np.random.rand(1000) * 20, + "Dir": np.random.rand(1000) * 360, + }) + subset = dataset.sample(frac=0.25) + target = pd.DataFrame({ + "HsPred": subset["Hs"] * 2 + subset["Tp"] * 3, + "DirPred": -subset["Dir"], + }) + + gp = ExactGPInterpolation(kernel='rbf+matern') + predictions = gp.fit_predict( + subset_data=subset, + subset_directional_variables=["Dir"], + target_data=target, + target_directional_variables=["DirPred"], + normalize_target_data=True, + dataset=dataset, + ) + print(predictions.head()) + + References + ---------- + [1] https://docs.gpytorch.ai/en/stable/examples/01_Exact_GPs/Simple_GP_Regression.html + [2] Rasmussen, C. E., & Williams, C. K. I. (2006). + Gaussian Processes for Machine Learning. MIT Press. + """ + + def __init__( + self, + kernel: str = "rbf+matern", + ard_num_dims: int | None = None, + device: str | torch.device | None = None, + epochs: int = 200, + learning_rate: float = 0.1, + patience: int = 30, + ): + """ + Initialize Exact GP interpolation model. + + Parameters + ---------- + kernel : str, optional + Type of kernel to use. Options: 'rbf', 'matern', 'rbf+matern'. + Default is 'rbf+matern'. + ard_num_dims : int, optional + Number of input dimensions for ARD. If None, inferred from data. + Default is None. + device : str or torch.device, optional + Device to run the model on. Default is None (auto-detect). + epochs : int, optional + Maximum number of training epochs. Default is 200. + learning_rate : float, optional + Learning rate for optimizer. Default is 0.1. + patience : int, optional + Early stopping patience. Default is 30. + """ + + super().__init__() + self.set_logger_name(name=self.__class__.__name__) + + # Validate and store parameters + if kernel.lower() not in ["rbf", "matern", "rbf+matern"]: + raise ValueError( + f"kernel must be one of ['rbf', 'matern', 'rbf+matern'], got {kernel}" + ) + self._kernel = kernel.lower() + self._ard_num_dims = ard_num_dims + self._epochs = epochs + self._learning_rate = learning_rate + self._patience = patience + + # Device management + if device is None: + self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + elif isinstance(device, str): + self.device = torch.device(device) + else: + self.device = device + + # GP-specific attributes - store models per target variable + self._models: dict[str, gpytorch.models.GP] = {} + self._likelihoods: dict[str, gpytorch.likelihoods.Likelihood] = {} + self._mlls: dict[str, gpytorch.mlls.MarginalLogLikelihood] = {} + + # Interpolation-specific attributes (similar to RBF) + self.is_fitted: bool = False + self.is_target_normalized: bool = False + self._original_subset_data: pd.DataFrame = pd.DataFrame() + self._subset_data: pd.DataFrame = pd.DataFrame() + self._normalized_subset_data: pd.DataFrame = pd.DataFrame() + self._target_data: pd.DataFrame = pd.DataFrame() + self._normalized_target_data: pd.DataFrame = pd.DataFrame() + self._subset_directional_variables: list[str] = [] + self._target_directional_variables: list[str] = [] + self._subset_processed_variables: list[str] = [] + self._target_processed_variables: list[str] = [] + self._subset_custom_scale_factor: dict = {} + self._target_custom_scale_factor: dict = {} + self._subset_scale_factor: dict = {} + self._target_scale_factor: dict = {} + self._hyperparameters: dict[str, dict] = {} # Store hyperparams per target var + + # Exclude from pickling + self._exclude_attributes = ["_models", "_likelihoods", "_mlls"] + + initial_msg = f""" + --------------------------------------------------------------------------------- + | Initializing Exact GP interpolation model with the following parameters: + | - kernel: {self._kernel} + | - ard_num_dims: {self._ard_num_dims} + | - device: {self.device} + | - epochs: {self._epochs} + | - learning_rate: {self._learning_rate} + | - patience: {self._patience} + | For more information, please refer to the documentation. + --------------------------------------------------------------------------------- + """ + self.logger.info(initial_msg) + + @property + def kernel(self) -> str: + """Return the kernel name.""" + return self._kernel + + @property + def ard_num_dims(self) -> int | None: + """Return the ARD number of dimensions.""" + return self._ard_num_dims + + @property + def subset_data(self) -> pd.DataFrame: + """Return the subset data.""" + return self._subset_data + + @property + def normalized_subset_data(self) -> pd.DataFrame: + """Return the normalized subset data.""" + return self._normalized_subset_data + + @property + def target_data(self) -> pd.DataFrame: + """Return the target data.""" + return self._target_data + + @property + def normalized_target_data(self) -> pd.DataFrame: + """Return the normalized target data.""" + if self._normalized_target_data.empty: + raise ValueError("Target data is not normalized.") + return self._normalized_target_data + + @property + def subset_directional_variables(self) -> list[str]: + """Return the subset directional variables.""" + return self._subset_directional_variables + + @property + def target_directional_variables(self) -> list[str]: + """Return the target directional variables.""" + return self._target_directional_variables + + @property + def subset_processed_variables(self) -> list[str]: + """Return the subset processed variables.""" + return self._subset_processed_variables + + @property + def target_processed_variables(self) -> list[str]: + """Return the target processed variables.""" + return self._target_processed_variables + + @property + def hyperparameters(self) -> dict[str, dict]: + """ + Return the learned hyperparameters for each target variable. + + Returns + ------- + dict + Dictionary mapping target variable names to their hyperparameters. + Each hyperparameter dict contains: + - 'lengthscale': list of lengthscales (one per input dimension if ARD) + - 'lengthscales': list of dicts for additive kernels (rbf+matern), + each with 'kernel_0', 'kernel_1', etc. keys + - 'outputscale': float, output scale from ScaleKernel + - 'noise': float, noise variance from likelihood + - 'mean_constant': float, mean constant from ConstantMean + + Notes + ----- + Hyperparameters are extracted after training. For additive kernels + (rbf+matern), lengthscales are stored per sub-kernel. + """ + return self._hyperparameters + + def _build_kernel(self, input_dim: int) -> Kernel: + """ + Build the covariance kernel. + + Parameters + ---------- + input_dim : int + Number of input dimensions. + + Returns + ------- + gpytorch.kernels.Kernel + The covariance kernel. + """ + if self._ard_num_dims is None: + ard_num_dims = input_dim + else: + ard_num_dims = self._ard_num_dims + + if self._kernel == "rbf": + base_kernel = RBFKernel(ard_num_dims=ard_num_dims) + elif self._kernel == "matern": + base_kernel = MaternKernel(nu=2.5, ard_num_dims=ard_num_dims) + elif self._kernel == "rbf+matern": + base_kernel = RBFKernel(ard_num_dims=ard_num_dims) + MaternKernel( + nu=2.5, ard_num_dims=ard_num_dims + ) + else: + raise ValueError(f"Unknown kernel type: {self._kernel}") + + return ScaleKernel(base_kernel) + + def _build_model( + self, input_dim: int, train_x: torch.Tensor, train_y: torch.Tensor + ) -> tuple[ExactGP, GaussianLikelihood]: + """ + Build the GPyTorch ExactGP model. + + Parameters + ---------- + input_dim : int + Number of input dimensions. + train_x : torch.Tensor + Training input data. + train_y : torch.Tensor + Training target data. + + Returns + ------- + tuple + (GP model, likelihood) + """ + kernel = self._build_kernel(input_dim) + + class GPModel(ExactGP): + def __init__(self, train_x, train_y, likelihood, kernel): + super().__init__(train_x, train_y, likelihood) + self.mean_module = ConstantMean() + self.covar_module = kernel + + def forward(self, x): + mean_x = self.mean_module(x) + covar_x = self.covar_module(x) + return gpytorch.distributions.MultivariateNormal(mean_x, covar_x) + + # Initialize likelihood with very small noise for exact interpolation + # Use a small fixed value (1e-6) for numerical stability while + # maintaining near-exact interpolation at training points (like RBF) + noise_lower = np.finfo(float).eps + noise_constraint = GreaterThan(lower_bound=noise_lower) + likelihood = GaussianLikelihood(noise_constraint=noise_constraint).to( + self.device + ) + # Initialize noise to a very small value for exact interpolation + # This ensures predictions at training points match observed values + initial_noise = 1e-6 + with torch.no_grad(): + likelihood.noise = torch.tensor( + initial_noise, device=self.device, dtype=torch.float32 + ) + model = GPModel(train_x, train_y, likelihood, kernel.to(self.device)).to( + self.device + ) + + return model, likelihood + + def _preprocess_subset_data( + self, subset_data: pd.DataFrame, is_fit: bool = True + ) -> pd.DataFrame: + """ + Preprocess the subset data (similar to RBF pattern). + + Parameters + ---------- + subset_data : pd.DataFrame + The subset data to preprocess (could be a dataset to predict). + is_fit : bool, optional + Whether the data is being fit or not. Default is True. + + Returns + ------- + pd.DataFrame + The preprocessed subset data. + """ + + subset_data = subset_data.copy() + + self.logger.info("Checking for NaNs in subset data") + subset_data = self.check_nans(data=subset_data, raise_error=True) + + self.logger.info("Preprocessing subset data") + for directional_variable in self._subset_directional_variables: + var_u_component, var_v_component = self.get_uv_components( + x_deg=subset_data[directional_variable].values + ) + subset_data[f"{directional_variable}_u"] = var_u_component + subset_data[f"{directional_variable}_v"] = var_v_component + subset_data.drop(columns=[directional_variable], inplace=True) + + self.logger.info("Normalizing subset data") + normalized_subset_data, subset_scale_factor = self.normalize( + data=subset_data, + custom_scale_factor=self._subset_custom_scale_factor + if is_fit + else self._subset_scale_factor, + ) + + if is_fit: + self._subset_data = subset_data + self._subset_processed_variables = list(subset_data.columns) + self._normalized_subset_data = normalized_subset_data + self._subset_scale_factor = subset_scale_factor + else: + normalized_subset_data = normalized_subset_data[ + self._subset_processed_variables + ] + + self.logger.info("Subset data preprocessed successfully") + + return normalized_subset_data.copy() + + def _preprocess_target_data( + self, + target_data: pd.DataFrame, + normalize_target_data: bool = True, + ) -> pd.DataFrame: + """ + Preprocess the target data (similar to RBF pattern). + + Parameters + ---------- + target_data : pd.DataFrame + The target data to preprocess. + normalize_target_data : bool, optional + Whether to normalize the target data. Default is True. + + Returns + ------- + pd.DataFrame + The preprocessed target data. + """ + + target_data = target_data.copy() + + self.logger.info("Checking for NaNs in target data") + target_data = self.check_nans(data=target_data, raise_error=True) + + self.logger.info("Preprocessing target data") + for directional_variable in self._target_directional_variables: + var_u_component, var_v_component = self.get_uv_components( + x_deg=target_data[directional_variable].values + ) + target_data[f"{directional_variable}_u"] = var_u_component + target_data[f"{directional_variable}_v"] = var_v_component + target_data.drop(columns=[directional_variable], inplace=True) + self._target_processed_variables = list(target_data.columns) + + if normalize_target_data: + self.logger.info("Normalizing target data") + normalized_target_data, target_scale_factor = self.normalize( + data=target_data, + custom_scale_factor=self._target_custom_scale_factor, + ) + self.is_target_normalized = True + self._target_data = target_data.copy() + self._normalized_target_data = normalized_target_data.copy() + self._target_scale_factor = target_scale_factor.copy() + self.logger.info("Target data preprocessed successfully") + return normalized_target_data.copy() + else: + self.is_target_normalized = False + self._target_data = target_data.copy() + self._normalized_target_data = pd.DataFrame() + self._target_scale_factor = {} + self.logger.info("Target data preprocessed successfully") + return target_data.copy() + + @validate_gp_data + def fit( + self, + subset_data: pd.DataFrame, + target_data: pd.DataFrame, + subset_directional_variables: list[str] = [], + target_directional_variables: list[str] = [], + subset_custom_scale_factor: dict = {}, + normalize_target_data: bool = True, + target_custom_scale_factor: dict = {}, + verbose: int = 1, + ) -> None: + """ + Fit the GP model to the data. + + Parameters + ---------- + subset_data : pd.DataFrame + The subset data used to fit the model. + target_data : pd.DataFrame + The target data used to fit the model. + subset_directional_variables : List[str], optional + The subset directional variables. Default is []. + target_directional_variables : List[str], optional + The target directional variables. Default is []. + subset_custom_scale_factor : dict, optional + The custom scale factor for the subset data. Default is {}. + normalize_target_data : bool, optional + Whether to normalize the target data. Default is True. + target_custom_scale_factor : dict, optional + The custom scale factor for the target data. Default is {}. + verbose : int, optional + Verbosity level. Default is 1. + """ + + self._subset_directional_variables = subset_directional_variables + self._target_directional_variables = target_directional_variables + self._subset_custom_scale_factor = subset_custom_scale_factor + self._target_custom_scale_factor = target_custom_scale_factor + + # Store original subset data before preprocessing + # (for explain, plot_partial_dependence, etc.) + self._original_subset_data = subset_data.copy() + + # Preprocess data + normalized_subset = self._preprocess_subset_data(subset_data=subset_data) + normalized_target = self._preprocess_target_data( + target_data=target_data, + normalize_target_data=normalize_target_data, + ) + + # Convert to tensors + X_tensor = torch.FloatTensor(normalized_subset.values).to(self.device) + + # Fit GP model for each target variable + self.logger.info("Fitting GP models for each target variable") + + for target_var in normalized_target.columns: + self.logger.info(f"Fitting GP for target variable: {target_var}") + y_tensor = torch.FloatTensor(normalized_target[target_var].values).to( + self.device + ) + + # Build model + input_dim = normalized_subset.shape[1] + model, likelihood = self._build_model(input_dim, X_tensor, y_tensor) + + # Set training data + model.set_train_data(X_tensor, y_tensor, strict=False) + mll = ExactMarginalLogLikelihood(likelihood, model) + + # Setup optimizer + optimizer = torch.optim.Adam( + list(model.parameters()) + list(likelihood.parameters()), + lr=self._learning_rate, + ) + + # Setup learning rate scheduler + scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau( + optimizer, mode="min", factor=0.8, patience=10 + ) + + # Training loop + model.train() + likelihood.train() + + best_loss = float("inf") + patience_counter = 0 + best_model_state = None + best_likelihood_state = None + + use_progress_bar = verbose > 0 + epoch_range = range(self._epochs) + if use_progress_bar: + epoch_range = tqdm( + epoch_range, + desc=f"Training GP for {target_var}", + unit="epoch", + ) + + for epoch in epoch_range: + optimizer.zero_grad() + + with gpytorch.settings.cholesky_jitter(1e-1): + output = model(X_tensor) + loss = -mll(output, y_tensor) + + loss.backward() + torch.nn.utils.clip_grad_norm_( + list(model.parameters()) + list(likelihood.parameters()), + max_norm=1.0, + ) + optimizer.step() + + # Keep noise small for exact interpolation + # Clip noise to stay within bounds for numerical stability + with torch.no_grad(): + if hasattr(likelihood, "noise"): + noise_value = likelihood.noise.item() + if noise_value > 1e-5: + likelihood.noise.data.clamp_( + min=np.finfo(float).eps, max=1e-5 + ) + + loss_value = loss.item() + scheduler.step(loss_value) + + # Early stopping + if loss_value < best_loss - 1e-4: + best_loss = loss_value + patience_counter = 0 + best_model_state = model.state_dict().copy() + best_likelihood_state = likelihood.state_dict().copy() + else: + patience_counter += 1 + if patience_counter >= self._patience: + if verbose > 0: + self.logger.info( + f"Early stopping at epoch {epoch + 1} for {target_var}" + ) + break + + # Update progress bar + if use_progress_bar and isinstance(epoch_range, tqdm): + epoch_range.set_postfix_str(f"Loss: {loss_value:.4f}") + elif verbose > 0 and (epoch + 1) % max(1, self._epochs // 10) == 0: + self.logger.info( + f"Epoch {epoch + 1}/{self._epochs} - Loss: {loss_value:.4f}" + ) + + # Restore best model + if best_model_state is not None: + model.load_state_dict(best_model_state) + likelihood.load_state_dict(best_likelihood_state) + + # Store model, likelihood, and mll for this target variable + self._models[target_var] = model + self._likelihoods[target_var] = likelihood + self._mlls[target_var] = mll + + # Extract and store hyperparameters + hyperparams = {} + + # Get lengthscales from kernel + covar_module = model.covar_module + if hasattr(covar_module, "base_kernel"): + base_kernel = covar_module.base_kernel + # Handle additive kernels (rbf+matern) + if hasattr(base_kernel, "kernels"): + # Additive kernel - extract from each sub-kernel + lengthscales = [] + for i, sub_kernel in enumerate(base_kernel.kernels): + if hasattr(sub_kernel, "lengthscale"): + ls = sub_kernel.lengthscale.detach().cpu() + lengthscales.append({f"kernel_{i}": ls.flatten().tolist()}) + hyperparams["lengthscales"] = lengthscales + else: + # Single kernel + if hasattr(base_kernel, "lengthscale"): + lengthscale = base_kernel.lengthscale.detach().cpu() + hyperparams["lengthscale"] = lengthscale.flatten().tolist() + + # Get output scale + if hasattr(covar_module, "outputscale"): + outputscale = covar_module.outputscale.detach().cpu().item() + hyperparams["outputscale"] = outputscale + + # Get noise variance + if hasattr(likelihood, "noise"): + noise = likelihood.noise.detach().cpu().item() + hyperparams["noise"] = noise + + # Get mean constant + if hasattr(model.mean_module, "constant"): + mean_const = model.mean_module.constant.detach().cpu().item() + hyperparams["mean_constant"] = mean_const + + self._hyperparameters[target_var] = hyperparams + + self.is_fitted = True + self.logger.info("GP models fitted successfully") + + def predict( + self, + dataset: pd.DataFrame, + return_std: bool = False, + verbose: int = 1, + ) -> pd.DataFrame: + """ + Predict using the fitted GP model. + + Parameters + ---------- + dataset : pd.DataFrame + The dataset to predict (must have same variables as subset). + return_std : bool, optional + If True, returns standard deviations. Default is False. + verbose : int, optional + Verbosity level. Default is 1. + + Returns + ------- + pd.DataFrame + The predicted dataset. If return_std=True, includes columns + with '_std' suffix for standard deviations. + + Raises + ------ + GPError + If the model is not fitted. + """ + + if not self.is_fitted: + raise GPError("GP model must be fitted before predicting.") + + self.logger.info("Preprocessing dataset for prediction") + normalized_dataset = self._preprocess_subset_data( + subset_data=dataset, is_fit=False + ) + + X_tensor = torch.FloatTensor(normalized_dataset.values).to(self.device) + + # Predict for each target variable + predictions_dict = {} + stds_dict = {} + + for target_var in self._target_processed_variables: + if verbose > 0: + self.logger.info(f"Predicting target variable: {target_var}") + + model = self._models[target_var] + likelihood = self._likelihoods[target_var] + + model.eval() + likelihood.eval() + + with torch.no_grad(), gpytorch.settings.fast_pred_var(): + pred_dist = likelihood(model(X_tensor)) + predictions_dict[target_var] = pred_dist.mean.cpu().numpy() + if return_std: + # stds_dict[f"{target_var}_std"] = pred_dist.stddev.cpu().numpy() + # self._target_scale_factor[f"{target_var}_std"] = ( + # self._target_scale_factor[target_var] + # ) + ( + stds_dict[f"{target_var}_lower_ci"], + stds_dict[f"{target_var}_upper_ci"], + ) = ( + pred_dist.confidence_region()[0].cpu().numpy(), + pred_dist.confidence_region()[1].cpu().numpy(), + ) + self._target_scale_factor[f"{target_var}_lower_ci"] = ( + self._target_scale_factor[target_var] + ) + self._target_scale_factor[f"{target_var}_upper_ci"] = ( + self._target_scale_factor[target_var] + ) + + # Convert to DataFrame + result = pd.DataFrame(predictions_dict) + + if return_std: + std_df = pd.DataFrame(stds_dict) + result = pd.concat([result, std_df], axis=1) + + # Denormalize if needed + if self.is_target_normalized: + self.logger.info("Denormalizing target data") + result = self.denormalize( + normalized_data=result, + scale_factor=self._target_scale_factor, + ) + + # Reconstruct directional variables + for directional_variable in self._target_directional_variables: + self.logger.info(f"Calculating target degrees for {directional_variable}") + result[directional_variable] = self.get_degrees_from_uv( + xu=result[f"{directional_variable}_u"].values, + xv=result[f"{directional_variable}_v"].values, + ) + + return result + + def fit_predict( + self, + subset_data: pd.DataFrame, + target_data: pd.DataFrame, + dataset: pd.DataFrame, + subset_directional_variables: list[str] = [], + target_directional_variables: list[str] = [], + subset_custom_scale_factor: dict = {}, + normalize_target_data: bool = True, + target_custom_scale_factor: dict = {}, + return_std: bool = False, + verbose: int = 1, + ) -> pd.DataFrame: + """ + Fit the model and predict in one step. + + Parameters + ---------- + subset_data : pd.DataFrame + The subset data used to fit the model. + target_data : pd.DataFrame + The target data used to fit the model. + dataset : pd.DataFrame + The dataset to predict (must have same variables as subset). + subset_directional_variables : List[str], optional + The subset directional variables. Default is []. + target_directional_variables : List[str], optional + The target directional variables. Default is []. + subset_custom_scale_factor : dict, optional + The custom scale factor for the subset data. Default is {}. + normalize_target_data : bool, optional + Whether to normalize the target data. Default is True. + target_custom_scale_factor : dict, optional + The custom scale factor for the target data. Default is {}. + return_std : bool, optional + If True, returns standard deviations. Default is False. + verbose : int, optional + Verbosity level. Default is 1. + + Returns + ------- + pd.DataFrame + The interpolated dataset. + """ + + self.fit( + subset_data=subset_data, + target_data=target_data, + subset_directional_variables=subset_directional_variables, + target_directional_variables=target_directional_variables, + subset_custom_scale_factor=subset_custom_scale_factor, + normalize_target_data=normalize_target_data, + target_custom_scale_factor=target_custom_scale_factor, + verbose=verbose, + ) + + return self.predict(dataset=dataset, return_std=return_std, verbose=verbose) diff --git a/bluemath_tk/interpolation/rbf.py b/bluemath_tk/interpolation/rbf.py index 85625f4..574f17a 100644 --- a/bluemath_tk/interpolation/rbf.py +++ b/bluemath_tk/interpolation/rbf.py @@ -11,6 +11,7 @@ from collections.abc import Callable import dask.array as da +import matplotlib.pyplot as plt import numpy as np import pandas as pd from scipy.optimize import fmin, fminbound @@ -20,35 +21,69 @@ from ._base_interpolation import BaseInterpolation -def gaussian_kernel(r: float, const: float) -> float: +def linear_kernel(r: float, const: float): """ - Calculate the Gaussian kernel value for the given distance and constant. + Calculate the linear kernel value. Parameters ---------- r : float The distance between the data points. const : float - The constant (usually called sigma for the Gaussian kernel). + The constant parameter (not used in linear kernel). Returns ------- float - The value of the Gaussian kernel. + The value of the linear kernel. + """ - Notes - ----- - - The Gaussian kernel is defined as: - K(r) = exp(-0.5 * (r / const)**2) (https://en.wikipedia.org/wiki/Gaussian_function) - - Here, we are assuming the mean is 0. + return -r + + +def cubic_kernel(r: float, const: float): """ + Calculate the cubic kernel value. - return np.exp(-0.5 * r * r / (const * const)) + Parameters + ---------- + r : float + The distance between the data points. + const : float + The constant parameter (not used in cubic kernel). + + Returns + ------- + float + The value of the cubic kernel. + """ + return r**3 -def multiquadratic_kernel(r: float, const: float): + +def quintic_kernel(r: float, const: float): """ - Calculate the multiquadratic kernel value. + Calculate the quintic kernel value. + + Parameters + ---------- + r : float + The distance between the data points. + const : float + The constant parameter (not used in quintic kernel). + + Returns + ------- + float + The value of the quintic kernel. + """ + + return -(r**5) + + +def thin_plate_kernel(r: float, const: float): + """ + Calculate the thin plate spline kernel value. Parameters ---------- @@ -60,10 +95,31 @@ def multiquadratic_kernel(r: float, const: float): Returns ------- float - The value of the multiquadratic kernel. + The value of the thin plate spline kernel. + + Notes + ----- + The thin plate kernel is defined as r^2 * log(r/const). + At r=0, this evaluates to 0 (since lim(r->0) r^2*log(r) = 0). + We handle this case explicitly to avoid NaN. """ - return np.sqrt(1 + (r / const) ** 2) + # Convert to numpy array for consistent handling + r = np.asarray(r) + is_scalar = r.ndim == 0 + if is_scalar: + r = np.array([r]) + + # Initialize result array + result = np.zeros_like(r, dtype=float) + + # For non-zero r, calculate r^2 * log(r/const) + # Use mask to handle the case where r is very small + mask = r > 1e-10 + result[mask] = r[mask] ** 2 * np.log(r[mask] / const) + + # Return scalar if input was scalar, otherwise return array + return float(result[0]) if is_scalar else result def inverse_kernel(r: float, const: float): @@ -86,29 +142,29 @@ def inverse_kernel(r: float, const: float): return 1 / np.sqrt(1 + (r / const) ** 2) -def cubic_kernel(r: float, const: float): +def inverse_quadratic_kernel(r: float, const: float): """ - Calculate the cubic kernel value. + Calculate the inverse quadratic kernel value. Parameters ---------- r : float The distance between the data points. const : float - The constant parameter (not used in cubic kernel). + The constant parameter. Returns ------- float - The value of the cubic kernel. + The value of the inverse quadratic kernel. """ - return r**3 + return 1 / (1 + (r / const) ** 2) -def thin_plate_kernel(r: float, const: float): +def multiquadratic_kernel(r: float, const: float): """ - Calculate the thin plate spline kernel value. + Calculate the multiquadratic kernel value. Parameters ---------- @@ -120,10 +176,36 @@ def thin_plate_kernel(r: float, const: float): Returns ------- float - The value of the thin plate spline kernel. + The value of the multiquadratic kernel. + """ + + return np.sqrt(1 + (r / const) ** 2) + + +def gaussian_kernel(r: float, const: float) -> float: + """ + Calculate the Gaussian kernel value for the given distance and constant. + + Parameters + ---------- + r : float + The distance between the data points. + const : float + The constant (usually called sigma for the Gaussian kernel). + + Returns + ------- + float + The value of the Gaussian kernel. + + Notes + ----- + - The Gaussian kernel is defined as: + K(r) = exp(-0.5 * (r / const)**2) (https://en.wikipedia.org/wiki/Gaussian_function) + - Here, we are assuming the mean is 0. """ - return r**2 * np.log(r / const) + return np.exp(-0.5 * r * r / (const * const)) class RBFError(Exception): @@ -192,13 +274,19 @@ class RBF(BaseInterpolation): """ rbf_kernels = { - "gaussian": gaussian_kernel, - "multiquadratic": multiquadratic_kernel, - "inverse": inverse_kernel, + "linear": linear_kernel, "cubic": cubic_kernel, + "quintic": quintic_kernel, "thin_plate": thin_plate_kernel, + "inverse": inverse_kernel, + "inverse_quadratic": inverse_quadratic_kernel, + "multiquadratic": multiquadratic_kernel, + "gaussian": gaussian_kernel, } + # Kernels that don't require sigma optimization + _kernels_no_sigma_opt = {"linear", "cubic", "quintic", "thin_plate"} + def __init__( self, sigma_min: float = 0.001, @@ -276,6 +364,7 @@ def __init__( # Below, we initialize the attributes that will be set in the fit method self.is_fitted: bool = False self.is_target_normalized: bool = False + self._original_subset_data: pd.DataFrame = pd.DataFrame() self._subset_data: pd.DataFrame = pd.DataFrame() self._normalized_subset_data: pd.DataFrame = pd.DataFrame() self._target_data: pd.DataFrame = pd.DataFrame() @@ -288,7 +377,6 @@ def __init__( self._target_custom_scale_factor: dict = {} self._subset_scale_factor: dict = {} self._target_scale_factor: dict = {} - self._rbf_coeffs: pd.DataFrame = pd.DataFrame() self._opt_sigmas: dict = {} # Exclude attributes to .save_model() method @@ -394,16 +482,88 @@ def target_scale_factor(self) -> dict: """Return the target scale factor.""" return self._target_scale_factor - @property - def rbf_coeffs(self) -> pd.DataFrame: - """Return the RBF coefficients.""" - return self._rbf_coeffs - @property def opt_sigmas(self) -> dict: - """Return the optimal sigmas.""" + """ + Return the optimal sigmas. + + Returns + ------- + dict + Dictionary mapping target variable names to their optimal sigma values. + Values may be None for kernels that don't require sigma optimization + (e.g., linear, cubic, quintic, thin_plate). + """ return self._opt_sigmas + def _print_validation_summary(self, all_results: dict) -> None: + """Print a summary of validation results.""" + print("\n" + "=" * 60) + print("RBF Fit Validation Summary") + print("=" * 60) + + overall_status = "good" + for var, results in all_results.items(): + if results["status"] == "poor": + overall_status = "poor" + elif results["status"] == "warning" and overall_status == "good": + overall_status = "warning" + + print(f"\nOverall Status: {overall_status.upper()}") + + for var, results in all_results.items(): + print(f"\n{var}:") + print(f" Status: {results['status'].upper()}") + + if results["matrix_condition"] is not None: + cond = results["matrix_condition"] + status_icon = "⚠️" if cond > 1e8 else "✓" + print(f" {status_icon} Matrix condition: {cond:.2e}") + + if results["matrix_rank"] is not None: + rank, expected, deficiency = results["matrix_rank"] + if deficiency > 0: + print( + f" ⚠️ Matrix rank: {rank}/{expected} " + f"(deficiency: {deficiency})" + ) + else: + print(f" ✓ Matrix rank: {rank}/{expected}") + + if results["training_error"] is not None: + error = results["training_error"] + status_icon = "⚠️" if error > 1e-5 else "✓" + print(f" {status_icon} Training error: {error:.2e}") + + if results["training_std"] is not None: + std_max = results["training_std"]["max"] + status_icon = "⚠️" if std_max > 1e-3 else "✓" + print(f" {status_icon} Training std: max={std_max:.2e}") + + if results["sigma_status"] is not None: + sigma_status = results["sigma_status"] + if sigma_status == "ok": + print(" ✓ Sigma: OK") + else: + opt_sigma = self._opt_sigmas.get(var) + if sigma_status == "at_lower_boundary": + print( + f" ⚠️ Sigma ({opt_sigma:.6f}) at lower boundary " + f"({self.sigma_min:.6f})" + ) + elif sigma_status == "at_upper_boundary": + print( + f" ⚠️ Sigma ({opt_sigma:.6f}) at upper boundary " + f"({self.sigma_max:.6f})" + ) + + if results["warnings"]: + print(" Warnings:") + for warning in results["warnings"]: + print(f" - {warning}") + + print("\n" + "=" * 60) + def _preprocess_subset_data( self, subset_data: pd.DataFrame, is_fit: bool = True ) -> pd.DataFrame: @@ -571,7 +731,15 @@ def _rbf_assemble(self, x, sigma): A = self.kernel_func(dists, sigma) # Subtract the smoothing parameter from the diagonal elements - np.fill_diagonal(A, A.diagonal() - self.smooth) + # For exact interpolation (smooth=0), use machine epsilon for numerical + # stability to handle near-singular matrices while maintaining exactness + if self.smooth == 0.0: + # Use machine epsilon for minimal numerical stability + # This is small enough to maintain essentially exact interpolation + numerical_stability = np.finfo(A.dtype).eps + else: + numerical_stability = self.smooth + np.fill_diagonal(A, A.diagonal() - numerical_stability) # Add the identity matrix to the matrix (polynomial term) P = np.hstack((np.ones((n, 1)), x.T)) @@ -612,7 +780,7 @@ def _calc_rbf_coeff( b = np.concatenate((y, np.zeros((m + 1,)))).reshape(-1, 1) # Calculate the RBF coefficients - rbfcoeff, _, _, _ = np.linalg.lstsq(A, b, rcond=None) # inverse + rbfcoeff, _, _, _ = np.linalg.lstsq(A, b, rcond=None) return rbfcoeff, A @@ -664,12 +832,190 @@ def _cost_sigma(self, sigma: float, x: np.ndarray, y: np.ndarray) -> float: return yy + def _needs_sigma_optimization(self) -> bool: + """ + Check if the current kernel requires sigma optimization. + + Returns + ------- + bool + True if the kernel requires sigma optimization, False otherwise. + """ + return self.kernel not in self._kernels_no_sigma_opt + + def _validate_fit( + self, + target_var: str, + opt_sigma: float | None, + A: np.ndarray, + rbf_coeff: np.ndarray, + target_variable: np.ndarray, + subset_variables: np.ndarray, + ) -> dict: + """ + Validate the RBF fit quality for a single target variable. + + This method performs all validation checks in one place: + - Matrix condition and rank + - Training point prediction accuracy + - Standard deviation values at training points + - Sigma value reasonableness (if applicable) + + Parameters + ---------- + target_var : str + Name of the target variable. + opt_sigma : float | None + Optimal sigma value (None if kernel doesn't need it). + A : np.ndarray + The RBF matrix used for fitting. + rbf_coeff : np.ndarray + The RBF coefficients. + target_variable : np.ndarray + The target variable values (normalized). + subset_variables : np.ndarray + The subset variables used for interpolation (normalized). + + Returns + ------- + dict + Dictionary containing validation results with keys: + - 'status': 'good', 'warning', or 'poor' + - 'matrix_condition': condition number + - 'matrix_rank': (actual, expected, deficiency) + - 'training_error': max absolute error at training points + - 'training_std': std values at training points (if return_std was used) + - 'sigma_status': sigma validation status (if applicable) + - 'warnings': list of warning messages + """ + + results = { + "status": "good", + "matrix_condition": None, + "matrix_rank": None, + "training_error": None, + "training_std": None, + "sigma_status": None, + "warnings": [], + } + + # Check matrix condition number + cond = np.linalg.cond(A) + results["matrix_condition"] = cond + if cond > 1e12: + results["status"] = "poor" + results["warnings"].append( + f"Matrix is ill-conditioned (condition: {cond:.2e})" + ) + elif cond > 1e8: + if results["status"] == "good": + results["status"] = "warning" + results["warnings"].append( + f"Matrix condition is moderately high ({cond:.2e})" + ) + + # Check matrix rank + rank = np.linalg.matrix_rank(A) + expected_rank = A.shape[0] + deficiency = expected_rank - rank + results["matrix_rank"] = (rank, expected_rank, deficiency) + if rank < expected_rank: + if results["status"] == "good": + results["status"] = "warning" + results["warnings"].append( + f"Matrix is rank-deficient ({rank}/{expected_rank}, " + f"deficiency: {deficiency})" + ) + + # Check training point prediction accuracy + # Predict at training points + n_pts = subset_variables.shape[1] + + # Manual prediction at training points + training_predictions = [] + for i in range(n_pts): + x_train = subset_variables[:, i : i + 1].T + x_subset_T = subset_variables.T + + r_train = np.linalg.norm( + x_train[:, None, :] - x_subset_T[None, :, :], axis=2 + ) + kernel_train = self.kernel_func(r_train, opt_sigma if opt_sigma else 1.0) + + # Get linear coefficients + linear_coeffs = rbf_coeff[n_pts + 1 :] + if linear_coeffs.ndim == 1: + linear_coeffs_2d = linear_coeffs.reshape(-1, 1) + else: + linear_coeffs_2d = linear_coeffs.T + + linear_term = np.dot(x_train, linear_coeffs_2d) + if linear_term.ndim > 1 and linear_term.shape[1] == 1: + linear_term = linear_term.squeeze(axis=1) + + pred = ( + rbf_coeff[n_pts] + np.dot(kernel_train, rbf_coeff[:n_pts]) + linear_term + ) + training_predictions.append(pred.flatten()[0]) + + training_predictions = np.array(training_predictions) + training_error = np.abs(training_predictions - target_variable) + max_error = np.max(training_error) + results["training_error"] = max_error + + # Check if training points are perfectly predicted (within numerical precision) + if max_error > 1e-5: + if results["status"] == "good": + results["status"] = "warning" + results["warnings"].append( + f"Training points not perfectly predicted (max error: {max_error:.2e})" + ) + + # Check std values at training points (should be ~0) + if hasattr(self, "_training_std") and target_var in self._training_std: + training_std = self._training_std[target_var] + results["training_std"] = { + "max": np.max(training_std), + "mean": np.mean(training_std), + } + if np.max(training_std) > 1e-3: + if results["status"] == "good": + results["status"] = "warning" + results["warnings"].append( + f"Std at training points is non-zero " + f"(max: {np.max(training_std):.2e})" + ) + + # Check sigma value (if applicable) + if opt_sigma is not None: + tolerance = 0.01 + if opt_sigma <= self.sigma_min * (1 + tolerance): + if results["status"] == "good": + results["status"] = "warning" + results["sigma_status"] = "at_lower_boundary" + results["warnings"].append( + f"Sigma ({opt_sigma:.6f}) is at lower boundary " + f"({self.sigma_min:.6f})" + ) + elif opt_sigma >= self.sigma_max * (1 - tolerance): + if results["status"] == "good": + results["status"] = "warning" + results["sigma_status"] = "at_upper_boundary" + results["warnings"].append( + f"Sigma ({opt_sigma:.6f}) is at upper boundary " + f"({self.sigma_max:.6f})" + ) + else: + results["sigma_status"] = "ok" + + return results + def _calc_opt_sigma( self, target_variable: np.ndarray, subset_variables: np.ndarray, iteratively_update_sigma: bool = False, - ) -> float: + ) -> tuple[np.ndarray, float | None]: """ Calculate the optimal sigma for the given target variable. @@ -684,10 +1030,24 @@ def _calc_opt_sigma( Returns ------- - float - The optimal sigma. + tuple[np.ndarray, float | None] + A tuple containing the RBF coefficients and the optimal sigma + (None if kernel doesn't require optimization). """ + # Check if kernel needs sigma optimization + if not self._needs_sigma_optimization(): + self.logger.info( + f"Kernel '{self.kernel}' does not require sigma optimization. " + "Fitting directly with dummy sigma value." + ) + # Use a dummy sigma value (1.0) for kernels that don't use it + dummy_sigma = 1.0 + rbf_coeff, _ = self._calc_rbf_coeff( + sigma=dummy_sigma, x=subset_variables, y=target_variable + ) + return rbf_coeff, None + t0 = time.time() # Initialize sigma_min, sigma_max, and d_sigma sigma_min, sigma_max, d_sigma = self.sigma_min, self.sigma_max, 0 @@ -733,9 +1093,93 @@ def _calc_opt_sigma( return rbf_coeff, opt_sigma + def _rbf_variable_variance( + self, + opt_sigma: float | None, + normalized_dataset: pd.DataFrame, + ) -> np.ndarray: + """ + Calculate prediction uncertainty based on distance to training points. + + For RBF interpolation, uncertainty increases with distance from training + data. This is a heuristic measure based on the kernel function value + at the minimum distance to training points. + + Parameters + ---------- + opt_sigma : float | None + The optimal sigma calculated for variable (None if kernel doesn't need it). + normalized_dataset : pd.DataFrame + The normalized dataset. + + Returns + ------- + np.ndarray + The prediction variance (uncertainty) for the variable. + Values are in [0, 1] range, where 0 = very certain (at training point), + 1 = very uncertain (far from training points). + """ + + # Use dummy sigma if None (for kernels that don't need it) + if opt_sigma is None: + opt_sigma = 1.0 + + norm_dataset = normalized_dataset.values + norm_subset = self.normalized_subset_data.values + + if self.row_chunks is not None: + chunks = (min(self.row_chunks, norm_dataset.shape[0]), -1) + self.logger.info(f"Using row chunks of size {chunks[0]} for variance") + else: + chunks = (norm_dataset.shape[0], -1) + + # Convert to dask arrays for large operations + d_dataset = da.from_array(norm_dataset, chunks=chunks) + d_subset = da.from_array(norm_subset) + + # Split computation into chunks + variances = [] + for i in range(0, len(d_dataset), chunks[0]): + chunk = d_dataset[i : i + chunks[0]] + + # Calculate distances from chunk to all training points + # Shape: (n_chunk, n_subset) + r_chunk = da.linalg.norm(chunk[:, None, :] - d_subset[None, :, :], axis=2) + + # Find minimum distance for each prediction point + min_distances = da.min(r_chunk, axis=1) # Shape: (n_chunk,) + + # Calculate uncertainty based on distance + # At training points (r=0), variance should be 0 + # For far points, variance should increase + # We normalize by the kernel value at r=0 to ensure + # variance=0 at training points + kernel_at_zero = self.kernel_func(0.0, opt_sigma) + kernel_values = self.kernel_func(min_distances, opt_sigma) + + # Normalize kernel values: if kernel(0) != 1, we need to adjust + # For kernels like linear where kernel(0) = 0, we handle it specially + if abs(kernel_at_zero) < 1e-10: + # Kernel returns 0 at r=0 (e.g., linear kernel) + # Use distance-based uncertainty: + # variance = min_distance / max_expected_distance + # For normalized data, max distance is typically + # around sqrt(num_dimensions) + max_expected_dist = np.sqrt(norm_subset.shape[1]) * 2 + variance_chunk = da.minimum(min_distances / max_expected_dist, 1.0) + else: + # Kernel returns non-zero at r=0 (e.g., Gaussian) + # Normalize: variance = 1 - kernel(r) / kernel(0) + normalized_kernel = kernel_values / kernel_at_zero + variance_chunk = 1.0 - normalized_kernel + + variances.append(variance_chunk.compute()) + + return np.concatenate(variances) + def _rbf_variable_interpolation( self, - opt_sigma: float, + opt_sigma: float | None, rbf_coeff: np.ndarray, normalized_dataset: pd.DataFrame, num_points_subset: int, @@ -744,8 +1188,10 @@ def _rbf_variable_interpolation( """ Interpolates the surface for a variable. - opt_sigma : float - The optimal sigma calculated for variable. + Parameters + ---------- + opt_sigma : float | None + The optimal sigma calculated for variable (None if kernel doesn't need it). rbf_coeff : np.ndarray The fitted coefficients for variable. normalized_dataset : pd.DataFrame @@ -755,10 +1201,16 @@ def _rbf_variable_interpolation( num_vars_subset : int The number of variables used in the fitting. + Returns + ------- np.ndarray The interpolated variable. """ + # Use dummy sigma if None (for kernels that don't need it) + if opt_sigma is None: + opt_sigma = 1.0 + # Calculate optimal chunk size based on memory norm_dataset = normalized_dataset.values norm_subset = self.normalized_subset_data.values @@ -787,15 +1239,30 @@ def _rbf_variable_interpolation( kernel_values = self.kernel_func(r_chunk, opt_sigma) # Compute this chunk's result + # Get linear coefficients and ensure proper shape for dot product + linear_coeffs = rbf_coeff[ + num_points_subset + 1 : num_points_subset + 1 + num_vars_subset + ] + # For single column case, linear_coeffs is 1D (num_vars_subset,) + # For multiple columns, it's also 1D (num_vars_subset,) + # We need to reshape to (num_vars_subset, 1) for matrix multiplication + # but then squeeze to get (n_chunk,) instead of (n_chunk, 1) + if linear_coeffs.ndim == 1: + linear_coeffs_2d = linear_coeffs.reshape(-1, 1) + else: + linear_coeffs_2d = linear_coeffs.T + + # Compute linear term: chunk (n_chunk, num_vars_subset) @ + # linear_coeffs_2d (num_vars_subset, 1) + # Result is (n_chunk, 1), squeeze to (n_chunk,) + linear_term = da.dot(chunk, linear_coeffs_2d) + if linear_term.ndim > 1 and linear_term.shape[1] == 1: + linear_term = linear_term.squeeze(axis=1) + chunk_result = ( rbf_coeff[num_points_subset] + da.dot(kernel_values, rbf_coeff[:num_points_subset]) - + da.dot( - chunk, - rbf_coeff[ - num_points_subset + 1 : num_points_subset + 1 + num_vars_subset - ].T, - ) + + linear_term ) # Compute and append @@ -805,8 +1272,12 @@ def _rbf_variable_interpolation( return np.concatenate(result) def _rbf_interpolate( - self, dataset: pd.DataFrame, num_workers: int = None - ) -> pd.DataFrame: + self, + dataset: pd.DataFrame, + num_workers: int = None, + target_variable: str = None, + return_std: bool = False, + ) -> pd.DataFrame | np.ndarray | tuple: """ Interpolate the dataset. @@ -816,11 +1287,22 @@ def _rbf_interpolate( The dataset to interpolate (must have same variables as subset). num_workers : int, optional The number of workers to use for the interpolation. Default is None. + target_variable : str, optional + If provided, only interpolate this target variable and return a numpy array. + Default is None (interpolate all variables). + return_std : bool, optional + If True, returns standard deviations. Default is False. Returns ------- - pd.DataFrame - The interpolated dataset (with all target variables). + pd.DataFrame | np.ndarray | tuple + If target_variable is None and return_std=False: DataFrame with predictions. + If target_variable is None and return_std=True: DataFrame with predictions + and std. + If target_variable is provided and return_std=False: numpy array with + predictions. + If target_variable is provided and return_std=True: tuple of + (predictions, std). """ normalized_dataset = self._preprocess_subset_data( @@ -831,10 +1313,62 @@ def _rbf_interpolate( num_vars_subset, num_points_subset = self.normalized_subset_data.T.shape _, num_points_dataset = normalized_dataset.T.shape - # Initialize the interpolated dataset + # If only one target variable requested, return array + if target_variable is not None: + # Get current sigma and recalculate coefficients on-the-fly + sigma = self._opt_sigmas[target_variable] + x = self.normalized_subset_data.values.T + y = self.normalized_target_data[target_variable].values + rbf_coeff, _ = self._calc_rbf_coeff(sigma=sigma, x=x, y=y) + rbf_coeff = rbf_coeff.flatten() + + interpolated_var = self._rbf_variable_interpolation( + normalized_dataset=normalized_dataset, + opt_sigma=sigma, + rbf_coeff=rbf_coeff, + num_points_subset=num_points_subset, + num_vars_subset=num_vars_subset, + ) + + if return_std: + # Calculate variance for this variable + variance = self._rbf_variable_variance( + normalized_dataset=normalized_dataset, + opt_sigma=self._opt_sigmas[target_variable], + ) + # Ensure non-negative + std = np.sqrt(np.maximum(variance, 0)) + + # Denormalize if needed + if self.is_target_normalized: + temp_df = pd.DataFrame( + {target_variable: interpolated_var}, index=dataset.index + ) + scale_factor_single = { + target_variable: self.target_scale_factor[target_variable] + } + temp_df = self.denormalize( + normalized_data=temp_df, scale_factor=scale_factor_single + ) + interpolated_var = temp_df[target_variable].values + + if return_std: + # Scale std by the same factor as the prediction + std = std * abs(scale_factor_single[target_variable]) + + if return_std: + return interpolated_var, std + return interpolated_var + + # Initialize the interpolated dataset for all variables interpolated_array = np.zeros( (num_points_dataset, len(self.target_processed_variables)) ) + std_array = None + if return_std: + std_array = np.zeros( + (num_points_dataset, len(self.target_processed_variables)) + ) # Loop through the target variables if num_workers > 1: @@ -842,18 +1376,19 @@ def _rbf_interpolate( f"Interpolating target variables using parallel execution " f"and num_workers={num_workers}" ) + # For parallel execution, we need to calculate coefficients first + # since we can't pass functions that depend on instance state easily + items = [] + for target_var in self.target_processed_variables: + sigma = self._opt_sigmas[target_var] + x = self.normalized_subset_data.values.T + y = self.normalized_target_data[target_var].values + rbf_coeff, _ = self._calc_rbf_coeff(sigma=sigma, x=x, y=y) + items.append((sigma, rbf_coeff.flatten())) + rbf_interpolated_vars = self.parallel_execute( func=self._rbf_variable_interpolation, - items=zip( - [ - self._opt_sigmas[target_var] - for target_var in self.target_processed_variables - ], - [ - self._rbf_coeffs[target_var].values - for target_var in self.target_processed_variables - ], - ), + items=items, num_workers=num_workers, normalized_dataset=normalized_dataset, num_points_subset=num_points_subset, @@ -861,19 +1396,51 @@ def _rbf_interpolate( ) for i_var, interpolated_var in rbf_interpolated_vars.items(): interpolated_array[:, i_var] = interpolated_var + if return_std: + target_var = self.target_processed_variables[i_var] + variance = self._rbf_variable_variance( + normalized_dataset=normalized_dataset, + opt_sigma=self._opt_sigmas[target_var], + ) + std_array[:, i_var] = np.sqrt(np.maximum(variance, 0)) else: for i_var, target_var in enumerate(self.target_processed_variables): self.logger.info(f"Interpolating target variable {target_var}") + # Get current sigma and recalculate coefficients on-the-fly + sigma = self._opt_sigmas[target_var] + x = self.normalized_subset_data.values.T + y = self.normalized_target_data[target_var].values + rbf_coeff, _ = self._calc_rbf_coeff(sigma=sigma, x=x, y=y) + rbf_coeff = rbf_coeff.flatten() + interpolated_var = self._rbf_variable_interpolation( normalized_dataset=normalized_dataset, - opt_sigma=self._opt_sigmas[target_var], - rbf_coeff=self._rbf_coeffs[target_var].values, + opt_sigma=sigma, + rbf_coeff=rbf_coeff, num_points_subset=num_points_subset, num_vars_subset=num_vars_subset, ) interpolated_array[:, i_var] = interpolated_var - return pd.DataFrame(interpolated_array, columns=self.target_processed_variables) + if return_std: + variance = self._rbf_variable_variance( + normalized_dataset=normalized_dataset, + opt_sigma=sigma, + ) + std_array[:, i_var] = np.sqrt(np.maximum(variance, 0)) + + result = pd.DataFrame( + interpolated_array, columns=self.target_processed_variables + ) + + if return_std: + std_df = pd.DataFrame( + std_array, + columns=[f"{var}_std" for var in self.target_processed_variables], + ) + result = pd.concat([result, std_df], axis=1) + + return result @validate_data_rbf def fit( @@ -916,15 +1483,20 @@ def fit( ----- - This function fits the RBF model to the data by: 1. Preprocessing the subset and target data. - 2. Calculating the optimal sigma for the target variables. + 2. Calculating the optimal sigma for the target variables (skipped for + kernels that don't require it: linear, cubic, quintic, thin_plate). 3. Storing the RBF coefficients and optimal sigmas. - The number of threads to use for the optimization can be specified. + - For kernels that don't require sigma optimization, the sigma value in + opt_sigmas will be None. """ self._subset_directional_variables = subset_directional_variables self._target_directional_variables = target_directional_variables self._subset_custom_scale_factor = subset_custom_scale_factor self._target_custom_scale_factor = target_custom_scale_factor + # Store original subset_data before preprocessing + self._original_subset_data = subset_data.copy() subset_data = self._preprocess_subset_data(subset_data=subset_data) target_data = self._preprocess_target_data( target_data=target_data, @@ -968,14 +1540,93 @@ def fit( rbf_coeffs[target_var] = rbf_coeff.flatten() opt_sigmas[target_var] = opt_sigma - # Store the RBF coefficients and optimal sigmas - self._rbf_coeffs = pd.DataFrame(rbf_coeffs) + # Store only optimal sigmas (coefficients will be recalculated on-the-fly) self._opt_sigmas = opt_sigmas + # Initialize training std storage (for validation) + self._training_std = {} + # Set the is_fitted attribute to True self.is_fitted = True - def predict(self, dataset: pd.DataFrame, num_workers: int = None) -> pd.DataFrame: + def validate_fit(self, verbose: bool = True) -> dict: + """ + Validate the RBF fit quality for all target variables. + + This method performs comprehensive validation checks: + - Matrix condition and rank consistency + - Training point prediction accuracy (should be exact) + - Standard deviation values at training points (should be ~0) + - Sigma value reasonableness (if kernel requires it) + + Parameters + ---------- + verbose : bool, optional + If True, print a summary of the validation results. Default is True. + + Returns + ------- + dict + Dictionary containing validation results for each target variable. + Keys are target variable names, values are dicts with: + - 'status': 'good', 'warning', or 'poor' + - 'matrix_condition': condition number + - 'matrix_rank': (actual, expected, deficiency) + - 'training_error': max absolute error at training points + - 'training_std': dict with 'max' and 'mean' std at training points + - 'sigma_status': 'ok', 'at_lower_boundary', or 'at_upper_boundary' + - 'warnings': list of warning messages + + Raises + ------ + RBFError + If the model is not fitted. + """ + + if not self.is_fitted: + raise RBFError("RBF model must be fitted before validation.") + + all_results = {} + + # Check each target variable + for target_var in self.target_processed_variables: + opt_sigma = self._opt_sigmas.get(target_var) + + # Reconstruct matrix and coefficients for validation + x = self.normalized_subset_data.values.T + y = self.normalized_target_data[target_var].values + + if opt_sigma is not None: + A = self._rbf_assemble(x=x, sigma=opt_sigma) + else: + # For kernels that don't need sigma, use dummy value + A = self._rbf_assemble(x=x, sigma=1.0) + + # Recalculate coefficients on-the-fly using current sigma + sigma_val = opt_sigma if opt_sigma else 1.0 + rbf_coeff, _ = self._calc_rbf_coeff(sigma=sigma_val, x=x, y=y) + rbf_coeff = rbf_coeff.flatten() + + # Perform comprehensive validation + results = self._validate_fit( + target_var=target_var, + opt_sigma=opt_sigma, + A=A, + rbf_coeff=rbf_coeff, + target_variable=y, + subset_variables=x, + ) + + all_results[target_var] = results + + if verbose: + self._print_validation_summary(all_results) + + return all_results + + def predict( + self, dataset: pd.DataFrame, num_workers: int = None, return_std: bool = False + ) -> pd.DataFrame: """ Predicts the data for the provided dataset. @@ -985,15 +1636,25 @@ def predict(self, dataset: pd.DataFrame, num_workers: int = None) -> pd.DataFram The dataset to predict (must have same variables than subset). num_workers : int, optional The number of workers to use for the interpolation. Default is None. + return_std : bool, optional + If True, returns standard deviations. Default is False. Returns ------- pd.DataFrame - The interpolated dataset. + The interpolated dataset. If return_std=True, includes columns + with '_std' suffix for standard deviations. + + Notes + ----- + - Coefficients are recalculated on-the-fly using current `opt_sigmas` values. + - To change sigma, modify `rbf.opt_sigmas[target_var] = new_sigma` before + calling predict(). This allows experimenting with different sigma values + without refitting. Raises ------ - ValueError + RBFError If the model is not fitted. Notes @@ -1002,6 +1663,8 @@ def predict(self, dataset: pd.DataFrame, num_workers: int = None) -> pd.DataFram 1. Reconstructing the data using the fitted coefficients. 2. Denormalizing the target data if normalize_target_data is True. 3. Calculating the degrees for the target directional variables. + - Standard deviations represent uncertainty based on distance to training + points. """ if self.is_fitted is False: @@ -1010,16 +1673,69 @@ def predict(self, dataset: pd.DataFrame, num_workers: int = None) -> pd.DataFram if num_workers is None: num_workers = self.num_workers - self.logger.info("Reconstructing data using fitted coefficients.") + self.logger.info("Reconstructing data using current sigma values.") interpolated_target = self._rbf_interpolate( - dataset=dataset, num_workers=num_workers + dataset=dataset, num_workers=num_workers, return_std=return_std ) - if self.is_target_normalized: - self.logger.info("Denormalizing target data") - interpolated_target = self.denormalize( - normalized_data=interpolated_target, - scale_factor=self.target_scale_factor, - ) + + # Handle std columns separately if needed + if return_std: + # Separate prediction and std columns + pred_cols = [ + col for col in interpolated_target.columns if not col.endswith("_std") + ] + std_cols = [ + col for col in interpolated_target.columns if col.endswith("_std") + ] + + # Denormalize predictions only + if self.is_target_normalized: + self.logger.info("Denormalizing target data") + interpolated_target[pred_cols] = self.denormalize( + normalized_data=interpolated_target[pred_cols], + scale_factor=self.target_scale_factor, + ) + # Scale std columns by their respective scale factors + for std_col in std_cols: + # Extract variable name from std column (e.g., "PC1_std" -> "PC1") + var_name = std_col.replace("_std", "") + if var_name in self.target_scale_factor: + scale_factor = self.target_scale_factor[var_name] + # Scale factor is [min, max], so range = max - min + if isinstance(scale_factor, (list, np.ndarray)): + scale_factor = abs(scale_factor[1] - scale_factor[0]) + else: + scale_factor = abs(scale_factor) + interpolated_target[std_col] = ( + interpolated_target[std_col] * scale_factor + ) + + # Store training std values if predicting at training points + # (for validation purposes) + try: + if len(dataset) == len(self._original_subset_data): + # Check if we're predicting at training points + # by comparing a few values + if all( + col in dataset.columns + for col in self._original_subset_data.columns + ): + for std_col in std_cols: + var_name = std_col.replace("_std", "") + self._training_std[var_name] = interpolated_target[ + std_col + ].values + except Exception: + # If comparison fails, just skip storing training std + pass + else: + if self.is_target_normalized: + self.logger.info("Denormalizing target data") + interpolated_target = self.denormalize( + normalized_data=interpolated_target, + scale_factor=self.target_scale_factor, + ) + for directional_variable in self.target_directional_variables: self.logger.info(f"Calculating target degrees for {directional_variable}") interpolated_target[directional_variable] = self.get_degrees_from_uv( @@ -1041,6 +1757,7 @@ def fit_predict( target_custom_scale_factor: dict = {}, num_workers: int = None, iteratively_update_sigma: bool = False, + return_std: bool = False, ) -> pd.DataFrame: """ Fits the model to the subset and predicts the interpolated dataset. @@ -1067,11 +1784,14 @@ def fit_predict( The number of workers to use for the optimization. Default is None. iteratively_update_sigma : bool, optional Whether to iteratively update the sigma parameter. Default is False. + return_std : bool, optional + If True, returns standard deviations. Default is False. Returns ------- pd.DataFrame - The interpolated dataset. + The interpolated dataset. If return_std=True, includes columns + with '_std' suffix for standard deviations. Notes ----- @@ -1093,212 +1813,217 @@ def fit_predict( iteratively_update_sigma=iteratively_update_sigma, ) - return self.predict(dataset=dataset, num_workers=num_workers) + return self.predict( + dataset=dataset, num_workers=num_workers, return_std=return_std + ) - def explain( + def plot_partial_dependence( self, - dataset: pd.DataFrame, + feature_name: str, target_variable: str = None, - num_samples: int = 100, - max_background_samples: int = 100, - ): + n_points: int = 100, + show_std: bool = False, + ) -> tuple[plt.Figure, plt.Axes]: """ - Explain RBF predictions using SHAP (SHapley Additive exPlanations) values. + Plot partial dependence of a target variable on a single input feature. - This method provides comprehensive model interpretability by automatically - generating interactive SHAP visualizations for each target variable. It uses - the training subset data as background. + This creates a plot showing how the predicted target variable changes + as one input feature varies, while other features are held constant. + The RBF interpolation curve will pass exactly through all training points + (since RBF is an exact interpolator). Parameters ---------- - dataset : pd.DataFrame - The test dataset to explain predictions for. Must have the same variables - as the subset_data used for fitting. + feature_name : str + Name of the input feature from subset_data to vary. target_variable : str, optional - The target variable to explain. If None, explains all target variables. + Target variable to plot. If None, plots the first target variable. Default is None. - num_samples : int, optional - Number of samples to use for SHAP approximation. Higher values give - more accurate results but are slower. Default is 100. - Recommended: 100-500 for good balance between speed and accuracy. - max_background_samples : int, optional - Maximum number of background samples to use. The subset data will be - automatically summarized using k-means if it exceeds this value. - Default is 100. + n_points : int, optional + Number of points to evaluate along the feature range. Default is 100. + show_std : bool, optional + If True, shows standard deviation as a shaded uncertainty band. + Default is False. Returns ------- - dict - Dictionary containing explanation results for each target variable: - - 'explanation': SHAP Explanation object - - 'shap_values': numpy array of SHAP values - - 'expected_value': base/expected prediction value - - 'feature_importance': pandas Series with mean absolute SHAP values - - 'summary_stats': dictionary with summary statistics + tuple + (fig, ax) matplotlib figure and axes objects. Raises ------ - ImportError - If SHAP is not installed. RBFError If the model is not fitted. + ValueError + If feature_name is not in subset_data or target_variable is invalid. """ - try: - import logging - - import shap - - # Suppress SHAP INFO logs (keep progress bars) - shap_logger = logging.getLogger("shap") - shap_logger.setLevel(logging.WARNING) + if not self.is_fitted: + raise RBFError("RBF model must be fitted before plotting.") - shap.initjs() # Initialize JavaScript for interactive plots - except ImportError: - raise ImportError( - "SHAP is required for explain method. Install with: pip install shap" + # Validate feature name + if feature_name not in self._original_subset_data.columns: + raise ValueError( + f"feature_name '{feature_name}' not found in subset_data. " + f"Available features: {self._original_subset_data.columns.tolist()}" ) - if not self.is_fitted: - raise RBFError("RBF model must be fitted before explaining.") - - # Determine which target variables to explain + # Select target variable if target_variable is None: - target_vars = self.target_processed_variables - else: - if target_variable not in self.target_processed_variables: - raise ValueError( - f"target_variable '{target_variable}' not found in " - f"target_processed_variables: {self.target_processed_variables}" - ) - target_vars = [target_variable] + target_variable = self.target_processed_variables[0] + elif target_variable not in self.target_processed_variables: + raise ValueError( + f"target_variable '{target_variable}' not found in " + f"target_processed_variables: {self.target_processed_variables}" + ) - # Prepare background data from subset (automatic) - background = self.subset_data.copy() + # Get predictions at the actual training points (using all original features) + # This ensures the curve passes exactly through training points since RBF + # is exact + self.logger.info( + f"Computing partial dependence for {feature_name} -> {target_variable}" + ) + training_results = self.predict( + dataset=self._original_subset_data, return_std=show_std + ) - # Summarize background data for efficiency if it's too large - if len(background) > max_background_samples: - self.logger.info( - f"Summarizing background data from {len(background)} " - f"to {max_background_samples} samples using k-means" + if show_std: + training_predictions = training_results[target_variable].values + training_std = training_results[f"{target_variable}_std"].values + else: + training_predictions = training_results[target_variable].values + training_std = None + + # Get feature values, predictions, and actual target values + training_x = self._original_subset_data[feature_name].values + training_y = training_predictions + # Get actual target values for comparison + # Check if target_variable exists in _target_data (might be processed) + if target_variable in self._target_data.columns: + training_y_actual = self._target_data[target_variable].values + else: + # If not found, try to get from normalized_target_data + # This handles cases where variable might have been processed + # For exact comparison, we should use the original target values + # If target was normalized, we need to check the original data + self.logger.warning( + f"Target variable '{target_variable}' not found in _target_data. " + "Using predictions as reference." ) - n_clusters = min(max_background_samples, len(background)) - background_summary = shap.kmeans(background, n_clusters) + training_y_actual = training_y.copy() + + # Sort by feature_name for smooth line plotting + sort_idx = np.argsort(training_x) + training_x_sorted = training_x[sort_idx] + training_y_sorted = training_y[sort_idx] + training_y_actual_sorted = training_y_actual[sort_idx] + if training_std is not None: + training_std_sorted = training_std[sort_idx] + + # Create additional points for smoother visualization + # Use training data range + feature_min = training_x_sorted.min() + feature_max = training_x_sorted.max() + feature_range = np.linspace(feature_min, feature_max, n_points) + + # Create base DataFrame with median values for other features + base_data = self._original_subset_data.copy() + base_data.drop(columns=[feature_name], inplace=True) + base_data_median = base_data.median() + + # Create smooth grid for visualization + smooth_data = pd.DataFrame({feature_name: feature_range}) + for col in base_data_median.index: + smooth_data[col] = base_data_median.loc[col] + + # Get predictions on smooth grid + smooth_results = self.predict(dataset=smooth_data, return_std=show_std) + + if show_std: + smooth_predictions = smooth_results[target_variable].values + smooth_std = smooth_results[f"{target_variable}_std"].values else: - n_clusters = len(background) - background_summary = background - - explanations = {} - - for target_var in target_vars: - self.logger.info( - f"Explaining predictions for target variable: {target_var}" + smooth_predictions = smooth_results[target_variable].values + smooth_std = None + + # Create plot + fig, ax = plt.subplots(figsize=(10, 6)) + + # Plot uncertainty band if show_std is True + if show_std and smooth_std is not None: + ax.fill_between( + feature_range, + smooth_predictions - smooth_std, + smooth_predictions + smooth_std, + alpha=0.3, + color="blue", + label="±1 std uncertainty", + zorder=0, ) - # Create a prediction function for this specific target variable - # This wrapper is needed because SHAP expects a function that takes - # numpy arrays and returns predictions - def predict_fn(X): - """ - Predict the target variable for SHAP explanation. - - Parameters - ---------- - X : np.ndarray - Input features in normalized space (shape: n_samples, n_features) - - Returns - ------- - np.ndarray - Predictions for the target variable (shape: n_samples,) - """ - - # Convert to DataFrame with proper column names - dataset = pd.DataFrame(X, columns=self.subset_processed_variables) + # Plot the smooth interpolation curve (partial dependence with median values) + ax.plot( + feature_range, + smooth_predictions, + "b-", + linewidth=3, + label="RBF interpolation", + zorder=1, + ) - # Get predictions for all targets - predictions = self.predict(dataset=dataset) + # Plot the actual target values (ground truth) + ax.scatter( + training_x_sorted, + training_y_actual_sorted, + c="red", + marker="o", + s=100, + alpha=0.7, + label="Actual target values", + zorder=2, + clip_on=False, + ) - # Return only the target variable we're explaining - return predictions[target_var] + # Plot the predicted training data points (should match actual values) + ax.scatter( + training_x, + training_y, + c="black", + marker="+", + s=150, + linewidths=2.5, + label="Predicted target values", + zorder=3, + clip_on=False, + ) - # Create SHAP explainer - self.logger.info( - f"Creating SHAP KernelExplainer with {n_clusters} " - f"background samples and {num_samples} evaluation samples" + # Optionally show std at training points + if show_std and training_std is not None: + ax.errorbar( + training_x_sorted, + training_y_sorted, + yerr=training_std_sorted, + fmt="none", + color="gray", + alpha=0.5, + capsize=3, + capthick=1, + zorder=4, ) - explainer = shap.KernelExplainer(predict_fn, background_summary) - - # Calculate SHAP values using normalized data - self.logger.info(f"Calculating SHAP values for {len(dataset)} samples...") - shap_values = explainer.shap_values(dataset.values, nsamples=num_samples) - - # Ensure shap_values is 2D (handle both single and multiple samples) - shap_values = np.array(shap_values) - if shap_values.ndim == 1: - shap_values = shap_values.reshape(1, -1) - - # Create SHAP Explanation object using original dataset for plotting - explanation = shap.Explanation( - values=shap_values, - base_values=explainer.expected_value, - data=dataset.values, - feature_names=dataset.columns.tolist(), - ) - - # Calculate feature importance (mean absolute SHAP values) - feature_importance = pd.Series( - np.abs(shap_values).mean(axis=0), - index=self.subset_processed_variables, - name="mean_abs_shap", - ).sort_values(ascending=False) - - # Calculate summary statistics - summary_stats = { - "n_samples": len(dataset), - "n_features": len(self.subset_processed_variables), - "expected_value": float(explainer.expected_value), - "mean_prediction": float( - shap_values.sum(axis=1).mean() + explainer.expected_value - ), - "shap_values_range": { - "min": float(shap_values.min()), - "max": float(shap_values.max()), - "mean": float(shap_values.mean()), - "std": float(shap_values.std()), - }, - "top_features": feature_importance.head(10).to_dict(), - } - # Generate single comprehensive plot - self.logger.info(f"Generating SHAP summary plot for {target_var}") - - # Print minimal essential statistics - print(f"SHAP Explanation: {target_var}") - print(f" Baseline: {summary_stats['expected_value']:.4f}") - print(f" Mean prediction: {summary_stats['mean_prediction']:.4f}") - top_features = ", ".join(feature_importance.head(5).index.tolist()) - print(f" Top 5 features: {top_features}") - - # Single comprehensive summary plot using original dataset - shap.summary_plot(shap_values, dataset, show=True) - - # Store comprehensive explanation - explanations[target_var] = { - "explanation": explanation, - "shap_values": shap_values, - "expected_value": explainer.expected_value, - "feature_importance": feature_importance, - "summary_stats": summary_stats, - "explainer": explainer, - "data": dataset, # Store original dataset - } + ax.set_xlabel(f"input, {feature_name}", fontsize=12) + ax.set_ylabel(f"output, {target_variable}", fontsize=12) + title = f"Partial Dependence: {feature_name} → {target_variable}" + if show_std: + title += " (with uncertainty)" + ax.set_title(title, fontsize=14, fontweight="bold") + ax.grid(True, alpha=0.3, linestyle="--") + ax.legend(loc="best", framealpha=0.9) - # Return single explanation if only one target variable - if len(explanations) == 1: - return list(explanations.values())[0] + plt.tight_layout() + plt.show() - return explanations + return fig, ax def basic_rbf_metric(df_true: pd.DataFrame, df_pred: pd.DataFrame) -> float: diff --git a/bluemath_tk/interpolation/rbf_scipy.py b/bluemath_tk/interpolation/rbf_scipy.py deleted file mode 100644 index ea7258a..0000000 --- a/bluemath_tk/interpolation/rbf_scipy.py +++ /dev/null @@ -1,790 +0,0 @@ -import copy -import time -from typing import List - -import numpy as np -import pandas as pd -from scipy.interpolate import RBFInterpolator -from scipy.optimize import fmin, fminbound -from sklearn.metrics import mean_squared_error -from sklearn.model_selection import KFold - -from ..core.decorators import validate_data_rbf -from ._base_interpolation import BaseInterpolation - - -class RBFError(Exception): - """ - Custom exception for RBF class. - """ - - def __init__(self, message: str = "RBF error occurred."): - self.message = message - super().__init__(self.message) - - -class RBF(BaseInterpolation): - """ - Radial Basis Function (RBF) interpolation model. - - Here, scipy's RBFInterpolator is used to interpolate the data. - https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.RBFInterpolator.html - - Warnings - -------- - - This class is a Beta, results may not be accurate. - - See Also - -------- - bluemath_tk.interpolation.RBF : - The stable version for this model. - - Attributes - ---------- - sigma_min : float - The minimum value for the sigma parameter. - This value might change in the optimization process. - sigma_max : float - The maximum value for the sigma parameter. - This value might change in the optimization process. - sigma_opt : float - The optimal value for the sigma parameter. - kernel : str - Type of RBF. This should be one of - - - 'linear' : ``-r`` - - 'thin_plate_spline' : ``r**2 * log(r)`` - - 'cubic' : ``r**3`` - - 'quintic' : ``-r**5`` - - 'multiquadric' : ``-sqrt(1 + r**2)`` - - 'inverse_multiquadric' : ``1/sqrt(1 + r**2)`` - - 'inverse_quadratic' : ``1/(1 + r**2)`` - - 'gaussian' : ``exp(-r**2)`` - - smoothing : float or (npoints, ) array_like - Smoothing parameter. The interpolant perfectly fits the data when this - is set to 0. For large values, the interpolant approaches a least - squares fit of a polynomial with the specified degree. - degree : int - Degree of the added polynomial. For some RBFs the interpolant may not - be well-posed if the polynomial degree is too small. Those RBFs and - their corresponding minimum degrees are - - - 'multiquadric' : 0 - - 'linear' : 0 - - 'thin_plate_spline' : 1 - - 'cubic' : 1 - - 'quintic' : 2 - - The default value is the minimum degree for `kernel` or 0 if there is - no minimum degree. Set this to -1 for no added polynomial. - neighbors : int - If specified, the value of the interpolant at each evaluation point - will be computed using only this many nearest data points. All the data - points are used by default. - rbfs : dict - Dict with RBFInterpolator instances. - subset_data : pd.DataFrame - The subset data used to fit the model. - normalized_subset_data : pd.DataFrame - The normalized subset data used to fit the model. - target_data : pd.DataFrame - The target data used to fit the model. - normalized_target_data : pd.DataFrame - The normalized target data used to fit the model. - This attribute is only set if normalize_target_data is True in the fit method. - subset_directional_variables : List[str] - The subset directional variables. - target_directional_variables : List[str] - The target directional variables. - subset_processed_variables : List[str] - The subset processed variables. - target_processed_variables : List[str] - The target processed variables. - subset_custom_scale_factor : dict - The custom scale factor for the subset data. - target_custom_scale_factor : dict - The custom scale factor for the target data. - subset_scale_factor : dict - The scale factor for the subset data. - target_scale_factor : dict - The scale factor for the target data. - rbf_coeffs : pd.DataFrame - The RBF coefficients for the target variables. - opt_sigmas : dict - The optimal sigmas for the target variables. - - Methods - ------- - fit(...) : - Fits the model to the data. - predict(...) : - Predicts the data for the provided dataset. - fit_predict(...) : - Fits the model to the subset and predicts the interpolated dataset. - - References - ---------- - .. [1] Fasshauer, G., 2007. Meshfree Approximation Methods with Matlab. - World Scientific Publishing Co. - - .. [2] http://amadeus.math.iit.edu/~fass/603_ch3.pdf - - .. [3] Wahba, G., 1990. Spline Models for Observational Data. SIAM. - - .. [4] http://pages.stat.wisc.edu/~wahba/stat860public/lect/lect8/lect8.pdf - - Notes - ----- - .. versionadded:: 1.0.3 - TODO: For the moment, this class only supports optimization for one parameter kernels. - For this reason, we only have sigma as the parameter to optimize. - This sigma refers to the sigma parameter in the Gaussian kernel (but is used for all kernels). - """ - - def __init__( - self, - sigma_min: float = 0.001, - sigma_max: float = 1.0, - sigma_opt: float = None, - kernel: str = "thin_plate_spline", - smoothing: float = 0.0, - degree: int = None, - neighbors: int = None, - ): - """ - Initializes the RBF model. - - Parameters - ---------- - sigma_min : float, optional - The minimum value for the sigma parameter. Default is 0.001. - sigma_max : float, optional - The maximum value for the sigma parameter. Default is 1.0. - sigma_opt : float, optional - The optimal value for the sigma parameter. Default is None. - kernel : str, optional - Type of RBF. Default is 'thin_plate_spline'. - smoothing : float, optional - Smoothing parameter. Default is 0.0. - degree : int, optional - Degree of the added polynomial. Default is None. - neighbors : int, optional - If specified, the value of the interpolant at each evaluation point will be - computed using only this many nearest data points. Default is None. - """ - - super().__init__() - self.set_logger_name(name=self.__class__.__name__) - if not isinstance(sigma_min, float) or sigma_min < 0: - raise ValueError("sigma_min must be a positive float.") - self._sigma_min = sigma_min - if not isinstance(sigma_max, float) or sigma_max < sigma_min: - raise ValueError( - "sigma_max must be a positive float greater than sigma_min." - ) - self._sigma_max = sigma_max - if sigma_opt is not None: - if not isinstance(sigma_opt, float) or sigma_opt < 0: - raise ValueError("sigma_opt must be a positive float.") - self._sigma_opt = sigma_opt - if not isinstance(kernel, str): - raise ValueError("kernel must be a string.") - self._kernel = kernel - if not isinstance(smoothing, float): - raise ValueError("smoothing must be a float.") - self._smoothing = smoothing - if not isinstance(degree, int) and degree is not None: - raise ValueError("degree must be an integer.") - self._degree = degree - if not isinstance(neighbors, int) and neighbors is not None: - raise ValueError("neighbors must be an integer.") - self._neighbors = neighbors - self._rbfs: dict = {} # Dict with RBFInterpolator instances - # Below, we initialize the attributes that will be set in the fit method - self.is_fitted: bool = False - self.is_target_normalized: bool = False - self._subset_data: pd.DataFrame = pd.DataFrame() - self._normalized_subset_data: pd.DataFrame = pd.DataFrame() - self._target_data: pd.DataFrame = pd.DataFrame() - self._normalized_target_data: pd.DataFrame = pd.DataFrame() - self._subset_directional_variables: List[str] = [] - self._target_directional_variables: List[str] = [] - self._subset_processed_variables: List[str] = [] - self._target_processed_variables: List[str] = [] - self._subset_custom_scale_factor: dict = {} - self._target_custom_scale_factor: dict = {} - self._subset_scale_factor: dict = {} - self._target_scale_factor: dict = {} - self._rbf_coeffs: pd.DataFrame = pd.DataFrame() - self._opt_sigmas: dict = {} - - @property - def sigma_min(self) -> float: - return self._sigma_min - - @property - def sigma_max(self) -> float: - return self._sigma_max - - @property - def sigma_opt(self) -> float: - return self._sigma_opt - - @property - def kernel(self) -> str: - return self._kernel - - @property - def smoothing(self) -> float: - return self._smoothing - - @property - def degree(self) -> int: - return self._degree - - @property - def neighbors(self) -> int: - return self._neighbors - - @property - def rbfs(self) -> dict: - return self._rbfs - - @property - def subset_data(self) -> pd.DataFrame: - return self._subset_data - - @property - def normalized_subset_data(self) -> pd.DataFrame: - return self._normalized_subset_data - - @property - def target_data(self) -> pd.DataFrame: - return self._target_data - - @property - def normalized_target_data(self) -> pd.DataFrame: - if self._normalized_target_data.empty: - raise ValueError("Target data is not normalized.") - return self._normalized_target_data - - @property - def subset_directional_variables(self) -> List[str]: - return self._subset_directional_variables - - @property - def target_directional_variables(self) -> List[str]: - return self._target_directional_variables - - @property - def subset_processed_variables(self) -> List[str]: - return self._subset_processed_variables - - @property - def target_processed_variables(self) -> List[str]: - return self._target_processed_variables - - @property - def subset_custom_scale_factor(self) -> dict: - return self._subset_custom_scale_factor - - @property - def target_custom_scale_factor(self) -> dict: - return self._target_custom_scale_factor - - @property - def subset_scale_factor(self) -> dict: - return self._subset_scale_factor - - @property - def target_scale_factor(self) -> dict: - return self._target_scale_factor - - @property - def rbf_coeffs(self) -> pd.DataFrame: - return self._rbf_coeffs - - @property - def opt_sigmas(self) -> dict: - if not self._opt_sigmas: - raise ValueError("Specified kernel does not require optimization.") - return self._opt_sigmas - - def _preprocess_subset_data( - self, subset_data: pd.DataFrame, is_fit: bool = True - ) -> pd.DataFrame: - """ - This function preprocesses the subset data. - - Parameters - ---------- - subset_data : pd.DataFrame - The subset data to preprocess (could be a dataset to predict). - is_fit : bool, optional - Whether the data is to fit or not. Default is True. - - Returns - ------- - pd.DataFrame - The preprocessed subset data. - - Raises - ------ - ValueError - If the subset contains NaNs. - - Notes - ----- - - This function preprocesses the subset data by: - - Checking for NaNs. - - Preprocessing directional variables. - - Normalizing the data. - """ - - # Make copies to avoid modifying the original data - subset_data = subset_data.copy() - - self.logger.info("Checking for NaNs in subset data") - subset_data = self.check_nans(data=subset_data, raise_error=True) - - self.logger.info("Preprocessing subset data") - for directional_variable in self.subset_directional_variables: - var_u_component, var_y_component = self.get_uv_components( - x_deg=subset_data[directional_variable].values - ) - subset_data[f"{directional_variable}_u"] = var_u_component - subset_data[f"{directional_variable}_v"] = var_y_component - # Drop the original directional variable in subset_data - subset_data.drop(columns=[directional_variable], inplace=True) - self._subset_processed_variables = list(subset_data.columns) - - self.logger.info("Normalizing subset data") - normalized_subset_data, subset_scale_factor = self.normalize( - data=subset_data, - custom_scale_factor=self.subset_custom_scale_factor - if is_fit - else self.subset_scale_factor, - ) - - self.logger.info("Subset data preprocessed successfully") - - if is_fit: - self._subset_data = subset_data - self._normalized_subset_data = normalized_subset_data - self._subset_scale_factor = subset_scale_factor - - return normalized_subset_data.copy() - - def _preprocess_target_data( - self, - target_data: pd.DataFrame, - normalize_target_data: bool = True, - ) -> pd.DataFrame: - """ - This function preprocesses the target data. - - Parameters - ---------- - target_data : pd.DataFrame - The target data to preprocess. - normalize_target_data : bool, optional - Whether to normalize the target data. Default is True. - - Returns - ------- - pd.DataFrame - The preprocessed target data. - - Raises - ------ - ValueError - If the target contains NaNs. - - Notes - ----- - - This function preprocesses the target data by: - - Checking for NaNs. - - Preprocessing directional variables. - - Normalizing the data. - """ - - # Make copies to avoid modifying the original data - target_data = target_data.copy() - - self.logger.info("Checking for NaNs in target data") - target_data = self.check_nans(data=target_data, raise_error=True) - - self.logger.info("Preprocessing target data") - for directional_variable in self.target_directional_variables: - var_u_component, var_y_component = self.get_uv_components( - x_deg=target_data[directional_variable].values - ) - target_data[f"{directional_variable}_u"] = var_u_component - target_data[f"{directional_variable}_v"] = var_y_component - # Drop the original directional variable in target_data - target_data.drop(columns=[directional_variable], inplace=True) - self._target_processed_variables = list(target_data.columns) - - if normalize_target_data: - self.logger.info("Normalizing target data") - normalized_target_data, target_scale_factor = self.normalize( - data=target_data, - custom_scale_factor=self.target_custom_scale_factor, - ) - self.is_target_normalized = True - self._target_data = target_data.copy() - self._normalized_target_data = normalized_target_data.copy() - self._target_scale_factor = target_scale_factor.copy() - self.logger.info("Target data preprocessed successfully") - return normalized_target_data.copy() - - else: - self.is_target_normalized = False - self._target_data = target_data.copy() - self._normalized_target_data = pd.DataFrame() - self._target_scale_factor = {} - self.logger.info("Target data preprocessed successfully") - return target_data.copy() - - def _cost_sigma( - self, sigma: float, x: np.ndarray, y: np.ndarray, k: int = 5 - ) -> float: - """ - Calculate the cost for a given sigma using K-Fold cross-validation. - - Parameters - ---------- - sigma : float - The sigma parameter for the kernel. - x : np.ndarray - The input data. - y : np.ndarray - The target data. - k : int, optional - The number of folds for cross-validation. Default is 5. - - Returns - ------- - float - The total cost for the RBF interpolation. - """ - - kf = KFold(n_splits=k) - total_cost = 0.0 - - for train_index, val_index in kf.split(x): - x_train, x_val = x[train_index], x[val_index] - y_train, y_val = y[train_index], y[val_index] - - # Instantiate the RBFInterpolator - rbf = RBFInterpolator( - y=x_train, - d=y_train, - neighbors=self.neighbors, - smoothing=self.smoothing, - kernel=self.kernel, - epsilon=sigma, - degree=self.degree, - ) - - # Predict on the validation set - predicted_y = rbf(x_val) - - # Calculate the cost (mean squared error) - cost = mean_squared_error(y_val, predicted_y) - total_cost += cost - - return total_cost / k - - def _calc_opt_sigma( - self, - target_variable: np.ndarray, - subset_variables: np.ndarray, - iteratively_update_sigma: bool = False, - ) -> RBFInterpolator: - """ - This function calculates the optimal sigma for the given target variable. - - Parameters - ---------- - target_variable : np.ndarray - The target variable to interpolate. - subset_variables : np.ndarray - The subset variables used to interpolate. - iteratively_update_sigma : bool, optional - Whether to iteratively update the sigma parameter. Default is False. - - Returns - ------- - float - The optimal sigma. - """ - - t0 = time.time() - - # Optimize sigma using fminbound or fmin - if self.sigma_opt is not None: - opt_sigma = fmin( - func=self._cost_sigma, - x0=self.sigma_opt, - args=(subset_variables, target_variable), - disp=0, - )[-1] - if iteratively_update_sigma: - self._sigma_opt = opt_sigma - else: - opt_sigma = fminbound( - func=self._cost_sigma, - x1=self.sigma_min, - x2=self.sigma_max, - args=(subset_variables, target_variable), - disp=0, - ) - - # Save the fitted RBF for the optimal sigma - rbf = RBFInterpolator( - y=subset_variables, - d=target_variable, - neighbors=self.neighbors, - smoothing=self.smoothing, - kernel=self.kernel, - epsilon=opt_sigma, - degree=self.degree, - ) - - # Calculate the time taken to optimize sigma - t1 = time.time() - self.logger.info(f"Optimal sigma: {opt_sigma} - Time: {t1 - t0:.2f} seconds") - - return rbf, opt_sigma - - @validate_data_rbf - def fit( - self, - subset_data: pd.DataFrame, - target_data: pd.DataFrame, - subset_directional_variables: List[str] = [], - target_directional_variables: List[str] = [], - subset_custom_scale_factor: dict = {}, - normalize_target_data: bool = True, - target_custom_scale_factor: dict = {}, - num_threads: int = None, - iteratively_update_sigma: bool = False, - ) -> None: - """ - Fits the model to the data. - - Parameters - ---------- - subset_data : pd.DataFrame - The subset data used to fit the model. - target_data : pd.DataFrame - The target data used to fit the model. - subset_directional_variables : List[str], optional - The subset directional variables. Default is []. - target_directional_variables : List[str], optional - The target directional variables. Default is []. - subset_custom_scale_factor : dict, optional - The custom scale factor for the subset data. Default is {}. - normalize_target_data : bool, optional - Whether to normalize the target data. Default is True. - target_custom_scale_factor : dict, optional - The custom scale factor for the target data. Default is {}. - num_threads : int, optional - The number of threads to use for the optimization. Default is None. - iteratively_update_sigma : bool, optional - Whether to iteratively update the sigma parameter. Default is False. - - Notes - ----- - - This function fits the RBF model to the data by: - 1. Preprocessing the subset and target data. - 2. Calculating the optimal sigma for the target variables. - 3. Storing the RBF coefficients and optimal sigmas. - - The number of threads to use for the optimization can be specified. - """ - - if num_threads is not None: - self.set_num_processors_to_use(num_processors=num_threads) - self.logger.info(f"Using {num_threads} threads for optimization.") - - self._subset_directional_variables = subset_directional_variables - self._target_directional_variables = target_directional_variables - self._subset_custom_scale_factor = subset_custom_scale_factor - self._target_custom_scale_factor = target_custom_scale_factor - subset_data = self._preprocess_subset_data(subset_data=subset_data) - target_data = self._preprocess_target_data( - target_data=target_data, - normalize_target_data=normalize_target_data, - ) - - self.logger.info("Fitting RBF model to the data") - # RBF fitting for all variables - rbf_coeffs, opt_sigmas = {}, {} - - # Optimize sigma for each target variable - for target_var in target_data.columns: - self.logger.info(f"Fitting RBF for variable {target_var}") - target_var_values = target_data[target_var].values - if ( - self.kernel == "linear" - or self.kernel == "cubic" - or self.kernel == "quintic" - or self.kernel == "thin_plate_spline" - ): - rbf = RBFInterpolator( - y=subset_data.values, - d=target_var_values, - neighbors=self.neighbors, - smoothing=self.smoothing, - kernel=self.kernel, - degree=self.degree, - ) - opt_sigma = None - else: - rbf, opt_sigma = self._calc_opt_sigma( - target_variable=target_var_values, - subset_variables=subset_data.values, - iteratively_update_sigma=iteratively_update_sigma, - ) - self.rbfs[target_var] = copy.deepcopy(rbf) - rbf_coeffs[target_var] = rbf._coeffs.flatten() - opt_sigmas[target_var] = opt_sigma - - # Store the RBF coefficients and optimal sigmas - self._rbf_coeffs = pd.DataFrame(rbf_coeffs) - self._opt_sigmas = opt_sigmas - - # Set the is_fitted attribute to True - self.is_fitted = True - - def predict(self, dataset: pd.DataFrame) -> pd.DataFrame: - """ - Predicts the data for the provided dataset. - - Parameters - ---------- - dataset : pd.DataFrame - The dataset to predict (must have same variables than subset). - - Returns - ------- - pd.DataFrame - The interpolated dataset. - - Raises - ------ - ValueError - If the model is not fitted. - - Notes - ----- - - This function predicts the data by: - 1. Reconstructing the data using the fitted coefficients. - 2. Denormalizing the target data if normalize_target_data is True. - 3. Calculating the degrees for the target directional variables. - """ - - if self.is_fitted is False: - raise RBFError("RBF model must be fitted before predicting.") - - self.logger.info("Reconstructing data using fitted coefficients.") - normalized_dataset = self._preprocess_subset_data( - subset_data=dataset, is_fit=False - ) - - # Create an empty array to store the interpolated target data - interpolated_target_array = np.zeros( - (normalized_dataset.shape[0], len(self.target_processed_variables)) - ) - for target_var in self.target_processed_variables: - self.logger.info(f"Predicting target variable {target_var}") - rbf = self.rbfs[target_var] - interpolated_target_array[ - :, self.target_processed_variables.index(target_var) - ] = rbf(normalized_dataset.values) - interpolated_target = pd.DataFrame( - data=interpolated_target_array, columns=self.target_processed_variables - ) - - # Denormalize the target data if normalize_target_data is True - if self.is_target_normalized: - self.logger.info("Denormalizing target data") - interpolated_target = self.denormalize( - normalized_data=interpolated_target, - scale_factor=self.target_scale_factor, - ) - - # Calculate the degrees for the target directional variables - for directional_variable in self.target_directional_variables: - self.logger.info(f"Calculating target degrees for {directional_variable}") - interpolated_target[directional_variable] = self.get_degrees_from_uv( - xu=interpolated_target[f"{directional_variable}_u"].values, - xv=interpolated_target[f"{directional_variable}_v"].values, - ) - - return interpolated_target - - def fit_predict( - self, - subset_data: pd.DataFrame, - target_data: pd.DataFrame, - dataset: pd.DataFrame, - subset_directional_variables: List[str] = [], - target_directional_variables: List[str] = [], - subset_custom_scale_factor: dict = {}, - normalize_target_data: bool = True, - target_custom_scale_factor: dict = {}, - num_threads: int = None, - iteratively_update_sigma: bool = False, - ) -> pd.DataFrame: - """ - Fits the model to the subset and predicts the interpolated dataset. - - Parameters - ---------- - subset_data : pd.DataFrame - The subset data used to fit the model. - target_data : pd.DataFrame - The target data used to fit the model. - dataset : pd.DataFrame - The dataset to predict (must have same variables than subset). - subset_directional_variables : List[str], optional - The subset directional variables. Default is []. - target_directional_variables : List[str], optional - The target directional variables. Default is []. - subset_custom_scale_factor : dict, optional - The custom scale factor for the subset data. Default is {}. - normalize_target_data : bool, optional - Whether to normalize the target data. Default is True. - target_custom_scale_factor : dict, optional - The custom scale factor for the target data. Default is {}. - num_threads : int, optional - The number of threads to use for the optimization. Default is None. - iteratively_update_sigma : bool, optional - Whether to iteratively update the sigma parameter. Default is False. - - Returns - ------- - pd.DataFrame - The interpolated dataset. - - Notes - ----- - - This function fits the model to the subset and predicts the interpolated dataset. - """ - - self.fit( - subset_data=subset_data, - target_data=target_data, - subset_directional_variables=subset_directional_variables, - target_directional_variables=target_directional_variables, - subset_custom_scale_factor=subset_custom_scale_factor, - normalize_target_data=normalize_target_data, - target_custom_scale_factor=target_custom_scale_factor, - num_threads=num_threads, - iteratively_update_sigma=iteratively_update_sigma, - ) - - return self.predict(dataset=dataset) diff --git a/pyproject.toml b/pyproject.toml index 7f6ce63..7c00b91 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -96,7 +96,6 @@ select = [ "N", # pep8-naming "UP", # pyupgrade ] - # Ignore some docstring rules (start lenient, tighten later) # Focus on missing docstrings first, style issues can be auto-fixed later ignore = [ diff --git a/tests/data/interpolation/predictor.csv b/tests/data/interpolation/predictor.csv new file mode 100644 index 0000000..0937d2f --- /dev/null +++ b/tests/data/interpolation/predictor.csv @@ -0,0 +1,1201 @@ +,Qp,Qb,Tp,Tau_ss_d,Sp,Sb,CM,Tau,wind,wind_dir +0,317.5206666666666,23.52191666666667,24.0,2.0,0.19045605867636878,0.10237087867888717,2.481998644056703,3.0,8.639639854431152,261.2489013671875 +1,362.2166666666667,140.87949999999998,9.0,-3.0,0.305436758185177,0.07214044014688897,3.127001355943297,1.0,12.154000282287598,290.625 +2,59.52416666666668,9.634999999999998,21.0,16.0,0.025957007361596503,-0.10281183213612666,4.3229984180661525,6.0,6.856968879699707,290.61334228515625 +3,317.7516666666667,44.426666666666655,24.0,24.0,0.3640293836659925,0.2022875712873033,3.426998644056703,7.0,10.751829147338867,290.390380859375 +4,270.0975,76.83083333333333,16.0,7.0,0.032076945830784645,-0.12478939879259243,4.418001355943297,11.0,12.323180198669434,285.22564697265625 +5,309.5183333333334,76.87666666666668,18.0,24.0,0.21966071594249664,0.21966071594249664,2.284998644056703,4.0,9.705472946166992,306.81915283203125 +6,39.62083333333333,17.245833333333334,21.0,21.0,0.14918405563217138,0.02742344593002527,4.041001355943298,13.0,5.55661678314209,309.66632080078125 +7,50.5875,8.760000000000002,24.0,-7.0,0.19065923564379145,-0.05041724138409151,3.7860013559432972,1.0,10.015145301818848,280.36981201171875 +8,39.498333333333335,18.01583333333333,23.0,11.0,0.030808939530948896,-0.0581284695910307,4.310001355943298,11.0,7.532832622528076,285.96783447265625 +9,37.81166666666666,0.91,24.0,-22.0,0.1429730453020993,0.06863716221766447,4.158001581933847,11.0,5.047021865844727,281.2979736328125 +10,48.73416666666666,11.168333333333331,11.0,24.0,-0.008583333333333274,-0.008583333333333274,4.722001355943298,10.0,7.947399616241455,286.475341796875 +11,457.0041666666666,123.08,9.0,4.0,0.29161011257316083,0.07011270770510081,2.994998418066153,5.0,13.182764053344727,282.56195068359375 +12,81.64833333333333,26.670833333333338,24.0,24.0,0.16385124096600884,0.0054436432678239,4.0940013559432975,1.0,8.961026191711426,267.5937805175781 +13,69.20916666666666,9.235833333333332,18.0,9.0,0.34866666666666674,0.1833229166666666,2.713998644056703,5.0,9.010427474975586,210.76780700683594 +14,310.62500000000006,49.89833333333334,18.0,5.0,0.27871075783676724,-0.05604832244861349,3.239998418066153,7.0,13.888649940490723,291.23883056640625 +15,410.7441666666667,157.0791666666667,14.0,24.0,0.2797016475028005,0.033285190940379794,4.220001581933847,11.0,8.601736068725586,286.6244812011719 +16,45.89583333333334,16.438333333333333,24.0,5.0,0.31991666666666674,0.25017881944444453,1.8509986440567028,9.0,7.767814636230469,203.83230590820312 +17,167.8525,6.55,24.0,17.0,0.14949043135335743,0.0033889383686828423,3.0460013559432975,10.0,9.496901512145996,350.2374267578125 +18,149.13500000000002,28.925000000000008,10.0,4.0,0.060621313721235415,-0.06489427838079405,3.948001355943297,12.0,8.142132759094238,302.59979248046875 +19,660.6925,123.72083333333335,9.0,-7.0,0.10622912912121427,-0.001117437355605086,3.609998644056703,3.0,9.09882640838623,300.8371887207031 +20,33.94416666666667,3.0799999999999996,24.0,22.0,0.07699016347291837,0.04565856825846633,3.790998644056703,6.0,6.300083637237549,286.0442199707031 +21,107.10749999999997,3.2599999999999985,19.0,2.0,0.3638425833444172,0.05667181149223599,3.0640013559432973,12.0,14.382354736328125,289.53240966796875 +22,62.63000000000002,4.413333333333333,20.0,20.0,0.23179475177578865,0.14118558267662554,4.408998644056703,4.0,5.633917808532715,49.09061813354492 +23,31.56,6.47,24.0,24.0,0.08191784432620366,-0.016458339988615858,1.7580013559432972,13.0,5.630878448486328,50.107913970947266 +24,59.5,4.448333333333333,22.0,1.0,0.08856532959742293,-0.08894817028163549,3.746001355943297,2.0,9.116408348083496,306.83062744140625 +25,223.54083333333335,8.493333333333334,18.0,24.0,0.27333333333333343,0.18347529736560192,2.269998644056703,3.0,9.724139213562012,275.94305419921875 +26,232.8275,78.06500000000001,20.0,24.0,0.5240386504418829,0.3919327792211408,3.9110013559432977,12.0,12.063785552978516,269.16339111328125 +27,45.37,41.65999999999999,24.0,24.0,0.06486094246742372,0.06486094246742372,3.742001355943297,10.0,6.508177757263184,98.45169830322266 +28,45.29333333333333,9.815833333333336,17.0,-2.0,0.25631435737465236,0.1039062133731421,2.460001581933847,12.0,8.897130012512207,263.7205810546875 +29,211.16166666666663,39.87,20.0,24.0,0.36232720867284707,0.19488667650166913,3.8599986440567027,7.0,7.622583389282227,307.65093994140625 +30,49.14916666666667,10.351666666666668,22.0,24.0,0.03350000000000009,-0.05861111111111102,2.0100013559432974,1.0,8.062515258789062,291.82977294921875 +31,411.8633333333334,20.099999999999998,23.0,13.0,0.12186494133542405,-0.06979731833733212,4.3209986440567025,6.0,11.818822860717773,287.4737548828125 +32,31.56,22.2375,12.0,-14.0,0.04687363455283468,-0.04523273034782928,3.051001355943297,1.0,6.759639263153076,169.96612548828125 +33,355.96583333333336,13.870000000000003,19.0,23.0,0.1952276048622347,0.06302126887539775,2.515998644056703,4.0,10.53762149810791,279.3226623535156 +34,70.19083333333333,13.3725,17.0,18.0,-0.0019999999999999064,-0.03183854166666658,2.280998418066153,3.0,6.135858535766602,287.8697509765625 +35,37.18,2.5499999999999994,23.0,19.0,0.1123840692279397,-0.003167169095829453,3.1520013559432973,12.0,6.300809383392334,0.17108425498008728 +36,79.82999999999998,3.149999999999999,21.0,18.0,0.14894079795380344,0.05431994141458321,3.0830013559432974,1.0,6.283632755279541,299.8641662597656 +37,97.76,2.854166666666666,22.0,24.0,0.036000000000000094,0.019968133575759196,3.3079986440567026,7.0,8.657599449157715,267.36383056640625 +38,96.15916666666668,37.48666666666668,11.0,21.0,0.02216666666666676,-0.012078124999999915,1.6400013559432973,9.0,7.025077819824219,287.3065185546875 +39,45.666666666666664,1.84,24.0,5.0,0.12452911223061235,-0.05391036142668733,2.5190013559432973,13.0,7.6242356300354,297.707275390625 +40,62.612500000000004,1.6291666666666673,22.0,24.0,0.22916666666666677,0.11870191437807284,4.596998418066153,5.0,7.9556121826171875,296.85443115234375 +41,286.31666666666666,2.791666666666666,24.0,24.0,0.25558333333333344,0.2174547355936165,1.9499986440567028,6.0,9.61872673034668,313.4038391113281 +42,88.27750000000002,8.606666666666667,24.0,13.0,0.06189206186081198,-0.018089034561481906,2.2330013559432977,13.0,8.782184600830078,279.4078369140625 +43,187.99166666666667,33.498333333333335,14.0,-23.0,-0.053677373009768076,-0.1932585126527603,3.3080013559432975,11.0,8.628103256225586,296.42584228515625 +44,38.440000000000005,9.713333333333333,18.0,-9.0,-0.07134212776629864,-0.2080328134651356,3.1820015819338474,13.0,6.03052282333374,282.875 +45,164.06250000000003,20.107499999999998,17.0,18.0,-0.016964982403435636,-0.13821909982042502,2.2560013559432974,12.0,9.768003463745117,287.7176208496094 +46,49.45583333333334,20.5125,24.0,-22.0,-0.019316508609256433,-0.11026091918459616,3.978001581933847,1.0,5.585178375244141,304.240234375 +47,275.05333333333334,15.979999999999999,8.0,1.0,-0.0474525739782648,-0.331024234805694,2.964001581933847,12.0,11.152703285217285,283.16986083984375 +48,35.19166666666667,11.023333333333332,24.0,-22.0,-0.0383686792918847,-0.14528208806082515,3.145001355943297,1.0,9.937807083129883,289.37506103515625 +49,30.670000000000012,6.468333333333331,15.0,-1.0,-0.06240872349064755,-0.16633670858852762,4.623001355943297,12.0,5.647650241851807,277.0070495605469 +50,49.87333333333334,3.7783333333333338,24.0,24.0,0.19205287588443826,0.08320468342065385,4.5759984180661535,3.0,6.7125630378723145,329.0019226074219 +51,198.97583333333333,35.84000000000001,20.0,21.0,0.18491666666666676,0.07690913409983094,2.0520013559432977,2.0,7.262315273284912,288.0158996582031 +52,103.135,16.430000000000003,24.0,0.0,0.19861470539315446,0.01845219865861733,1.6180015819338467,1.0,5.880589962005615,285.596435546875 +53,133.82250000000002,39.040000000000006,13.0,4.0,0.1227279230805716,-0.0717328098749265,3.3680013559432975,12.0,9.591411590576172,292.4080505371094 +54,47.93,2.9941666666666666,18.0,8.0,0.09941666666666678,0.02070486111111125,2.074998644056703,8.0,9.483529090881348,283.9675598144531 +55,630.2808333333332,0.6433333333333334,20.0,8.0,0.06425000000000011,0.009485732442377062,2.509001581933847,13.0,5.575372219085693,305.3603515625 +56,40.37000000000001,1.9116666666666668,24.0,12.0,0.06377417674372768,0.003116071371643242,4.051998644056702,2.0,5.675177574157715,42.09859848022461 +57,126.29999999999997,3.919166666666667,19.0,9.0,0.2647431957665587,0.09732603298823311,3.4980013559432974,1.0,8.75196647644043,16.157913208007812 +58,36.95333333333334,9.714999999999998,13.0,13.0,0.30271441655231024,0.16230764224214456,3.374001581933847,13.0,7.499722480773926,289.3928527832031 +59,65.235,6.5716666666666645,21.0,20.0,0.20730711595564538,0.011640127495575886,3.3900015819338467,12.0,7.193569183349609,275.1912536621094 +60,116.63999999999997,5.7108333333333325,22.0,8.0,0.240202479961687,0.047802495425807084,3.5480013559432972,12.0,8.102508544921875,311.853759765625 +61,187.67916666666667,33.02333333333333,24.0,21.0,0.2013424326875392,0.14682816220850248,3.3310013559432976,10.0,7.130411148071289,328.65673828125 +62,114.38499999999998,14.203333333333333,24.0,9.0,0.1980000000000001,0.10748103363465342,4.309001355943298,12.0,10.653990745544434,207.91802978515625 +63,42.31083333333332,5.920000000000001,24.0,24.0,-0.03541666666666656,-0.043560746793120685,3.222001355943297,11.0,5.699121475219727,306.2886657714844 +64,381.4533333333334,111.9883333333333,5.0,6.0,0.528908203548121,0.15974791566129143,2.0310015819338467,9.0,11.111101150512695,330.6773681640625 +65,123.18333333333335,52.27250000000001,24.0,22.0,0.08564730063373664,0.08564730063373664,4.238998644056703,2.0,7.63604736328125,311.37066650390625 +66,188.41583333333335,45.43666666666667,21.0,23.0,0.1306534484035079,0.1306534484035079,2.7350015819338465,1.0,7.71270751953125,296.4352722167969 +67,191.5916666666667,27.022499999999994,14.0,24.0,0.06604340736402498,0.06604340736402498,2.7359986440567026,7.0,7.136730670928955,295.428955078125 +68,33.498333333333335,17.271666666666665,22.0,2.0,0.1223749333474536,-0.013618708637555432,3.7980013559432972,12.0,3.7327492237091064,347.94189453125 +69,67.92583333333332,23.49749999999999,24.0,-22.0,0.1994558161581783,0.01996757715910985,1.6120013559432973,12.0,10.416769027709961,279.25213623046875 +70,102.09000000000002,33.41,23.0,16.0,0.16843691363595695,-0.031559303942266526,3.3420013559432977,12.0,10.704462051391602,286.75531005859375 +71,195.27499999999998,34.07916666666667,22.0,1.0,0.06916666666666674,-0.0011475694444443851,3.2910013559432976,9.0,8.22249984741211,287.45794677734375 +72,116.22166666666665,14.203333333333333,24.0,12.0,0.019500000000000066,-0.008333333333333266,2.8429986440567028,4.0,9.027729034423828,271.7666931152344 +73,256.9525,51.67666666666667,8.0,-2.0,0.25518586742228994,0.07409389083232032,2.9580013559432974,1.0,11.461088180541992,274.7409362792969 +74,66.65916666666668,9.329166666666667,12.0,4.0,4.2267677086718636e-05,-0.16757644850132625,3.4479986440567028,3.0,6.807092666625977,4.171119213104248 +75,52.14166666666667,5.11,24.0,-23.0,0.1390833333333334,0.09009048780693607,3.209001355943297,13.0,6.228907585144043,207.0631866455078 +76,319.6191666666666,41.76083333333333,23.0,-23.0,0.046824410184043604,0.028696978190785143,2.303001355943297,3.0,10.873367309570312,284.076171875 +77,102.71,17.97,17.0,11.0,0.4876512795830714,0.1210683273611366,1.9589986440567027,6.0,13.210498809814453,291.7101745605469 +78,428.8908333333334,86.65000000000002,17.0,10.0,0.2308596463020613,0.11743679208609809,4.766001355943297,1.0,13.322553634643555,293.7390441894531 +79,304.8566666666667,25.818333333333328,19.0,10.0,0.21369644018907294,0.005615508440632799,2.239998644056703,8.0,13.135181427001953,276.0301818847656 +80,76.54666666666667,8.9975,10.0,16.0,0.13023322411246963,-0.008176244606948269,4.270001355943297,12.0,8.158682823181152,288.9858093261719 +81,124.04083333333334,11.342500000000001,24.0,23.0,0.2666781380651204,0.13693887751226225,4.084001355943297,12.0,7.52000617980957,285.7328186035156 +82,57.828333333333326,2.9600000000000004,22.0,24.0,0.22746639596416823,0.14810802344848256,1.4499984180661531,8.0,9.21432113647461,272.8247985839844 +83,169.29250000000002,50.096666666666664,13.0,10.0,-0.0010997296089363118,-0.13766315105604535,3.6890013559432973,13.0,8.98540210723877,304.443115234375 +84,359.15000000000003,22.679999999999996,12.0,-2.0,0.10559160535901044,-0.13838516637720982,3.4150013559432972,10.0,11.589315414428711,278.79241943359375 +85,1173.5708333333334,70.14583333333333,24.0,-3.0,0.4217200073015815,0.24932113427725583,2.4290013559432975,13.0,14.072980880737305,294.2030944824219 +86,91.33500000000002,30.3175,24.0,11.0,-0.005842600332741393,-0.11022109223965201,1.6570013559432974,13.0,7.747704982757568,291.8443298339844 +87,208.9533333333333,49.86000000000001,9.0,24.0,0.10421757952350816,-0.039810300584824876,2.9990013559432973,1.0,8.692423820495605,287.5229797363281 +88,62.93,11.085,24.0,24.0,0.11741666666666672,0.091829724820323,1.4849984180661533,7.0,6.381709575653076,279.56610107421875 +89,32.615,2.9183333333333334,20.0,16.0,0.05164822933828493,-0.14130806141491783,3.9180013559432973,12.0,9.977774620056152,293.07196044921875 +90,54.17083333333334,8.506666666666666,24.0,24.0,0.1188507098427977,-0.02448513754790954,4.152001355943298,2.0,6.874385356903076,301.1564025878906 +91,53.49,1.82,24.0,14.0,0.07498459959681772,-0.03781368897121907,1.8840013559432975,12.0,7.056942462921143,289.1119384765625 +92,51.29999999999999,3.9083333333333345,18.0,24.0,0.14975000000000005,0.06473197968354777,1.8730013559432974,11.0,8.976588249206543,289.061767578125 +93,49.44583333333335,2.8299999999999996,24.0,15.0,0.14170089679943035,0.055333639856747496,2.3550013559432976,12.0,5.254964828491211,18.865938186645508 +94,252.42000000000004,43.16833333333333,19.0,1.0,0.12698479157728373,-0.08318107269192272,4.278001355943298,1.0,11.772808074951172,301.4169616699219 +95,31.899999999999995,7.190000000000001,10.0,-2.0,0.3685381922809928,0.07952109201065155,3.8999984180661538,6.0,11.317715644836426,278.16015625 +96,61.60083333333333,7.775833333333335,24.0,21.0,0.03939910319622795,0.022854927792095366,3.8180013559432973,13.0,6.261366844177246,347.6805419921875 +97,259.795,50.935,14.0,-23.0,0.34610502854509934,0.15537458559385703,3.475998644056703,6.0,13.748801231384277,284.2099609375 +98,520.2966666666667,71.55333333333336,14.0,24.0,0.3670202703447928,0.06297644647802453,3.113001355943297,12.0,12.200216293334961,293.2322998046875 +99,201.9725,35.86833333333334,21.0,8.0,0.19640352332153968,-0.022319581336443517,1.6310013559432972,12.0,8.414977073669434,327.95513916015625 +100,33.00916666666667,24.814999999999998,10.0,12.0,0.13158333333333339,0.07690769038408102,2.2329986440567025,7.0,4.601818561553955,314.6217041015625 +101,33.85999999999999,16.025000000000002,24.0,23.0,0.08140488958250514,0.023473192539327378,3.3209986440567025,8.0,6.096288204193115,271.6534423828125 +102,40.40999999999999,16.650000000000002,23.0,8.0,0.02759409495857732,-0.07053062385853952,3.5230013559432973,11.0,4.698474407196045,45.33683395385742 +103,143.57416666666666,1.2200000000000002,24.0,14.0,0.11750000000000005,0.0035478902806314605,4.162998644056703,2.0,11.284472465515137,278.6455078125 +104,118.03333333333335,29.95583333333333,6.0,0.0,0.056778019664014884,-0.07135997609734507,2.094001355943297,13.0,11.154809951782227,285.632568359375 +105,177.80947178502416,6.216272603835011,21.0,-5.0,0.26172625826130935,0.07547681329612643,2.3300013559432973,1.0,10.74108600616455,267.9744873046875 +106,48.0325,3.121,24.0,22.0,-0.030903979029912286,-0.09911842008243446,2.5629984180661536,6.0,3.3123226165771484,277.85418701171875 +107,516.2466666666668,90.21000000000004,24.0,0.0,-0.01736254168924456,-0.13748268850221299,3.7560013559432974,10.0,8.808548927307129,314.7304992675781 +108,133.28666666666666,45.88999999999999,13.0,3.0,0.013557771818829327,-0.0774385380442141,2.965998418066153,7.0,9.628653526306152,285.953369140625 +109,43.17083333333333,16.980999999999998,24.0,17.0,0.27542394736611026,0.06715631274071049,4.238998644056703,7.0,8.241395950317383,132.5605010986328 +110,83.39,39.81,11.0,22.0,-0.010209991995044285,-0.15367641081521133,4.346001355943297,11.0,7.495718002319336,341.90496826171875 +111,34.13666666666666,2.723333333333333,4.0,20.0,0.09523715529704282,0.03222773402929019,3.452001355943297,8.0,8.404056549072266,274.765869140625 +112,73.705,10.542000000000003,24.0,7.0,-0.0393333333333333,-0.08575520833333328,3.2069986440567027,7.0,7.674698829650879,290.35809326171875 +113,46.47336818741141,3.0021690862754316,24.0,22.0,0.0014166666666666934,-0.03136284722222219,1.8100013559432973,13.0,8.196100234985352,286.189208984375 +114,76.9938282464109,5.428673282970908,24.0,19.0,0.15649126986904568,-0.0019171655228740203,2.440001581933847,1.0,10.163163185119629,288.3130798339844 +115,34.00160728181063,3.149819894281499,24.0,-23.0,-0.007833333333333296,-0.030595486111111077,4.394001355943297,1.0,6.831943511962891,297.312255859375 +116,37.246708314843026,2.5300000000000002,24.0,14.0,0.11396972639844352,-0.002800966323005541,1.1809986440567026,6.0,6.194048881530762,337.88323974609375 +117,93.15251622944957,24.278600922704424,24.0,19.0,0.21746725323078192,-0.013583108061688082,3.4570013559432975,13.0,8.200360298156738,292.8885803222656 +118,116.59754041547482,17.78398784376634,16.0,1.0,0.05376163357999267,-0.042344424008024725,3.7210013559432973,12.0,8.903711318969727,324.9503173828125 +119,309.83037322632583,71.8823752333456,15.0,2.0,0.4107093580991234,0.09380931453033742,2.357998418066153,8.0,11.920799255371094,275.0240173339844 +120,259.4170833333333,42.11566666666666,24.0,-4.0,0.265464828152491,0.16077827045215204,3.433998644056703,4.0,7.065324306488037,4.141475677490234 +121,72.96149999999999,11.920999999999998,24.0,24.0,0.03113655256499045,-0.013907505058268498,2.1550013559432974,11.0,7.6787943840026855,286.06549072265625 +122,340.65904186046515,53.77903566328581,24.0,-23.0,0.007757028032140217,0.00504008476340608,3.6190013559432974,9.0,7.605906009674072,316.22772216796875 +123,46.05310539560318,14.682158371727915,21.0,21.0,0.43553775226805225,0.2868126166785091,4.428998418066153,5.0,11.380340576171875,277.2616271972656 +124,35.87282903045263,17.71371742828396,24.0,-23.0,0.2961666666666667,0.22668576388888895,1.3210015819338468,10.0,9.178385734558105,200.69874572753906 +125,240.30685912870993,84.47394872557327,10.0,23.0,0.20134809281303548,0.20134809281303548,2.0990013559432974,12.0,8.250228881835938,279.0096435546875 +126,226.3453409215385,29.53785905070201,16.0,24.0,0.3212765315653272,0.13064994880722958,1.7970013559432974,11.0,9.79000473022461,303.1637878417969 +127,135.1221017185674,19.166995235146924,9.0,19.0,0.0584166666666667,-0.0043573111530591235,3.648998418066153,7.0,5.71779203414917,329.9492492675781 +128,101.45445288352035,14.333163017115389,11.0,-4.0,0.043571275388435665,-0.12401413743512023,4.045001355943297,12.0,8.894583702087402,282.6202392578125 +129,51.18682570028926,4.7754413687579325,21.0,20.0,0.022666666666666696,0.0038077609836979047,2.888001355943297,2.0,3.6145927906036377,48.26362228393555 +130,84.07068565212907,26.04849544499307,14.0,23.0,0.06675000000000002,0.043532986111111116,2.035998644056703,7.0,5.0989508628845215,355.3311462402344 +131,73.85832749806788,15.736779943434849,24.0,13.0,0.04075000000000003,0.003304462924804942,3.637998418066153,6.0,10.923680305480957,292.585205078125 +132,70.52877122566292,3.97269024596488,19.0,12.0,-0.003035219218654305,-0.03150345256317384,2.628001581933847,13.0,5.180827617645264,315.7484130859375 +133,199.14475157568324,33.017437114089596,7.0,24.0,0.14605274288331477,0.06262934738970927,2.2940015819338466,12.0,5.195274353027344,262.6291809082031 +134,84.7907633353101,5.924127022710167,17.0,24.0,0.12183333333333335,0.0469010416666667,3.924001355943297,11.0,8.185311317443848,285.82708740234375 +135,90.83933333333333,39.832750000000004,7.0,0.0,0.35398584846431913,0.18134030346985552,3.538001581933847,9.0,5.6720356941223145,255.53311157226562 +136,30.0,30.0,0.0,0.0,0.4093113366566202,0.2105654887156097,3.151998418066153,7.0,12.154000282287598,290.625 +137,175.3155833333333,73.448,24.0,-24.0,0.23905319140537143,0.09756688306601305,1.9420015819338468,1.0,11.8248872756958,285.147216796875 +138,75.83604166666667,47.14934999999999,20.0,14.0,0.2947327552400064,0.1732089336938803,4.348001355943298,12.0,8.434569358825684,275.8511962890625 +139,202.9091666666667,38.135,24.0,-11.0,0.7162882035976059,-0.012637518339102538,2.868998644056703,5.0,19.244121551513672,264.0550537109375 +140,77.79916666666666,18.120833333333337,24.0,23.0,0.413070512750653,0.18239593381940966,3.2000013559432974,12.0,9.93686580657959,275.52960205078125 +141,148.94500000000002,11.178333333333335,9.0,-24.0,0.44724338607897635,0.17201042773076064,2.0049984180661533,5.0,12.815786361694336,312.67779541015625 +142,30.0,30.0,0.0,0.0,0.23749061970338375,0.04370374527213372,4.254001355943297,1.0,12.815786361694336,312.67779541015625 +143,30.0,30.0,0.0,0.0,0.1870833333333334,0.07469270833333339,3.457001355943297,12.0,10.015145301818848,280.36981201171875 +144,30.0,30.0,0.0,0.0,0.32729014509213433,0.20468059082418016,3.8650013559432974,12.0,10.015145301818848,280.36981201171875 +145,164.82750000000001,17.139999999999997,23.0,23.0,0.3168643313045074,0.1716081033629938,4.012998418066154,6.0,11.899084091186523,267.0032653808594 +146,30.0,30.0,0.0,0.0,0.2970921504531081,0.05502584267559635,3.4870013559432977,12.0,11.899084091186523,267.0032653808594 +147,57.88999999999999,44.38833333333333,4.0,-21.0,0.4395833333333334,0.15219618055555567,1.8409986440567028,8.0,10.699501991271973,282.5140686035156 +148,30.0,30.0,0.0,0.0,0.2884166666666667,0.19054513888888897,3.9169986440567035,3.0,10.699501991271973,282.5140686035156 +149,30.0,30.0,0.0,0.0,0.190516561985819,0.10092898233306291,2.9669986440567024,4.0,10.699501991271973,282.5140686035156 +150,396.9666666666667,157.0791666666667,13.0,23.0,0.2797016475028005,0.033285190940379794,4.220001581933847,11.0,11.08395767211914,290.02191162109375 +151,41.540000000000006,12.863333333333335,11.0,8.0,0.4564166666666667,0.08150580767727755,4.465001355943297,8.0,13.132201194763184,218.96324157714844 +152,30.0,30.0,0.0,0.0,0.19316666666666674,0.12452256944444448,2.6480015819338467,12.0,13.132201194763184,218.96324157714844 +153,30.0,30.0,0.0,0.0,0.33266147021895276,-0.004391056158270623,4.807998644056703,6.0,13.132201194763184,218.96324157714844 +154,42.57,33.80833333333333,24.0,10.0,0.21958333333333344,0.10397222222222227,2.4119986440567027,3.0,5.397805690765381,215.4268035888672 +155,31.56,5.528333333333333,24.0,10.0,0.26108333333333344,0.17180767294309823,3.2090013559432973,1.0,7.9302659034729,224.62081909179688 +156,30.0,30.0,0.0,0.0,0.18919980055366273,0.05835105260324333,2.1480013559432978,12.0,7.9302659034729,224.62081909179688 +157,30.0,30.0,0.0,0.0,0.19420546643244657,0.0776149653730156,4.516998644056702,5.0,7.9302659034729,224.62081909179688 +158,180.21166666666667,8.493333333333334,12.0,23.0,0.28266666666666673,0.16237033423838765,2.1930013559432973,11.0,9.724139213562012,275.94305419921875 +159,159.67,66.55333333333333,6.0,-17.0,0.5996481328509795,0.3229203977110139,3.885998644056703,7.0,12.936824798583984,266.60064697265625 +160,33.40666666666666,33.40666666666666,0.0,-24.0,0.20516666666666675,0.08792936657322067,1.4860013559432974,12.0,9.101889610290527,204.39816284179688 +161,206.55000000000004,20.390000000000004,24.0,5.0,0.254762059738464,0.11370591407765124,3.610001581933847,10.0,9.512039184570312,277.17755126953125 +162,30.0,30.0,0.0,0.0,0.3453986680046968,0.19043959974333263,2.9230013559432972,1.0,9.512039184570312,277.17755126953125 +163,36.40999999999999,33.13999999999999,24.0,22.0,0.29616666666666674,0.19532812500000013,4.030001581933847,9.0,9.443790435791016,201.46034240722656 +164,162.1966666666667,31.435000000000002,24.0,23.0,0.37722058610054915,0.18570538003911324,3.926001581933847,11.0,7.612980842590332,308.981201171875 +165,30.0,30.0,0.0,0.0,0.19132668544527096,0.08552660926185282,2.5579986440567026,8.0,7.612980842590332,308.981201171875 +166,30.0,30.0,0.0,0.0,0.45622635274709333,0.1962257344728251,4.105998644056703,6.0,7.612980842590332,308.981201171875 +167,30.0,30.0,0.0,0.0,0.27616717027428694,0.10843510710919863,1.6840013559432974,12.0,7.612980842590332,308.981201171875 +168,30.0,30.0,0.0,0.0,0.2265026702965617,0.1299797811391308,3.372001355943297,12.0,7.612980842590332,308.981201171875 +169,68.42916666666666,8.342500000000001,10.0,21.0,0.22642103265163455,-0.0009257371515164203,3.4470013559432973,12.0,9.526407241821289,291.0509948730469 +170,30.0,30.0,0.0,0.0,0.2970833333333334,0.15530801938794614,3.770001355943297,12.0,9.526407241821289,291.0509948730469 +171,30.0,30.0,0.0,0.0,0.29527371579930034,0.209434576975235,1.8359986440567027,7.0,9.526407241821289,291.0509948730469 +172,117.73333333333329,5.177499999999999,13.0,9.0,0.3073982855847736,-0.004818526032103254,2.920998644056703,6.0,13.254295349121094,286.6992492675781 +173,45.380833333333335,3.520000000000001,24.0,23.0,0.19488148264496635,0.08029297806861174,4.598001355943298,2.0,6.7125630378723145,329.0019226074219 +174,56.693333333333335,8.61,12.0,22.0,0.2633441144209275,0.1050903509740414,3.210001355943297,13.0,7.750696182250977,269.2320556640625 +175,146.1166666666667,41.57999999999999,21.0,21.0,0.34617117834414707,0.07593187716489008,3.422998644056703,5.0,10.078605651855469,270.559326171875 +176,30.0,30.0,0.0,0.0,0.2892496722963264,0.10856257465755231,2.7909984180661533,5.0,10.078605651855469,270.559326171875 +177,30.0,30.0,0.0,0.0,0.1871666666666668,0.014880208333333533,4.087998418066153,4.0,10.078605651855469,270.559326171875 +178,30.0,30.0,0.0,0.0,0.2173333333333334,0.1403362472287609,2.9200013559432976,11.0,10.078605651855469,270.559326171875 +179,30.0,30.0,0.0,0.0,0.2457535734601301,0.12437550120850033,4.4210013559432975,12.0,10.078605651855469,270.559326171875 +180,65.235,6.5716666666666645,21.0,20.0,0.20730711595564538,0.011640127495575886,3.3900015819338467,12.0,7.420760631561279,275.796875 +181,111.90999999999997,7.865000000000001,24.0,23.0,0.25575783640798655,0.05922567904317311,3.3310013559432976,13.0,9.172830581665039,273.4454345703125 +182,123.44000000000004,25.79166666666667,15.0,2.0,0.18558974195500133,-0.06173551000714202,3.065001355943297,1.0,10.73923397064209,288.9654846191406 +183,187.67416666666668,88.89,22.0,1.0,0.2517693596467028,0.03707730303504886,2.805998644056703,5.0,12.330705642700195,286.669677734375 +184,135.72333333333333,55.11166666666667,12.0,14.0,0.2408696934338659,0.05379592155966448,4.403998418066154,6.0,13.061789512634277,272.73834228515625 +185,64.54666666666667,43.775,9.0,-20.0,0.34576687132411277,0.11876366836039015,2.340001581933847,13.0,12.157576560974121,275.8736267089844 +186,62.32750000000001,25.006666666666664,24.0,9.0,0.28467996840581217,0.12291254364885368,2.250001355943297,1.0,7.449378490447998,66.28460693359375 +187,30.0,30.0,0.0,0.0,0.24315869068860094,0.10142511429261816,1.6930015819338466,1.0,7.449378490447998,66.28460693359375 +188,54.29666666666666,33.41,18.0,23.0,0.19156819589139168,0.016041703962721393,3.3420013559432977,13.0,10.704462051391602,286.75531005859375 +189,30.0,30.0,0.0,0.0,0.19491666666666674,0.1122586805555556,1.2490013559432973,11.0,10.704462051391602,286.75531005859375 +190,30.0,30.0,0.0,0.0,0.19216666666666674,0.10301388888888888,3.5670013559432974,12.0,10.704462051391602,286.75531005859375 +191,30.0,30.0,0.0,0.0,0.19650371281256973,0.01872226769733376,1.2700013559432972,12.0,10.704462051391602,286.75531005859375 +192,129.44333333333336,12.000833333333333,20.0,15.0,0.2717779520044575,0.02874528166607676,4.289001355943297,13.0,11.70299243927002,283.4332580566406 +193,30.0,30.0,0.0,0.0,0.42386105777553307,0.23526149531261875,1.9269984180661532,8.0,11.461088180541992,274.7409362792969 +194,30.0,30.0,0.0,0.0,0.3285540772243678,0.04346456155366801,3.1849986440567024,6.0,11.461088180541992,274.7409362792969 +195,30.0,30.0,0.0,0.0,0.2861048632335857,0.20205900600469012,3.325998644056703,6.0,11.461088180541992,274.7409362792969 +196,226.3266666666667,122.04416666666667,5.0,-18.0,0.437637686061809,0.06813907253622942,4.520998644056702,5.0,14.98900032043457,280.24542236328125 +197,40.26,33.755,12.0,-16.0,0.23333333333333336,0.15520486111111112,4.335998644056703,3.0,6.744097709655762,296.2830810546875 +198,30.0,30.0,0.0,0.0,0.21045128836591248,0.08258553387115697,2.340001355943297,12.0,6.744097709655762,296.2830810546875 +199,30.0,30.0,0.0,0.0,0.21440190644602464,0.07328608091697103,3.125001355943297,1.0,6.744097709655762,296.2830810546875 +200,30.0,30.0,0.0,0.0,0.2075031988384374,0.13871978924024111,1.4260015819338467,11.0,6.744097709655762,296.2830810546875 +201,30.0,30.0,0.0,0.0,0.24540731229109305,0.0916617604804392,4.615001355943297,2.0,6.744097709655762,296.2830810546875 +202,30.0,30.0,0.0,0.0,0.2821509979108912,0.07343261003362006,3.6860015819338465,12.0,6.744097709655762,296.2830810546875 +203,30.0,30.0,0.0,0.0,0.2663582623826307,0.1541274402704375,2.636998644056703,7.0,6.744097709655762,296.2830810546875 +204,30.0,30.0,0.0,0.0,0.4302161038655401,0.1128314950431849,2.9169986440567026,6.0,6.744097709655762,296.2830810546875 +205,166.67499999999998,61.929999999999986,24.0,8.0,0.2566883991492208,0.08551167174654833,4.375001581933847,12.0,9.039578437805176,269.3879699707031 +206,255.92000000000004,135.6258333333333,6.0,18.0,0.18954168150416448,0.029510614140150132,3.879001355943297,9.0,10.835078239440918,284.6174011230469 +207,30.0,30.0,0.0,0.0,0.2493333333333334,0.05184201388888893,3.737998644056703,7.0,10.835078239440918,284.6174011230469 +208,30.0,30.0,0.0,0.0,0.32275000000000004,0.14168576388888887,3.608001355943297,9.0,10.835078239440918,284.6174011230469 +209,493.1033333333333,71.55333333333336,13.0,23.0,0.3670202703447928,0.06297644647802453,3.113001355943297,12.0,12.200216293334961,293.2322998046875 +210,176.91333333333338,85.25,12.0,21.0,0.2724425548653292,0.06816584765008055,2.1610013559432977,12.0,10.841472625732422,288.7580871582031 +211,73.34916666666669,5.986666666666667,10.0,-24.0,0.19785824670407562,0.008292877126545695,2.8499986440567024,6.0,8.013354301452637,208.83892822265625 +212,52.01999999999999,41.15999999999999,6.0,-19.0,0.29146128140911715,0.08945479615764101,4.283001355943297,2.0,8.282185554504395,190.31089782714844 +213,30.0,30.0,0.0,0.0,0.3104597509865139,0.09944946199746152,4.519998644056703,8.0,8.282185554504395,190.31089782714844 +214,30.0,30.0,0.0,0.0,0.20000000000000004,0.12228993055555562,2.128998644056703,4.0,8.282185554504395,190.31089782714844 +215,30.0,30.0,0.0,0.0,0.19816480503873568,0.09379614333372072,3.891001355943297,11.0,8.282185554504395,190.31089782714844 +216,30.0,30.0,0.0,0.0,0.2700833333333334,0.15175103603607193,2.282001581933847,1.0,8.282185554504395,190.31089782714844 +217,30.0,30.0,0.0,0.0,0.3283523612059477,0.12991208127589865,3.078998418066153,5.0,8.282185554504395,190.31089782714844 +218,30.0,30.0,0.0,0.0,0.3147390064550119,0.047616374716370535,4.430998644056703,7.0,8.241395950317383,132.5605010986328 +219,30.0,30.0,0.0,0.0,0.2199844393928159,-0.02470231967193323,2.458998644056703,7.0,8.241395950317383,132.5605010986328 +220,30.0,30.0,0.0,0.0,0.2828333333333334,0.18619270833333335,3.569001355943297,9.0,8.241395950317383,132.5605010986328 +221,91.70657396103284,3.684006782406741,24.0,14.0,0.23037117050677797,0.011144944687379865,4.1500013559432976,1.0,8.37102222442627,284.9960021972656 +222,93.95749999999998,13.74708333333333,21.0,15.0,0.3782536365920806,-0.07992609174247056,2.0149986440567025,9.0,14.376069068908691,269.3013610839844 +223,178.87874434371247,8.8825,6.0,18.0,0.4388103381040224,0.025793779605439326,2.340998644056703,6.0,13.057626724243164,272.3252868652344 +224,43.081760957156,30.525889668608503,24.0,-24.0,0.25845336969784927,0.05352320329434085,3.486998418066153,6.0,7.201434135437012,219.2325439453125 +225,222.1702155255571,29.53785905070201,15.0,23.0,0.3212765315653272,0.13064994880722958,1.7970013559432974,11.0,9.79000473022461,303.1637878417969 +226,129.29267401166211,25.960181858947035,14.0,-14.0,0.2406182713486978,0.12997734201457373,3.3869986440567033,3.0,8.686917304992676,314.9817810058594 +227,126.06616666666666,46.44108333333333,8.0,-13.0,0.35398584846431913,0.1408445177109754,3.8440013559432975,10.0,10.6655912399292,272.398193359375 +228,317.5206666666666,23.52191666666667,24.0,2.0,0.19045605867636878,0.10237087867888717,2.481998644056703,7.0,8.639639854431152,261.2489013671875 +229,362.2166666666667,140.87949999999998,9.0,-3.0,0.305436758185177,0.07214044014688897,2.9989984180661535,3.0,12.154000282287598,290.625 +230,30.101000000000003,30.101000000000003,0.0,-31.0,0.4093113366566202,0.2105654887156097,3.3600013559432975,12.0,11.954904556274414,257.50775146484375 +231,142.1025833333333,47.43783333333334,24.0,12.0,0.0835652799919568,-0.04179358807977312,3.2089984180661535,5.0,8.15102481842041,357.1053771972656 +232,63.79625000000001,47.14934999999999,19.0,13.0,0.2947327552400064,0.1732089336938803,4.348001355943298,2.0,8.434569358825684,275.8511962890625 +233,154.11025000000004,55.074333333333335,14.0,29.0,0.17745746049258043,-0.10946599200081386,3.5470015819338467,10.0,7.505548477172852,338.52252197265625 +234,13.458333333333336,11.105083333333333,6.0,-11.0,0.10082903508190183,-0.008980365382128791,3.2480013559432974,13.0,7.520030498504639,96.43468475341797 +235,202.9091666666667,38.135,24.0,-11.0,0.7162882035976059,-0.012637518339102538,2.6310015819338473,2.0,19.244121551513672,264.0550537109375 +236,270.0975,76.83083333333333,16.0,46.0,0.26709567081419683,-0.11813480386939737,4.559001581933847,9.0,12.323180198669434,285.22564697265625 +237,148.94500000000002,11.178333333333335,9.0,-24.0,0.44724338607897635,0.17201042773076064,2.122001355943297,3.0,12.815786361694336,312.67779541015625 +238,12.247499999999997,6.605,17.0,19.0,0.23749061970338375,0.04370374527213372,4.254001355943297,9.0,7.794609546661377,305.2272644042969 +239,22.58,8.914166666666665,24.0,17.0,0.14950000000000008,0.0977403591505625,4.334001355943297,1.0,8.486844062805176,298.62939453125 +240,10.379999999999999,8.404166666666667,12.0,-2.0,0.11456159284155282,-0.00013188949128117855,4.1479986440567025,3.0,7.926605224609375,294.3294372558594 +241,50.5875,8.760000000000002,24.0,-7.0,0.19065923564379145,-0.05041724138409151,3.960998644056703,8.0,10.015145301818848,280.36981201171875 +242,15.5325,5.546666666666667,23.0,36.0,0.08541666666666674,0.032269097222222334,2.151998418066153,6.0,9.906084060668945,285.81195068359375 +243,39.498333333333335,18.01583333333333,23.0,11.0,0.030808939530948896,-0.0581284695910307,4.193998644056703,5.0,7.532832622528076,285.96783447265625 +244,2.775,1.3650000000000002,23.0,38.0,0.051083333333333404,-0.04862673611111105,2.1590013559432975,11.0,11.080944061279297,282.26263427734375 +245,2.0975000000000006,1.6699999999999997,19.0,47.0,0.029250000000000054,-0.026749999999999947,3.590001581933847,1.0,7.894705295562744,286.38153076171875 +246,27.51416666666667,11.168333333333331,8.0,45.0,0.1456552771725683,0.006297380569798672,4.657998644056702,8.0,8.089737892150879,281.8280944824219 +247,21.069999999999997,3.669166666666666,14.0,26.0,0.32729014509213433,0.20468059082418016,3.349998644056703,7.0,10.092907905578613,288.0948486328125 +248,457.0041666666666,123.08,9.0,4.0,0.29161011257316083,0.07011270770510081,3.4980013559432974,11.0,13.182764053344727,282.56195068359375 +249,18.3225,4.244999999999998,23.0,12.0,0.2970921504531081,0.05502584267559635,3.414998644056703,5.0,10.629844665527344,274.18048095703125 +250,57.88999999999999,44.38833333333333,4.0,-21.0,0.4395833333333334,0.15219618055555567,1.8409986440567028,9.0,10.699501991271973,282.5140686035156 +251,19.856666666666666,11.539999999999997,13.0,13.0,0.2884166666666667,0.19054513888888897,3.9169986440567035,7.0,9.129508018493652,268.1993713378906 +252,210.91083333333336,23.185833333333335,24.0,4.0,0.2797016475028005,0.033285190940379794,4.220001581933847,1.0,11.08395767211914,290.02191162109375 +253,64.07583333333334,20.39416666666667,20.0,32.0,0.1583758618965748,-0.050037467802892796,2.5949986440567026,5.0,8.840475082397461,287.3660888671875 +254,41.540000000000006,12.863333333333335,11.0,8.0,0.4564166666666667,0.08150580767727755,4.250998644056702,7.0,13.132201194763184,218.96324157714844 +255,12.461666666666666,9.477500000000001,22.0,-38.0,0.12911485912465448,0.051223009077880244,3.734998644056703,2.0,7.992770671844482,89.30781555175781 +256,25.069999999999997,6.47,24.0,12.0,0.33266147021895276,-0.004391056158270623,4.807998644056703,5.0,13.704707145690918,280.46917724609375 +257,167.8525,6.55,24.0,17.0,0.14949043135335743,0.0033889383686828423,1.9469986440567026,6.0,9.496901512145996,350.2374267578125 +258,149.13500000000002,28.925000000000008,10.0,4.0,0.060621313721235415,-0.06489427838079405,3.941998644056703,5.0,8.142132759094238,302.59979248046875 +259,660.6925,123.72083333333335,9.0,-7.0,0.10622912912121427,-0.001117437355605086,3.5920015819338467,1.0,9.09882640838623,300.8371887207031 +260,3.545,3.0375,4.0,29.0,0.09433333333333344,0.03766319444444455,3.6040013559432973,8.0,8.831278800964355,295.53363037109375 +261,2.980833333333333,2.7600000000000002,13.0,-20.0,0.18919980055366273,0.05835105260324333,2.5449986440567027,7.0,7.8486552238464355,84.20854187011719 +262,4.930000000000001,2.91,19.0,15.0,0.19420546643244657,0.0776149653730156,4.516998644056702,3.0,12.796878814697266,270.045166015625 +263,31.093333333333334,3.0799999999999996,24.0,21.0,0.08450000000000009,0.036949078953606856,3.7800013559432974,9.0,7.679932117462158,294.3619384765625 +264,107.10749999999997,3.2599999999999985,19.0,2.0,0.3638425833444172,0.05667181149223599,2.9909986440567025,4.0,14.382354736328125,289.53240966796875 +265,42.75416666666666,3.7999999999999994,21.0,4.0,0.23179475177578865,0.14118558267662554,4.516001355943297,9.0,7.826748847961426,277.3910217285156 +266,59.5,4.448333333333333,22.0,1.0,0.08856532959742293,-0.08894817028163549,3.7690013559432973,10.0,9.116408348083496,306.83062744140625 +267,223.54083333333335,8.493333333333334,18.0,29.0,0.28266666666666673,0.16237033423838765,2.5230015819338467,10.0,9.724139213562012,275.94305419921875 +268,80.43999999999998,17.209999999999997,12.0,45.0,0.20516666666666675,0.09005667001444065,1.5700013559432973,2.0,12.184678077697754,275.28839111328125 +269,81.10499999999999,36.271666666666654,8.0,5.0,0.13630535352402612,0.015063930222742383,3.5849986440567028,6.0,9.139863967895508,276.663330078125 +270,33.47333333333333,31.56,24.0,2.0,0.29616666666666674,0.19532812500000013,4.030001581933847,12.0,9.443790435791016,201.46034240722656 +271,45.29333333333333,9.815833333333336,17.0,-2.0,0.2753848143272226,0.08483575642057184,2.348001355943297,9.0,8.897130012512207,263.7205810546875 +272,211.16166666666663,39.87,20.0,19.0,0.37722058610054915,0.1647520715924376,3.9420013559432974,10.0,7.622583389282227,307.65093994140625 +273,49.14916666666667,10.351666666666668,22.0,25.0,0.03658333333333342,-0.059684027777777676,2.111998644056703,2.0,8.062515258789062,291.82977294921875 +274,21.37166666666667,7.739999999999999,17.0,15.0,0.22859502359447628,0.0648571993897338,1.7970013559432971,1.0,7.752500534057617,210.2730712890625 +275,411.8633333333334,20.099999999999998,23.0,13.0,0.12186494133542405,-0.06979731833733212,4.645998644056702,4.0,11.818822860717773,287.4737548828125 +276,203.05583333333334,57.12833333333333,24.0,-4.0,0.05451251877751977,-0.12788471948577174,2.1400015819338467,1.0,8.93731689453125,303.17608642578125 +277,355.96583333333336,13.870000000000003,19.0,23.0,0.1952276048622347,0.06302126887539775,2.9569984180661537,3.0,10.53762149810791,279.3226623535156 +278,13.048333333333334,13.048333333333334,2.0,-25.0,-0.05785463953173739,-0.14492731525157285,4.374001355943297,9.0,7.6262030601501465,83.56298828125 +279,6.983333333333332,5.677499999999998,1.0,-8.0,0.037631319135029824,-0.04585035454255544,2.461998644056703,6.0,7.729085922241211,285.356689453125 +280,5.664166666666667,3.3299999999999987,15.0,-9.0,0.12757655470136042,-0.06617189680538343,3.8959986440567027,4.0,8.090641975402832,282.3855285644531 +281,5.825,1.88,13.0,14.0,0.06666666666666676,-0.009326388888888787,2.340998418066153,4.0,7.727761745452881,274.9259948730469 +282,97.76,2.854166666666666,22.0,41.0,0.09342263829268238,-0.026096703837487703,3.486001355943297,1.0,8.657599449157715,267.36383056640625 +283,68.42916666666666,8.342500000000001,10.0,21.0,0.22642103265163455,-0.0009257371515164203,3.4470013559432973,9.0,9.526407241821289,291.0509948730469 +284,46.5925,6.829999999999999,8.0,-6.0,0.02216666666666676,-0.012078124999999915,1.3960013559432976,12.0,8.363704681396484,292.1567077636719 +285,13.080000000000004,3.8258333333333336,23.0,22.0,0.1267500000000001,-0.0028246527777776864,2.8809986440567026,6.0,8.26823902130127,293.0279846191406 +286,4.3341666666666665,2.2783333333333333,24.0,-5.0,0.14493788413398162,-0.013924785299417652,3.2019986440567028,3.0,9.858139991760254,284.796142578125 +287,45.666666666666664,1.84,24.0,5.0,0.12452911223061235,-0.05391036142668733,2.6850013559432977,10.0,7.6242356300354,297.707275390625 +288,2.3325,1.491666666666667,1.0,-33.0,0.22966666666666677,0.11199249486785992,4.596998418066153,4.0,8.802557945251465,171.37997436523438 +289,286.31666666666666,2.791666666666666,24.0,4.0,0.25766666666666677,0.13274013882611774,2.496001355943297,10.0,9.61872673034668,313.4038391113281 +290,88.27750000000002,8.606666666666667,24.0,26.0,0.09459369023706919,-0.021655883996327452,2.353001355943297,11.0,8.782184600830078,279.4078369140625 +291,142.94583333333335,20.107499999999998,12.0,13.0,-0.016964982403435636,-0.13821909982042502,2.1560015819338467,2.0,10.447630882263184,286.8326110839844 +292,275.05333333333334,15.979999999999999,8.0,1.0,-0.0474525739782648,-0.331024234805694,2.7879986440567026,6.0,11.152703285217285,283.16986083984375 +293,35.19166666666667,11.023333333333332,24.0,18.0,-0.06633333333333323,-0.1302744515010692,2.402001581933847,12.0,9.937807083129883,289.37506103515625 +294,18.97666666666667,5.7266666666666675,13.0,40.0,-0.02866666666666656,-0.06725173611111102,2.9830015819338467,12.0,10.137873649597168,275.34759521484375 +295,14.69,6.940833333333333,18.0,14.0,0.1967500000000001,0.10996611232300091,4.330001355943297,9.0,8.825325012207031,280.4233703613281 +296,45.8975,25.430000000000003,10.0,10.0,0.23681747234457406,0.02410721713492575,3.444998644056703,3.0,12.529861450195312,276.9610595703125 +297,3.0224999999999995,2.866666666666666,4.0,-30.0,0.14193949977515302,-0.008321847454100861,2.7019984180661534,3.0,8.029501914978027,87.77302551269531 +298,133.82250000000002,39.040000000000006,13.0,4.0,0.1227279230805716,-0.0717328098749265,3.3680013559432975,10.0,9.591411590576172,292.4080505371094 +299,3.9333333333333322,2.9116666666666666,1.0,-47.0,0.09941666666666678,0.024380208333333403,2.859001355943297,2.0,9.730810165405273,288.52587890625 +300,5.1000000000000005,4.14,18.0,5.0,0.09875000000000012,0.03691754467328076,3.3079984180661532,4.0,9.769136428833008,289.7355041503906 +301,2.4066666666666663,2.2666666666666666,14.0,-9.0,0.09550000000000013,0.0012777777777778637,2.5220013559432974,11.0,7.568146705627441,285.1623840332031 +302,11.4825,2.600833333333333,19.0,23.0,0.08058333333333344,-0.03371527777777768,1.6109986440567028,9.0,8.050477981567383,291.31097412109375 +303,1.9600000000000006,1.6024999999999998,15.0,-19.0,0.20125000000000007,0.06600738494169447,1.9429984180661535,5.0,11.217289924621582,271.92828369140625 +304,29.300000000000008,4.423333333333333,15.0,19.0,0.24323164359661587,0.011769262585145879,4.2030013559432975,13.0,8.992109298706055,288.42315673828125 +305,126.29999999999997,3.919166666666667,19.0,9.0,0.2647431957665587,0.09732603298823311,3.4329986440567026,6.0,8.75196647644043,16.157913208007812 +306,36.95333333333334,9.714999999999998,13.0,13.0,0.30271441655231024,0.16230764224214456,3.384001355943297,12.0,7.499722480773926,289.3928527832031 +307,116.63999999999997,5.7108333333333325,22.0,8.0,0.240202479961687,0.047802495425807084,3.5819986440567027,8.0,8.102508544921875,311.853759765625 +308,30.55833333333334,6.7799999999999985,24.0,18.0,0.25575783640798655,0.05922567904317311,3.290998644056703,8.0,9.172830581665039,273.4454345703125 +309,163.17,31.381666666666675,12.0,-17.0,0.11098626588108927,-0.045164818666094605,2.4580013559432974,11.0,10.357069969177246,281.51971435546875 +310,114.38499999999998,14.203333333333333,24.0,9.0,0.1980000000000001,0.10748103363465342,4.209998644056703,6.0,10.653990745544434,207.91802978515625 +311,22.6425,16.5475,17.0,13.0,0.06983333333333343,-0.015630208333333222,2.077001355943297,13.0,11.28193187713623,276.43109130859375 +312,7.277499999999999,6.379166666666666,1.0,-25.0,-0.002916666666666566,-0.11856308824392278,3.264998644056703,5.0,7.721860408782959,210.1708984375 +313,175.98000000000002,66.32000000000001,11.0,5.0,0.08689477110211258,-0.047733317558655904,3.0330013559432976,12.0,13.597992897033691,286.3681640625 +314,135.72333333333333,55.11166666666667,12.0,14.0,0.2408696934338659,0.05379592155966448,4.504001355943297,12.0,13.061789512634277,272.73834228515625 +315,83.0375,60.247500000000024,10.0,31.0,0.2920833333333334,0.2333038194444445,2.7179986440567028,8.0,11.748675346374512,268.0958251953125 +316,32.759166666666665,20.111666666666668,18.0,13.0,0.2991580777056304,0.13285946123144898,4.392998418066154,4.0,7.988285064697266,275.66876220703125 +317,50.27250000000001,43.775,21.0,-8.0,0.34576687132411277,0.11876366836039015,2.3009986440567025,4.0,12.157576560974121,275.8736267089844 +318,97.45333333333333,37.353333333333346,10.0,6.0,0.23925000000000007,0.12974479166666664,3.665998644056703,3.0,9.333334922790527,278.9872741699219 +319,188.41583333333335,45.43666666666667,21.0,35.0,0.28467996840581217,0.07568793866646606,2.7350015819338465,1.0,7.71270751953125,296.4352722167969 +320,22.974999999999998,11.825833333333334,15.0,19.0,0.11946064067289261,0.004071590059246372,4.451998644056703,8.0,7.925320148468018,304.1521911621094 +321,117.14416666666664,16.279999999999998,24.0,5.0,0.16462400903790095,0.030716513213761953,3.7050013559432973,11.0,7.703359603881836,256.0624084472656 +322,67.92583333333332,23.49749999999999,24.0,-22.0,0.1994558161581783,0.01996757715910985,1.6120013559432973,1.0,10.416769027709961,279.25213623046875 +323,26.680000000000003,20.849999999999998,18.0,-15.0,0.017984100344553923,-0.06723251279094726,4.171998644056703,2.0,8.440791130065918,297.19354248046875 +324,102.09000000000002,33.41,23.0,28.0,0.19156819589139168,0.016041703962721393,2.921998644056703,7.0,10.704462051391602,286.75531005859375 +325,195.27499999999998,34.07916666666667,22.0,1.0,0.06916666666666674,-0.0011475694444443851,3.287001581933847,1.0,8.22249984741211,287.45794677734375 +326,116.22166666666665,14.203333333333333,24.0,12.0,0.0340833333333334,-0.022916666666666603,3.0569986440567027,6.0,9.027729034423828,271.7666931152344 +327,13.399999999999999,3.4591666666666665,12.0,-10.0,0.1636601547822467,0.03249678357937347,4.2750013559432976,1.0,7.533950328826904,282.76806640625 +328,1.8008333333333333,0.8574999999999999,15.0,-25.0,0.19650371281256973,0.01872226769733376,1.1979986440567028,4.0,9.010810852050781,205.3875274658203 +329,129.44333333333336,12.000833333333333,20.0,15.0,0.2717779520044575,0.02874528166607676,4.289001355943297,9.0,11.70299243927002,283.4332580566406 +330,86.09416666666668,19.153333333333336,14.0,-2.0,0.047645332208409066,-0.06235731021892751,3.601001355943297,10.0,7.969348430633545,323.83221435546875 +331,256.9525,51.67666666666667,8.0,-2.0,0.25518586742228994,0.07409389083232032,3.3290013559432974,11.0,11.461088180541992,274.7409362792969 +332,29.103333333333335,13.63,24.0,29.0,0.11061105732056394,-0.02665010243128453,3.2090015819338467,1.0,9.623237609863281,279.17938232421875 +333,26.30083333333333,10.132500000000002,23.0,0.0,0.42386105777553307,0.16237365381218694,2.1419984180661533,6.0,11.343595504760742,199.1056671142578 +334,12.400000000000004,10.979166666666664,12.0,-17.0,0.2722365122698933,0.0442845389212812,4.253001355943297,11.0,12.14862060546875,277.12957763671875 +335,26.095,12.30666666666667,22.0,10.0,0.04218871818626145,-0.031568000817688104,3.0870015819338468,10.0,8.425860404968262,279.72869873046875 +336,226.3266666666667,122.04416666666667,5.0,-18.0,0.437637686061809,0.06813907253622942,4.631001355943297,12.0,14.98900032043457,280.24542236328125 +337,11.030833333333332,8.67,13.0,-13.0,0.13023322411246963,-0.008176244606948269,4.174001355943298,10.0,10.152673721313477,282.8492126464844 +338,5.971666666666667,3.6041666666666665,17.0,33.0,0.1668333333333334,0.007646222341165493,2.8270013559432976,1.0,9.963193893432617,271.2194519042969 +339,11.430833333333332,4.894166666666666,9.0,21.0,0.02425000000000005,-0.042048611111111064,1.9870013559432973,9.0,8.665813446044922,286.417236328125 +340,15.908333333333333,2.917499999999999,15.0,14.0,0.10525000000000005,-0.017131944444444394,3.4530013559432975,10.0,8.57835578918457,292.0799865722656 +341,10.707500000000001,5.935,12.0,34.0,0.021250000000000057,-0.0466820000679076,2.3330013559432974,11.0,8.627388000488281,281.2730407714844 +342,4.025000000000001,2.98,24.0,27.0,0.08883333333333339,0.0007013888888889458,2.1939984180661534,6.0,8.960554122924805,291.6553039550781 +343,17.185000000000002,2.9424999999999994,23.0,-6.0,0.05459223318883365,-0.0196437087984122,4.616998644056703,6.0,10.57917308807373,289.43182373046875 +344,2.388333333333333,1.5999999999999999,19.0,17.0,0.15100000000000005,0.07779340277777785,1.3040015819338469,11.0,7.747890472412109,295.58319091796875 +345,54.480833333333344,1.1900000000000002,24.0,27.0,0.2821509979108912,0.07343261003362006,3.821001355943298,1.0,10.023198127746582,283.40802001953125 +346,57.828333333333326,2.9600000000000004,22.0,23.0,0.25375282235200003,0.12023305539398416,1.8489984180661532,8.0,9.21432113647461,272.8247985839844 +347,129.53166666666667,45.80916666666666,10.0,-9.0,0.20304221953136753,0.13977876018350355,2.861998644056703,5.0,7.779788970947266,331.3631286621094 +348,169.29250000000002,50.096666666666664,13.0,10.0,-0.0010997296089363118,-0.13766315105604535,3.6890013559432973,11.0,8.98540210723877,304.443115234375 +349,160.5533333333333,21.70583333333333,11.0,2.0,0.15592604029202947,-0.04710668283013496,2.013001581933847,2.0,9.109527587890625,290.9413757324219 +350,19.685833333333335,6.04,18.0,33.0,0.21201026543117069,0.06740862483998256,2.2140013559432976,2.0,10.582108497619629,272.70556640625 +351,73.34249999999997,24.70583333333333,11.0,-23.0,0.2566883991492208,0.08551167174654833,4.292998644056703,5.0,9.039578437805176,269.3879699707031 +352,1173.5708333333334,70.14583333333333,24.0,-2.0,0.4217200073015815,0.25026572891469195,2.1280013559432973,1.0,14.072980880737305,294.2030944824219 +353,339.715,86.98500000000001,24.0,0.0,0.1514614301276136,-0.035309924057603165,3.3669984180661534,4.0,8.8590669631958,312.3909606933594 +354,360.5583333333334,196.2875,23.0,43.0,0.18954168150416448,0.022973549853087055,2.979998644056703,4.0,11.319561004638672,287.74090576171875 +355,36.27,22.849999999999998,24.0,0.0,-0.005842600332741393,-0.11022109223965201,1.891998644056703,8.0,8.599764823913574,301.7046813964844 +356,208.9533333333333,49.86000000000001,9.0,25.0,0.1216784713102849,-0.051717988065403064,2.563998644056703,6.0,8.692423820495605,287.5229797363281 +357,66.24333333333335,66.24333333333335,0.0,-31.0,-0.05675520730219902,-0.12688723559672999,2.1239986440567025,6.0,8.716387748718262,287.3387145996094 +358,10.173333333333334,7.005833333333334,24.0,22.0,0.2493333333333334,0.05184201388888893,3.737998644056703,6.0,10.153996467590332,214.97396850585938 +359,23.4825,2.9183333333333334,16.0,24.0,0.06196512555833593,-0.11069256952537047,3.518001355943297,1.0,10.584833145141602,282.83612060546875 +360,3.2150000000000003,2.8299999999999996,24.0,-18.0,0.046083333333333386,-0.054894768231315894,2.610998418066153,4.0,9.052460670471191,289.53741455078125 +361,3.1516666666666673,2.690000000000001,21.0,24.0,0.09216666666666672,0.0167319918603855,1.6229984180661532,7.0,8.564987182617188,290.18292236328125 +362,2.6466666666666665,2.1700000000000004,24.0,-30.0,0.1358546100008955,-0.05404911092617769,3.6099984180661533,6.0,10.312761306762695,279.21435546875 +363,3.624166666666667,2.4200000000000004,24.0,6.0,0.17038353675553045,0.008141885013655537,1.3539986440567027,6.0,8.37985610961914,276.36968994140625 +364,2.723333333333334,2.1100000000000008,6.0,3.0,0.32275000000000004,0.14168576388888887,3.646998418066153,2.0,10.518367767333984,203.2516632080078 +365,1.93,1.82,24.0,1.0,0.07498459959681772,-0.03781368897121907,1.5779986440567026,3.0,10.170136451721191,287.28314208984375 +366,51.29999999999999,3.9083333333333345,18.0,27.0,0.1576666666666667,0.07022954200546444,1.6440015819338467,2.0,8.976588249206543,289.061767578125 +367,252.42000000000004,43.16833333333333,19.0,1.0,0.12698479157728373,-0.08318107269192272,4.278001355943298,13.0,11.772808074951172,301.4169616699219 +368,2.806666666666666,1.6733333333333336,10.0,-5.0,0.06175000000000005,-0.025388888888888843,2.555998418066153,8.0,8.453893661499023,195.44900512695312 +369,27.251666666666665,2.15,24.0,-11.0,0.31614751009157244,0.19336072832156187,2.0470013559432974,1.0,11.828133583068848,269.9294128417969 +370,31.899999999999995,7.190000000000001,10.0,-2.0,0.3685381922809928,0.07952109201065155,3.8999984180661538,8.0,11.317715644836426,278.16015625 +371,41.15999999999999,11.218333333333334,14.0,13.0,0.035833333333333384,-0.07582465277777775,2.462998644056703,6.0,9.829970359802246,276.1478271484375 +372,8.908333333333337,8.908333333333337,0.0,-21.0,-0.026302099239765203,-0.1216251650626396,2.0869986440567025,4.0,7.999703407287598,278.1973571777344 +373,259.795,50.935,14.0,-23.0,0.34610502854509934,0.15537458559385703,3.917998418066153,4.0,13.748801231384277,284.2099609375 +374,520.2966666666667,71.55333333333336,14.0,24.0,0.3670202703447928,0.06297644647802453,3.1439986440567025,6.0,12.200216293334961,293.2322998046875 +375,87.83249999999998,5.986666666666667,5.0,8.0,0.13028078136182153,-0.04769547557235801,3.473001355943297,2.0,9.382037162780762,306.807861328125 +376,201.9725,35.86833333333334,21.0,8.0,0.19640352332153968,-0.022319581336443517,1.6310013559432972,1.0,8.414977073669434,327.95513916015625 +377,52.01999999999999,41.15999999999999,6.0,-19.0,0.29146128140911715,0.08945479615764101,4.502998644056703,6.0,8.282185554504395,190.31089782714844 +378,8.323333333333334,7.035833333333333,20.0,19.0,0.019205010227117472,-0.12728148451015503,1.6949984180661533,7.0,8.671130180358887,298.43536376953125 +379,8.735000000000001,7.438333333333333,23.0,-21.0,0.3104597509865139,0.09944946199746152,4.519998644056703,7.0,7.867384433746338,116.84494018554688 +380,12.909999999999998,4.766666666666667,14.0,26.0,0.05975000000000005,0.007678819444444485,3.3740013559432978,10.0,10.716706275939941,291.9836730957031 +381,10.020833333333334,1.7100000000000006,24.0,0.0,0.20000000000000004,0.12228993055555562,2.276001355943297,1.0,9.616074562072754,284.8039855957031 +382,143.57416666666666,1.2200000000000002,24.0,14.0,0.11750000000000005,0.0035478902806314605,4.162998644056703,4.0,11.284472465515137,278.6455078125 +383,118.03333333333335,29.95583333333333,6.0,0.0,0.056778019664014884,-0.07135997609734507,2.026998418066153,6.0,11.154809951782227,285.632568359375 +384,177.80947178502416,6.216272603835011,21.0,-5.0,0.26172625826130935,0.07547681329612643,2.3300013559432973,13.0,10.74108600616455,267.9744873046875 +385,137.68833333333336,40.03499999999999,10.0,7.0,0.16607488153181127,-0.047158616456623684,4.252001355943298,11.0,9.209582328796387,299.6966552734375 +386,8.382594698158197,7.764635507751802,1.0,1.0,0.14708333333333337,0.05630928842856761,3.431998644056703,5.0,8.328373908996582,269.55657958984375 +387,53.87645733885986,14.983476805723498,24.0,8.0,0.27255197843498347,-0.020661638660206427,2.2250015819338467,3.0,13.093729972839355,271.9767761230469 +388,43.17083333333333,16.980999999999998,24.0,17.0,0.27542394736611026,0.06715631274071049,4.333001355943297,10.0,8.241395950317383,132.5605010986328 +389,14.820000000000002,11.735416666666666,10.0,21.0,0.10248264774314259,-0.012853813683875628,2.2390013559432975,12.0,11.180647850036621,284.9004821777344 +390,56.49,7.111,20.0,-1.0,-0.010209991995044285,-0.15367641081521133,4.346001355943297,11.0,9.715217590332031,293.4315185546875 +391,34.13666666666666,2.723333333333333,4.0,20.0,0.09523715529704282,0.03222773402929019,3.452001355943297,11.0,8.404056549072266,274.765869140625 +392,25.105999999999998,9.900000000000002,24.0,45.0,0.025000000000000036,-0.026105902777777742,3.9610013559432975,9.0,10.350502014160156,289.7410888671875 +393,5.308166666666666,3.978416666666666,11.0,11.0,0.043889126568437395,-0.03663688068267143,1.227001355943297,2.0,7.715152263641357,79.82229614257812 +394,17.668494747726275,6.593416666666667,14.0,16.0,0.1536666666666667,0.02861359917032727,3.5030013559432973,12.0,9.510577201843262,284.23028564453125 +395,46.47336818741141,3.0021690862754316,24.0,5.0,0.00308333333333336,-0.04809895833333331,1.8710015819338468,2.0,8.196100234985352,286.189208984375 +396,15.692874859656563,6.955928008148283,14.0,23.0,0.0356666666666667,-0.06508450035285125,2.811001355943297,12.0,8.571462631225586,278.1744079589844 +397,10.462160516729613,2.754427192133912,24.0,3.0,0.1665833333333334,0.08777998960087122,3.8820013559432973,11.0,13.102869033813477,272.13775634765625 +398,91.70657396103284,3.684006782406741,24.0,14.0,0.23037117050677797,0.011144944687379865,4.257998644056703,7.0,8.37102222442627,284.9960021972656 +399,2.2107181691507867,1.9860959697402298,3.0,-12.0,0.05864842274585164,-0.041609961024780394,4.031001355943298,10.0,8.41567325592041,293.2806396484375 +400,116.59754041547482,17.78398784376634,16.0,1.0,0.05376163357999267,-0.042344424008024725,4.092998644056703,4.0,8.903711318969727,324.9503173828125 +401,60.46015672490461,23.52520614222654,8.0,8.0,0.07166230440200072,-0.12345535762870033,2.406998418066153,5.0,8.217992782592773,282.7414855957031 +402,222.14479073246642,27.802464295413046,19.0,32.0,0.18340932954244632,0.042132378661613484,3.3950013559432977,2.0,8.629935264587402,296.8550109863281 +403,309.83037322632583,71.8823752333456,15.0,2.0,0.4107093580991234,0.09380931453033742,2.6319986440567025,3.0,11.920799255371094,275.0240173339844 +404,93.95749999999998,13.74708333333333,21.0,15.0,0.3782536365920806,-0.07992609174247056,2.0149986440567025,7.0,14.376069068908691,269.3013610839844 +405,67.839,23.456833333333332,23.0,41.0,0.10581574431525306,0.031501781288060554,1.9099986440567027,4.0,10.597352981567383,278.0785827636719 +406,67.414,41.11483333333333,24.0,7.0,0.1222432970732001,0.00047194377428615153,3.178001355943297,11.0,10.592103004455566,291.4364929199219 +407,72.96149999999999,11.920999999999998,24.0,29.0,0.064338486194267,-0.04736932078154152,2.0659984180661533,7.0,7.6787943840026855,286.06549072265625 +408,266.7635833333333,53.58724999999999,10.0,-6.0,0.1804142845550449,0.014229194580462512,4.421001355943298,9.0,9.788517951965332,304.54620361328125 +409,140.16816666666662,23.918750000000003,7.0,-1.0,0.042614215604700884,-0.027740200937158482,1.5129984180661533,3.0,8.350974082946777,342.2430725097656 +410,112.07341666666667,112.07341666666667,0.0,-36.0,0.15243064683877636,0.03143089636614388,2.932001355943297,13.0,7.875317573547363,281.15386962890625 +411,82.4767984320983,69.98,15.0,-2.0,0.11538330263890474,0.01366177094777786,3.8040013559432975,9.0,7.75039005279541,296.21636962890625 +412,340.65904186046515,53.77903566328581,24.0,-32.0,0.06937937036704914,-0.029396951496448408,3.6899986440567027,7.0,7.605906009674072,316.22772216796875 +413,46.05310539560318,14.682158371727915,21.0,21.0,0.43553775226805225,0.2868126166785091,4.428998418066153,6.0,11.380340576171875,277.2616271972656 +414,29.570775747039363,18.948090564095317,8.0,14.0,0.34225,0.24728819444444455,3.740998644056703,7.0,9.803524017333984,283.33856201171875 +415,26.409341165726392,25.788271829930576,1.0,-3.0,0.3074166666666667,0.1961024305555556,1.8210013559432974,10.0,10.154327392578125,272.97686767578125 +416,74.60779773165358,36.78944130072213,24.0,47.0,0.2628242046137126,0.08426477351987444,4.154001581933846,9.0,8.537044525146484,289.19354248046875 +417,178.87874434371247,8.8825,6.0,18.0,0.4388103381040224,0.025793779605439326,2.340998644056703,5.0,13.057626724243164,272.3252868652344 +418,226.3453409215385,29.53785905070201,16.0,24.0,0.3212765315653272,0.13064994880722958,2.303001355943297,12.0,9.79000473022461,303.1637878417969 +419,14.961348399518789,12.942168173778184,10.0,-36.0,0.09858091974129704,-0.026531532090147525,3.857998644056703,7.0,8.715963363647461,290.3516845703125 +420,18.462814107027683,9.03034801981568,22.0,43.0,0.10269532883189021,-0.05901387412225869,3.3160013559432975,12.0,8.917999267578125,299.0911865234375 +421,73.85832749806788,15.736779943434849,24.0,13.0,0.04075000000000003,0.003304462924804942,3.730001355943297,1.0,10.923680305480957,292.585205078125 +422,11.83747103040337,3.964112967031872,24.0,32.0,0.02400000000000002,-0.030506944444444427,4.351998644056703,4.0,8.097366333007812,289.2522277832031 +423,2.724493279764157,2.4718045012611767,11.0,-12.0,0.0679166666666667,0.0025190972222222385,2.2579984180661534,6.0,7.816391468048096,277.47308349609375 +424,1.8420041911712024,1.758489695273686,12.0,-19.0,0.15136970765924015,-0.06785466915982306,3.9109986440567024,3.0,10.211179733276367,283.8554992675781 +425,1.9329820309889039,0.29,18.0,-22.0,0.13508333333333336,0.03595833333333337,2.9310013559432972,1.0,9.399395942687988,291.6820068359375 +426,129.29267401166211,25.960181858947035,14.0,-14.0,0.2406182713486978,0.12997734201457373,3.3869986440567033,6.0,8.686917304992676,314.9817810058594 +427,42.47362445340219,15.05781418370232,7.0,29.0,0.2386943145383275,0.11640237494703237,4.024001581933847,1.0,11.02658462524414,268.63104248046875 +428,6.648691107688687,3.008984935824467,24.0,23.0,0.14283333333333334,0.055170138888888914,3.9850013559432975,12.0,8.256604194641113,283.1815490722656 +429,8.821439496441347,4.21213580432913,18.0,-10.0,0.0250455892496773,-0.07396433195641224,3.4380015819338468,9.0,8.773239135742188,293.86016845703125 +430,671.3244439995786,136.51071339098175,20.1045872936521,33.62124278696439,0.6031967077215662,0.08595148465681285,4.729964679765574,12.853734839036463,13.24983985847465,287.03941031593655 +431,373.88127916057476,119.0391999140322,8.003284275177045,-35.04383546183321,-0.05428402783127462,-0.31982030995946703,1.2808990240179732,1.1184097972414289,7.1060732276146314,38.648812744159265 +432,11.101333873522279,4.1589533114256625,1.2623542677420414,-40.56221194851222,0.07118592111189485,-0.1588903693683555,4.272612714673415,12.482560557733873,4.89340889355647,351.6303399061591 +433,80.61566272044799,19.854940728753228,5.0310863406794635,38.91823621991405,0.47539945380911264,0.3465900069968721,1.6833612746608746,2.147552060873868,9.226535521248937,327.3932818894938 +434,182.29604448328706,1.7761273379373328,22.581704426997575,38.114536851460954,0.0042723602501186925,-0.08238191198693781,1.4306183614965722,12.84025258359047,11.669115610999743,102.60175859435398 +435,18.17228495027311,1.2527490033812492,21.549037830846558,-17.864341765723598,0.380993528911991,-0.15305106089361545,4.794188896455701,1.602291814203536,12.98148683740827,133.5262018812286 +436,460.6554417508876,178.082411214383,22.581326592502123,-45.06557345083603,0.572657487270781,0.250315615033678,1.2732018016312159,1.8276123608867318,13.995842871408417,274.4775013378008 +437,342.66737710075796,166.1846167274604,5.677834480594987,39.89360214646712,-0.033711741076124076,-0.13147595170254384,4.626132304300291,1.357342693866173,7.279238565850751,356.6000552922738 +438,1135.9606897822705,75.19359626429323,23.863098342511826,-38.25266892620556,-0.0438753734213186,-0.2168389357699802,3.7216782398395694,4.427066666092244,6.847862413507082,297.420525788753 +439,966.3033604491999,91.90978992385998,21.883522642676926,41.19944120806568,0.28034044769651123,0.25014636569332177,1.2756966005565822,1.3279436581905324,8.622419927203874,28.142930833982437 +440,341.2848034212791,189.38365878677737,6.39138002842131,-46.65964404970884,0.36707043535609873,0.17353466104897913,4.458225801951975,10.870796066348854,5.945109720607769,64.32549304341917 +441,411.652102627133,182.33611657623425,10.732128749043193,-2.086210599979843,-0.013758079882861866,-0.23319759618492197,1.6041113007746006,12.006073426425537,9.107141655418907,343.9272624770862 +442,76.03749349863635,10.687232079260426,10.169955715843665,-35.88247814627162,0.6590021812200435,0.11083915275084782,1.5363296491039713,11.612009691996072,17.248864144006298,254.74645622945118 +443,814.1228243602205,74.48849852548186,15.065294954450515,38.60183692878954,0.0969806137882198,-0.16800621167454405,4.478220475963962,8.805984894398328,4.822290378725323,27.134674624123164 +444,1058.0728947795092,80.61653072354112,21.182129261286484,-33.80899512212757,0.25929624320019384,0.23599242624012667,1.6661954586653365,12.161160437936415,11.076882151562145,150.41618846897916 +445,116.26024905588807,13.567742295113888,23.7277193030591,21.168337124006484,-0.006438735967901094,-0.09874441923633143,2.120637344112571,1.0722911485237834,5.061644086007719,335.1462925032218 +446,277.86553877462313,119.42313717571612,7.294239747145502,26.322533633103774,0.43316129311036244,0.32732378577082594,1.5046634436216721,11.799920994084886,7.064963465244817,70.25011195366353 +447,397.82144352269137,186.3236887843654,9.762727278205515,25.172194482831046,0.5544577689200766,0.1189757373758798,3.815462130056285,1.5328121356148352,10.964914868971373,99.12312340192848 +448,87.01952399507215,86.16913970471911,23.08814807043521,-35.952135139435796,-0.06540692533242377,-0.12997282965634163,4.099638143248382,12.253223198184074,9.099122784217526,104.50591954839079 +449,187.96240623159883,74.46152368498566,22.34759496255341,43.44763375853914,0.5900608808145802,-0.07483333371616235,1.4940190214121636,5.034318365098082,18.02068325116514,262.07136046489234 +450,127.70781278058126,1.2545713702613888,0.5549698374179474,-43.36084448855686,0.06759993347327951,0.06964705853148001,1.3329929052686018,12.860286744748217,5.157203826243092,76.41198818818334 +451,81.36657255653668,6.527441006256419,1.0490517247206985,41.49446897402855,-0.031245657111127235,-0.3199959921388567,2.930982882166952,1.1505161385453277,5.13227823466079,25.357456408826696 +452,267.3786494517072,45.42278953623043,7.316355246373396,-43.52937019205396,0.42584651303315624,0.33410885726682643,1.779694521860363,1.1195521744987953,9.205648143998687,69.46542269000877 +453,189.09791143754563,9.491338795735633,2.776942083740402,38.2801753898117,0.45529014858517436,0.19159411107692653,4.571686938534254,9.563396289823693,16.608647878381397,228.5688401972032 +454,972.9751474471957,46.93801046810239,19.24211918022382,-44.37844935393946,0.4990158947668829,0.3598033631190675,4.625450055024755,3.1679075865528983,9.67477383789888,301.77782534747985 +455,1058.878689221749,71.52862994650263,22.303394201471683,35.64375060072473,0.4247144597745186,-0.07493440466824142,1.8953905132021602,8.592499564416695,6.813063988289111,350.6211817338449 +456,123.06748277520197,69.06243727618528,2.1582490026571572,-43.90038988990755,0.2152044131522461,0.07298529018588779,4.657411235230887,1.541030536279567,10.835038304382902,306.69864707788264 +457,707.0956740990391,35.384043634114285,10.692971711306074,-46.34302903988787,0.11751113635495579,-0.2609163351836085,1.3050701959790643,6.844691199741208,13.37021212137478,270.87840486429275 +458,142.47491477275096,36.82923886011892,1.2676991087934093,44.92219559135442,0.058553175901995866,-0.038520818529400924,1.6786042617522976,12.956379867441786,7.696289480779402,287.99440294823637 +459,368.07563215053267,194.47364540800777,23.811694728182694,-3.806472187741072,0.2452829434033983,-0.199592079166877,4.394483983876722,4.32541183296938,13.614639371820878,269.8739455961273 +460,76.38490902854944,46.67194595029154,21.074697784032175,45.77920105161144,0.43716307260660314,0.3347278350551954,4.701276939457568,1.4848545845807444,15.237741896596194,257.2476656596663 +461,140.4707778036679,76.35926935901226,22.573496298882993,-43.04230958291528,0.43496226887743306,0.19449083791112937,3.3950494529513167,9.966429577090455,7.521976655927839,335.71074195322154 +462,264.85380932810955,3.2298045208001303,23.768345236860114,41.71213158420808,0.10594300153191093,-0.06462759213936853,4.691389957461389,11.700350159640118,10.701137352467253,281.00140495423227 +463,40.81714164701732,28.760974777318356,1.7997408333668952,-4.188588687175873,0.06337055048153438,-0.09805322907719116,4.548479369494076,12.117055204741368,8.866445254934948,23.79269829879 +464,378.7110198073583,181.72257702137676,22.788684008689245,46.71046529371023,-0.034164320116341865,-0.17442365808372867,1.2493828950488595,3.3650849777143845,5.645211330349813,78.7830342151938 +465,350.41493804800115,190.2551271000898,4.209436701077803,-44.63378892523002,0.3205534915588032,0.28236374370594935,2.0397995873857315,7.048855081149269,7.49304954027215,313.5270086534023 +466,1060.6760178841123,84.45517928921689,21.40111597482235,35.05532068652791,0.42541255863899696,-0.1119535373040117,4.674076464439785,1.4056230308968087,10.07865946233947,220.3473376316117 +467,564.5363857956982,150.27781341470745,23.160104317332863,-41.93377132977954,0.3733514858373838,0.1381808499880201,4.411964962967294,1.4299197120943732,7.459032109623774,15.406792736969148 +468,191.05343908449632,114.775622890917,2.7148171975996602,23.19700282959782,0.17810067921625217,-0.22947589290036094,2.187376604689472,5.471693731963609,14.225071016766625,149.49096968874866 +469,616.9082618167138,7.085239915865195,19.03336936473112,-23.091430588478804,0.6164017507613015,-0.055554460993965826,3.9900602691491596,12.246966753700125,13.467640665032075,144.36482531480593 +470,35.60341703987521,35.31480929189531,22.04768961341509,-32.046674645147135,0.38088049487173686,0.2634796691736529,1.2168140259219167,10.779235560779064,7.963083231297556,47.177518098252136 +471,81.85222385035465,62.927069585059456,23.16270397204926,38.19836591881206,0.32606222679986907,0.021384501148325075,2.8372082317216996,4.385531518988776,8.196621201121118,14.134289235147717 +472,579.7415480061553,150.7961829848488,7.8473696052713,-45.43864738703688,-0.034459616874169305,-0.18977014118539273,4.73011684809119,4.624466029154774,3.508680930069014,208.50295403449348 +473,295.98374656716044,173.63594465663704,5.112917734368377,-12.753707587922833,0.4641203001402264,-0.1223039953993097,4.190510648723821,10.511877616009206,16.392423039195606,244.98256267748627 +474,528.4589957781603,12.367921002525307,20.552296788653422,-34.8999780623317,0.35149828662270177,-0.15363747360927368,2.4644087597318465,1.045774060504754,5.781190489583831,13.929442816261448 +475,611.6199251462326,2.478942192906435,19.005296921244366,41.723283451549904,0.6003431566404895,0.26495661579354807,2.097791664382284,10.810672906359375,12.880777373809964,159.09898587377094 +476,469.3916508239685,46.41175440356167,22.969494523658184,-23.918488032774263,-0.01647544087109236,-0.2597215201622868,1.5577449636210086,11.559647836299263,3.3381049978843205,283.73581050112614 +477,376.29484502347606,193.64135902762925,19.961590562826824,20.449045003337233,0.1103839333929643,-0.03561368027940892,2.8571820024765606,12.870368474789812,4.764714557120876,53.14284901695916 +478,590.0616273581098,11.772666663903125,8.756881319062636,41.17956229480181,0.302763008849668,0.20620162010734105,4.505883969463997,3.3856251882259185,5.173557516040217,261.0015667263203 +479,463.24607034872827,1.2394632714369722,17.07081708367192,-18.91562650209541,0.651323449543119,0.1531283969742463,2.3155513289492253,1.026542992802448,16.673479520383836,243.57633337804907 +480,343.08309914677983,179.7895763706398,16.767245580978912,-35.92594457506106,0.39201301408632644,-0.12745516789378994,1.2017291296646364,7.2963407051688565,9.123113951372895,104.13719119042956 +481,106.34575468258078,36.65476203346847,1.1712791692535023,-41.03613112411941,0.5630093752879342,0.27222830698044115,4.214669148817263,11.032612725932337,11.485087384846889,164.98165965902652 +482,182.3203455777333,15.342702220691356,1.3916198517573042,-24.418986911881326,-0.0003663063803645006,-0.23693424534477617,2.2305873803752356,1.2182031508513411,6.103390956181623,341.75737063935696 +483,591.8296857651547,158.7577558451672,10.444924670638699,45.19843983172663,0.5431353454785125,0.32770756222130787,1.6759255764287464,7.051715714709318,15.525082228405216,277.81207356811035 +484,903.7996383231144,43.29455236478386,20.600700140165113,21.494144833121183,0.050618724569043386,-0.2926717698686823,1.5071943307807856,6.010603966606936,9.189714707415208,59.65410653579668 +485,660.9922101049954,148.7090853030778,14.47651999485667,-35.81605675315788,0.2298786659025424,-0.16339064271627773,1.9842062774057942,1.9006028907827208,4.817434571465763,353.649490249845 +486,515.177501267876,136.35000510455527,23.641489250167496,30.449870090617594,0.3401981883419417,0.28132999698782885,3.077401026208535,1.1397696344398596,7.560750894632738,341.5049682476079 +487,855.7548634945923,65.32802790303232,15.149263561560996,-12.963243298851687,0.10167317295439791,0.09680990982186938,4.341255395854183,11.639562970041755,9.28349170616296,315.3551429487379 +488,208.96707735507542,131.3095933231227,3.7890423565273466,42.50441589709014,0.07335951298083086,-0.28901487009087523,4.251054594669797,11.758861958566076,5.108685332370314,338.5187223039019 +489,474.33546415211305,131.0747683606353,23.637758316714155,46.21708180972722,-0.00999052042807188,-0.3011152193358178,2.989114501821514,8.213095644707352,6.195055975465602,306.8581416623682 +490,48.817585802911154,2.018818421033239,0.19943309383510077,-2.216860559065559,0.39471791730898426,0.19705140818274874,4.273881896371731,2.1148552227293886,9.211273251654948,47.93202516208601 +491,438.84082278858494,0.9247643127091727,6.425796814809995,25.66587614131521,0.06502400369938265,0.0674255271372729,1.2219388321604865,6.173128094504485,5.407633126236746,36.69515547811788 +492,67.15538211697118,45.54500429943435,13.500798083825188,-17.699738191056863,0.19814482680264295,-0.23383278809979358,2.7805089223587522,12.965698182386076,13.44510706312591,297.2387622341525 +493,175.43791207114273,26.736418365842308,15.227281513533313,-28.597197509246406,-0.05626195436042308,-0.30406238677015096,4.618795079819118,5.6910433442971815,9.287738429282992,331.45641969044794 +494,667.8285377385445,64.72567888976455,13.357871298197107,-41.737199070111416,0.15471306769897114,-0.22857846334689386,2.429936422261619,12.688649261685205,4.534973673905691,34.72501140437569 +495,400.3781696605509,157.02437287922632,8.068623529787002,44.61557035382188,0.02842213099219762,-0.1464662543828258,1.2382279059938928,2.1498556299677567,6.504634107347676,317.128930105832 +496,183.4152625855062,29.874956780884983,23.381917670656343,22.21283253342257,0.3144730916941636,0.15364175335816244,1.3226015058666467,11.176140174642311,7.158681762215074,331.04518247811757 +497,663.7016096430696,10.960255601481972,9.20299945302336,-22.250546894867753,0.296804108552046,-0.1733369232106994,4.697995988302983,1.1463068306328135,5.9685725192658055,160.31405827390725 +498,454.71568178919824,119.09579764822399,17.93387382411428,-13.79954752998858,0.6210037695438102,0.17924644182125954,4.595916155599767,3.432189166879456,17.587691293922333,239.39234287179414 +499,5.495895265770598,0.9933034725731724,17.167736822330426,-44.343861779677994,0.14933089100657915,0.014627553792331882,1.8591470683696942,3.3614160088990612,9.632750514139266,238.91105098625175 +500,361.43021429482314,141.06619795765965,19.132719611372853,-11.866715837099179,0.5590540640426485,0.3732331541165272,2.5930455357780158,11.519975688020875,15.274578469223146,197.97151738663854 +501,286.8202430047271,151.43032596189795,14.66544624000086,24.106992533068308,-0.06997699270109689,-0.22675242917715255,4.182513540994062,2.3532004188511335,8.147472792316584,56.34330736545557 +502,171.8454128652478,126.1050019248201,4.847901289219341,36.678438084410956,0.26742359606492894,0.18023120974852253,4.804370391284022,11.786808468582876,7.2061499014623225,156.71935976781853 +503,490.4354515834462,19.952156759101644,22.2862778292965,-16.880742818729757,0.253965300949878,0.21977378115170304,4.515932704910488,12.071386683647786,6.055400771573807,8.337426550331623 +504,382.07895145705896,115.50030757428449,6.8908912315432005,43.39592417638907,-0.0513819949945344,-0.32811943112328046,2.1670196887294653,10.976686973740557,5.023022995374669,64.20597767030652 +505,795.3403533227962,42.8226530507451,15.663716701451104,7.285410553129346,0.131107862432068,0.13097035240357152,1.3372497161242014,2.9688952164500053,12.956416350904068,301.766061060485 +506,655.5091624970321,10.631877944961255,8.957661545707467,40.717936751421306,0.512781996553057,0.11323753414521515,1.638235736131458,1.17086801363125,12.232974071661513,121.6730302822113 +507,558.7582904213327,50.27960029264683,7.395177930445817,-29.350712558872388,0.2777766750906292,0.15883959481287285,1.7624456757520983,11.315376104539956,5.896166425038363,282.6178587540175 +508,331.9857440450497,181.68066259824,20.83650015460895,46.028248275501554,0.4427694615321893,0.22039097904498045,1.9135609889980951,12.17771047086917,7.158832394513444,260.8308248820589 +509,99.4376889352573,6.262272154295513,1.693979251494412,36.337345542339136,0.09041234218578086,-0.18905331024784922,4.444722555463191,3.9961503607582847,9.89635590003981,304.1479982799758 +510,352.2519773671316,125.02972395418283,4.55826173116198,-42.45521573487486,-0.030359138445753817,-0.31640956912379187,4.042997016750023,12.78286113916506,9.514334012530332,183.92537307198637 +511,303.9142536877737,139.65276919683166,18.513195390505864,7.129521612540756,0.4681071930096593,-0.036954551617161324,4.797577455824307,9.51532724242236,9.991741369198452,51.53553518766364 +512,562.5015800895253,163.53960846264235,21.787598011926335,-46.425304628945106,0.34384417991708593,-0.10242701583379396,3.3974107762551995,11.58195159480959,14.818829372666594,243.438906602527 +513,462.98121782384925,155.21944296125264,5.958595803506366,18.933474937619522,0.39779642775908947,0.27933396712537667,4.6728960232810035,5.500520891389602,9.92773560918604,342.3149555366115 +514,223.6939437644639,72.90690383210445,22.222407727977053,-19.50101109079715,0.24491578185559149,0.09028034846687588,4.579784718719169,1.4813830936558081,5.102071324756373,303.17577682415316 +515,33.15594146165844,16.78757383510322,22.170408633928446,33.8539201074387,-0.03156368593113232,-0.30343932736460183,4.677854976884532,10.022439122620115,3.7385198602878633,66.41140975602906 +516,624.6217826314321,25.225728232467567,8.578689875162336,21.426065723085046,0.4464059467472885,0.020429129605368135,3.1683793325576834,12.896818746897162,7.317264655725034,28.29536315082185 +517,667.4643450657064,27.631828939378394,11.324798530419653,43.44447731864395,-0.05522414090888557,-0.2793950769788073,2.9294254806849978,2.818513347370729,5.604367938871847,216.1553130143818 +518,187.7988585611252,56.44002047202572,2.170924808051537,-24.228313894774534,0.3025826401884867,0.07915027117041051,1.3699429830877545,4.086565821718911,14.766910697520682,289.07903423599265 +519,1075.4344801169718,69.71361078674455,21.167463309520116,-37.37062854280053,0.371358237283591,0.19375429970019348,2.1586863461510055,2.126895776075467,11.456306615221944,85.27976183138591 +520,191.0735754173542,133.24894781443723,6.441332649501055,-36.694843640710985,0.2463792661725125,-0.1170271424636111,3.814652809130963,1.8309884779588321,10.450163161094956,67.4352135535632 +521,422.07191842189616,186.6028205726411,21.590641612045076,-31.733540688596797,-0.055475261509031405,-0.26387573785501284,3.1484925628808895,8.536964577306144,4.72763394541936,235.5354815770267 +522,923.256994347883,102.11056402782158,22.152143417223193,12.563105668002002,0.10926482809497289,0.11805810249376886,3.234200578000304,4.636550063546254,4.517925811248993,154.5463680792706 +523,1034.0163913078538,56.78853665528255,21.90033157774721,-40.06003164357789,0.36041588650255724,-0.08838085454984693,4.260635312096814,7.343701148146408,8.02326391485477,46.83139449791304 +524,182.14744662653047,121.72816108357263,2.6117448382044417,-39.56889810582415,0.4954435888457144,0.04362290834396404,1.2769773712831876,11.82390812049959,12.282599263656934,108.67263487954541 +525,93.65118903558229,90.599538902073,0.6150400721089939,13.7045505106651,0.5905471661514673,0.12498369781256269,2.608562833505288,12.548187933601145,13.92952489219744,294.64796494815005 +526,87.32016280718503,86.9978136219056,5.108155177109923,29.226631738710722,0.6844698543499135,0.06636635106509137,1.3804379773853537,1.1332026948912175,18.451815803911558,269.26199737756883 +527,240.44167754829743,23.421028594505117,10.534623816594246,29.878194877750715,0.43124618168185924,-0.13717859502439247,2.506952109671415,6.902835827981736,9.329768514379113,298.63176405251596 +528,506.8781573149407,58.58631851125902,11.971953066193445,13.557165826296774,0.1614438242820777,0.1665666495827563,3.6726315261669757,1.3469478453107853,13.894538394009874,141.84688325955287 +529,123.27081383216733,28.109627346834486,22.9141226271678,41.629610949008665,0.5419912521984265,0.31534765780888047,4.754404509078739,12.162347346969952,15.308422785368123,250.5045723783121 +530,323.4848570567601,169.25365889872788,17.86249058530578,9.248417244990485,0.5313539688876019,0.2467340355428786,1.2262245533453575,2.018266905575842,11.004281267617074,79.86577881428803 +531,91.96817169800582,80.40990906224542,0.24099848042135186,-31.54445801771777,-0.057940289525992505,-0.30735939024771297,1.3058816921647924,8.252784406517566,9.86617972011275,224.86053876045926 +532,165.21587956770588,93.16847862446245,16.012199484068223,-7.8099835193150895,0.013105037969032673,-0.06475809924113918,2.175244394490056,6.420316231413814,4.758054679123797,116.3691579427417 +533,71.09762440152721,2.9486032167102363,22.602001779086788,25.289564187262442,0.5353074566622407,0.376747438131604,1.3974746408020766,1.9364835058297332,11.036902467627295,212.7515306629672 +534,1100.4232922427311,62.50306248059,23.480166880498643,40.07648550223911,0.299300090753967,-0.02438928404348234,3.4441355311185387,9.08305196302021,13.428417071739156,134.67997205997727 +535,408.2873564407471,176.50466765663614,6.0146232168804925,-33.79414551191307,-0.06065333173825372,-0.09084291175265863,1.3917856118304948,12.57519657768101,6.294916081959962,53.129669943121364 +536,272.5745529235314,66.67185405207509,20.23042216847353,-42.243658297473054,-0.045692450716227295,-0.2165466578585226,4.242985938676802,1.5468181279804476,6.1389479259303465,81.29267747887852 +537,379.311154552077,190.81646861998655,10.79374790371676,28.474579919541526,0.47037778305045574,-0.10256281268357512,1.224197569783875,11.401662906225633,12.732043624315983,145.77024466419223 +538,138.88182575451117,114.23489700285049,22.066422567009443,-0.9509430265404859,0.29049963506885024,-0.06849665497332857,1.2527742846588847,1.5419450304198359,10.104958848275778,259.61825008047344 +539,372.8707985635047,162.83086753048374,13.905922110208298,27.32618922691249,0.040810547241465295,0.024173195823832982,3.5523760205581167,10.274506231475016,12.59614857404391,251.217988496956 +540,253.11973632325385,110.65593340133569,2.69230173397975,-42.85382937938566,0.5709482144444601,0.3509048102009115,3.5605759014416796,3.867524003601411,16.26022277677317,207.39190008683056 +541,991.3813549266291,89.18083812845127,23.603839038587388,11.489588235990752,0.4651460974743453,0.3608291213292489,3.3584309998178297,8.715836405074162,11.814237936331931,318.13762576654284 +542,586.1145732084087,1.8250514931119948,20.29882466549366,20.120904017929476,-0.028361407886772702,-0.06099121925098422,4.562656967710332,2.4262891425891615,11.061603070334744,311.8099059575942 +543,411.2231353850733,29.45908471928205,23.79947200167381,-31.83243764730542,0.39918068380463634,-0.1458132090640475,1.216286093368579,9.249349442373875,14.864624650325625,181.8480155705401 +544,118.64623028403514,100.44804657018082,2.9152106440636176,2.9930538849304114,0.14464946845666832,0.029272352931374923,2.9655279534690724,6.732828910515397,4.343819135952458,307.9628534390218 +545,100.44801198554268,3.9035492202590865,21.066850956089663,-14.641309472899493,0.5624449509271128,0.31232468136568853,4.78025408376581,6.322444924748752,12.986206137669724,190.11105535345865 +546,43.6238878384728,33.820209317437964,10.12362695587892,8.961157792345581,0.2381253719686643,0.1278041355900788,4.6178175297292965,12.706196299544798,8.883632018823063,340.2585425000708 +547,293.58479664387755,154.36794454392665,22.214178071206042,1.3497523296977931,0.09646584463641415,0.08477012337967743,1.211119010390596,9.868300866557092,13.51551706994443,202.98211539248192 +548,118.80508746439213,50.47800965685638,11.111826274034105,24.7141396162977,0.5476617806972229,0.3409616862601585,2.9817939982084094,5.682235257688242,11.247469560294922,87.3154373424418 +549,895.0284050420286,83.67896384402917,23.091159230275846,43.30329265782835,0.49425762726312283,0.32356572516733956,1.268465833844806,2.7931403461841615,16.164193181576405,248.49608039101068 +550,700.3970247999646,112.52719546024743,23.151107015054944,46.067909105180405,0.2508460941070647,0.10290716658840987,1.376453245759947,12.538141160388417,8.631672044389099,58.19086485594224 +551,408.0711414637689,170.17477602529286,5.4689827877193995,-35.96259820084086,0.02130345363986566,-0.27561682954987526,2.7989113715774785,5.174789490665072,12.164957173131025,292.5574089937863 +552,893.9547024809204,108.10170537904354,21.063473802420987,-42.033497952364044,0.1986829546616699,0.011304774974713994,4.546575441991229,1.8499854259385655,14.399029327661092,183.5405719306128 +553,164.60492880302195,72.05310953264902,3.48168314865192,46.29990275713833,0.11816773409095165,-0.0018525859243587184,4.734865434866154,1.5463612932250133,8.72542408917127,30.435961011181586 +554,703.0149388298063,39.48283952814975,10.37569099238951,37.3342041012301,0.4363032595840959,-0.09938420179961183,4.376269729356769,5.571681001726991,15.999229391370132,290.0927185032822 +555,710.0431445569607,107.31321435256915,20.82614992617951,44.34230491927654,0.1563449045627503,-0.22334202417481747,2.0206127803858935,1.8986786976182635,12.342042224003306,234.7461342438612 +556,193.87400827838835,34.46640122293937,3.2230564416277567,-46.69792403007508,0.1786223364831434,0.14899330511176545,3.3706801731049483,7.151990396193938,5.665766323249809,37.61015319647959 +557,813.3406588540572,41.89612519966907,15.960670232400448,40.51125305191759,0.15927647307222947,-0.2545996744515238,2.5610293050266923,12.002974946630312,4.275956120622381,197.9997258783029 +558,228.29255536609486,145.00430341605093,6.807968182566604,46.905577741229166,0.15544094593924207,-0.06770848925651857,1.3172196173778499,1.7459981867430847,5.674312342222565,14.877616990872626 +559,629.7752154975278,10.941524765037316,9.64523609607592,-35.42147953199475,0.280094620874215,0.2611581238038498,3.1408241256868203,1.2395583243619939,6.490265566862163,311.0227972456069 +560,244.90102182830157,107.97670323318921,23.17319385278561,-34.60144909523876,0.5859326339582228,-0.0504597664977558,2.9740504006580233,1.9932072904212539,12.702603050735046,137.97310715961797 +561,535.941103072974,112.73809727070692,23.451484806886548,-34.77315526828748,0.014892627128781782,-0.28115932882908096,2.0048530221037337,1.402946923048708,10.915339713952898,139.44274516938992 +562,406.10532015951077,179.1395842569739,15.645364462526159,-24.05487490539276,0.40945559058207825,-0.030762566271732072,4.7699237680426165,8.788156814537402,6.744953323006665,313.4644662787212 +563,107.16464198723692,3.6776523192956634,7.135658713938506,44.15817967452065,-0.04964151007273137,-0.17933124834930744,4.249778818001518,11.88910383866832,6.888773889009249,217.82324689258067 +564,62.456419791807434,3.9475807050507172,4.987499285610969,-33.808762758005145,0.29649274647180524,-0.08282659862095582,3.5697202394210654,7.312360860496045,15.432252673032634,192.98293634542333 +565,642.316149926596,7.323776927716651,13.07408610370291,-7.317648869935681,0.05043755633903213,-0.27275986487306025,4.557489575276819,11.580365356433227,5.948141255933864,161.9808816658078 +566,779.0407748974666,35.21145528233754,21.09669145924282,-16.421856981179566,0.04958498390012529,-0.2781146424194826,1.4589777003696223,2.5786672939826216,4.0602311618618625,286.90962534338576 +567,727.8998308478593,21.050118030484715,15.656092565414598,29.175060457627154,0.13531354204415552,0.10666492597661675,1.5331688989763994,12.191806723652698,13.618019598522237,272.45634753415607 +568,104.42556888019077,96.29821869950851,22.822613252364658,14.319409701315038,0.5419068585451701,-0.05275765723387865,3.7154717856530004,6.4377403915841205,11.107651348318392,279.94254180267814 +569,117.41246924218709,22.829843727679282,0.3275376302833456,-1.1006194129100848,0.34424643543100075,0.26666658525202996,1.3210833464688458,8.119249668030163,8.59259804072174,143.55469178820343 +570,404.42957267493483,184.33532432514244,23.897371965693885,-10.47699566697058,0.3410544383316408,-0.17084746344928725,1.7514269822243684,12.984807405038502,5.933479534392966,290.7282251280531 +571,685.1673654681086,139.5749876462282,10.031055180669277,-5.180639972482666,0.46219574059504864,-0.023029029158045167,2.4716309621959467,6.5449211578188,13.225130534854495,215.150690041069 +572,198.50141437551332,139.60733839301747,2.677586031820903,42.558390008338534,0.005798374625495983,-0.273150052337125,4.395599036121774,8.496960872029366,11.270436484387268,106.13774095863418 +573,217.73204886482708,9.58633389598232,2.8593986595668213,4.833673076138702,0.5459298246526773,-0.02825951174992225,3.2968427414259285,1.2164875779826303,13.680630166698045,242.82248177258194 +574,598.8420579181552,57.32451167000535,8.42632236760215,-38.56934529343774,0.49117293674847706,0.3623530316065881,2.3574764611032375,12.668205145453271,11.679432335958799,90.04360025068493 +575,842.6900199232612,73.75993931163462,22.209719792205636,5.132784324785163,0.45001937801215186,0.3317237139289488,4.768075219455984,5.429196172880575,8.193125184980797,83.93623196992799 +576,416.08636955309447,3.406031853646363,11.972579614812258,5.829005982753465,0.02022074632019806,0.033756252935314646,4.650003369573194,5.092830466949735,6.48915830254272,12.72672575155195 +577,564.1909338012134,32.52487485891854,11.288497551275638,-4.39573312463763,0.514597703467691,0.2996403378141516,3.191929927143084,12.984706440911648,13.686779222755584,305.4450611501902 +578,112.54186766264033,71.77152967369753,22.688047967946353,40.83328756674372,0.13302662476690275,0.02903622913989823,2.9877553472073624,10.640315957029452,4.151801393048527,185.5941578518344 +579,418.54283023954673,5.743515541427158,8.93516731160882,8.617141988459522,0.14506741843138893,-0.20636306462132048,1.4466252381550648,1.2054122111596908,12.23349589958858,141.2360014791303 +580,479.2084327095753,173.53229805807982,7.32728456632007,-36.52850062760512,0.22944607661634875,0.21216418955881994,1.6305577654381254,3.390626572043568,6.963729071955694,62.05212647729781 +581,561.3702709154094,17.766687969700467,21.421130525935645,-46.01877525945634,0.5388519367000237,0.35276215569546004,2.430424125762614,6.809621310450693,11.378430601250766,203.5345926219147 +582,168.43794000485448,115.85184775554488,3.4549674831074,18.120344309541252,0.40581954994494995,-0.12666915648463278,4.643397396124291,4.586884575752287,8.58114985530425,211.70322783635626 +583,994.2592863350847,50.967821839561935,19.389431379943435,-21.177701479992393,0.4809576490204561,-0.11048994721969038,2.2098521878214434,3.930937358881425,9.459998117589574,285.59179573426206 +584,659.4853689122989,117.63682065707697,15.786022800588581,-40.84687026579009,0.10805461545909743,0.09978782748253656,4.759638488160017,11.246354965107779,10.591600735437876,82.28804291035419 +585,302.04643095355317,168.7475776461683,22.084888926198563,37.19193584750066,0.19878091479576482,0.1443859301846152,4.700696815191815,3.7022670381308522,7.680825627957706,125.29118595576122 +586,283.5687066558682,22.54126192459577,7.042157552086623,-8.70050770850171,0.23810588534047478,-0.15780059554045706,1.5235640001223818,10.586737265574929,12.769774409976545,111.31365375401114 +587,152.72892781533707,103.15519224322503,19.2026809886485,44.618265881436855,-0.028908033987251967,-0.31785862759890776,4.756991063073732,2.445625207444847,10.018422103263877,304.4237217332772 +588,438.20540776446643,174.51611492572897,19.63291693891169,-31.7011643842659,0.4009435398457186,0.18894163319218488,3.0267415289735426,3.0359035805826977,6.32672892374316,246.51969522940027 +589,106.508134895033,19.973157766278053,23.443307815340063,31.402231146836655,0.10534034328888452,-0.2181199729701293,2.0229804272360923,3.953153279188647,13.601331253786205,181.07766951149912 +590,285.6953411886417,9.257019276040948,5.388107782688758,-46.82209889498968,-0.06580359864747375,-0.24277488810079356,3.170028957730362,2.0882140319401823,7.315494754339468,48.33164536605477 +591,689.7874786023935,137.9455775039582,22.566377937060984,41.33624848861996,0.5712077591343496,0.3488862757844215,3.2316583649574016,1.8524078678744742,11.545190878545208,125.4748509074191 +592,459.0249872612955,124.30946739414756,20.524794589529456,45.03270583388725,0.14449117698532182,0.15854271048630403,4.510614667660651,9.063988213330898,5.2634891835603685,345.5891214759693 +593,316.92149738418703,15.290816044581614,20.81552877360301,-9.250563384005105,0.22893412084108977,-0.1448461837172474,3.527753679760268,9.79084189583634,5.258542750297116,351.97231953105614 +594,77.52408146971476,20.606751919730872,21.438121940520652,-39.71436340698863,0.2934344915656715,0.25612053291171616,3.1471424503653216,2.981049039073725,6.251172595927562,60.75622800409437 +595,433.6799427337193,170.52421318026927,6.029821106870386,33.18821191505438,0.3457511961010644,0.2271991018158745,1.4297352142927153,1.430127207779306,5.557874666930475,207.28154951065932 +596,453.8699426353244,138.58851487992413,8.850685412364788,-4.517842847930886,0.5533451143836329,0.3687442641140301,4.624449500653548,10.015292151623665,11.705430923003947,115.67072672309126 +597,708.0974679828263,139.52848390991932,23.634563345349942,-31.032311528559912,-0.02017402280721818,-0.21557109426140747,1.8055352419204842,8.302103211975618,5.969627765341714,19.46482167840145 +598,981.318232960713,92.00471012036394,21.78572035858152,1.135180548299921,-0.039386691515765834,-0.30603754804359684,3.6068228744387207,10.101727727122514,9.380416202114134,188.35656248916774 +599,424.35620937679846,33.63217500631093,6.170945894193896,-36.39043466999857,0.6302061507119021,-0.054155749035059875,4.592556425099036,12.582553349962248,18.295608847113193,249.8197483161714 +600,232.86846354797348,136.68852094496273,19.53931318802907,46.62614239787899,0.3754670557263438,0.23279222940577576,3.4039165503965423,12.907962146907412,9.95562037355235,61.09532305885726 +601,205.92372241691743,137.41843814206914,12.938184338164852,-37.52190102920348,0.4864129253481967,-0.058639993710248195,1.3380100471732301,7.946315431352401,9.344257914109697,346.89830311895383 +602,151.208863067867,88.66734920656927,8.9601200522285,40.90615241219254,0.10421762974336084,0.009811312004958272,2.4686398345951237,12.624719946398079,12.039923967147972,98.82351287151305 +603,552.6952172528171,10.023820510571511,16.808197905994202,23.38897638146028,-0.050129764696139126,-0.28311689909475884,1.8055163639279361,7.376352918658734,10.554774922501696,331.3421630006779 +604,303.08671319884166,3.0010353579537985,9.109037949163831,36.80184433935291,0.5696341768665105,-0.006299867658943081,1.5728261077924444,11.903642348249768,17.306784648372503,247.37356811120364 +605,646.2323785795516,58.16187114385839,11.78185946804918,-38.10784783377754,0.28200448823477586,-0.15210156755648782,4.807346379009276,7.720909926259716,13.517511776263374,227.27430069545184 +606,432.6640667060242,138.65982708530422,9.716746902542354,-40.63378199872685,0.6226022011702916,-0.0313190375466596,2.2251806703397494,12.232078234859141,17.87620599805244,265.8803530545681 +607,535.4710871192323,61.14788337276276,13.273241694564799,24.098730394046598,0.33185717425316613,0.2603919175458466,1.7768760098163503,6.678007822841886,6.286781873869335,212.719583034835 +608,86.92596732055033,64.74412984631815,0.09942997830021735,22.213746425781707,0.1482773355128547,0.11302880679980953,1.8745860781162271,1.464452947753129,8.96123960837912,189.3703623311175 +609,732.8253341915133,25.992485597680528,22.633508271357407,28.364401753843794,0.4238835172292615,0.17056061750619594,4.35893449074465,12.109605272160927,6.912604024075101,248.72106921140585 +610,245.86930839688742,27.389455635311993,14.886990768027118,33.16318334526184,0.30894127521502046,-0.18628396266427272,4.516115588288413,5.982961281009527,12.42381782660895,111.99937604594354 +611,351.43633444389224,188.44734742027836,4.498785426756484,-5.313009928172484,0.19108998486190631,0.18769941185842737,2.139728220840729,2.106432283285164,13.568026645681869,261.06386720420795 +612,167.2031434900284,100.38127183579884,3.1649322635817683,-46.39235306973387,0.23468121283497495,0.11122645331117381,4.293513432368742,12.708308984431874,10.617702065015106,314.0239319955832 +613,135.77418250005894,104.5013865814878,12.82534290890767,46.838591008373825,-0.03656912552459792,-0.31890624067842577,1.345913762094657,9.676376219604634,5.8402180982919445,353.12528304582116 +614,93.49244099255492,2.649624604119264,15.239024762129947,13.681917973206012,0.038004009094176144,0.044584069882392274,3.944507771209116,4.117048495694672,3.550312601877907,238.1707348897626 +615,151.53626993419155,120.04382586269544,6.796970704191877,-11.7982702856104,0.29027154906228647,0.2590642809650931,4.697372239158604,5.172368730817023,5.146706042291777,49.05480694095618 +616,670.9348861117617,119.051069669119,13.059285799733248,4.790144052516965,0.12220846643544318,-0.1973852896027798,3.5383728017749405,4.614354438527658,8.201224285699169,290.2787860648737 +617,89.6963477161863,42.39168415540774,23.85534857409323,3.962247277420076,0.4819933393216479,0.2807698148317543,1.2850887229223051,11.340049594990763,16.59347193209934,216.0139486312356 +618,658.3007775310956,131.21692506603114,21.13947147774676,36.530508090488624,0.637345264442806,0.06935015822493501,2.145235705532723,11.958359010361168,15.3772393496498,244.78309912322223 +619,741.9951816295089,129.9681054412784,12.625283110019698,-24.101101422362923,0.05500722477338087,-0.27792362511057317,1.3706068475211843,12.158086799405691,12.303218376856044,159.31561881213105 +620,833.5512272219838,50.21118846999262,14.630870577721852,42.60577160544727,-0.008972861773810369,-0.25480644493661253,4.643252206001621,10.530404611063041,10.111222119812911,302.6608250111025 +621,115.9676255217193,68.57671051776103,22.41510009155001,36.96163515618518,0.2952821309029663,-0.14169642770072338,2.779853625809964,12.475313600944363,15.448155371731044,199.1083852988082 +622,264.90863190821256,153.73244198861116,22.53369313086965,-16.166566451451416,0.2859011902174583,0.2606269753442429,2.6352076421146142,9.535960723478452,5.645406533245699,121.46614856089793 +623,647.8281530749668,145.60798848434703,12.336503672385794,-27.152753000026028,0.11687870711142233,-0.2677016486696112,3.4954018925426835,7.421012152596788,9.547962287813878,83.97028282819772 +624,63.12484286689879,10.307607319603425,19.52039759906782,-36.51498221049274,0.19626394679533615,0.17585771640477404,2.903286839903174,11.631611088851132,12.897867240783942,167.8991239654695 +625,397.63958914569713,10.225949725028405,21.40239834277147,-41.043072684064214,0.030386654450952483,-0.14698120752520394,2.505679529560493,8.132249858006896,9.457920092900128,84.23118283040002 +626,704.5492443165158,35.144958610969226,22.036390812518945,-34.793553025029084,0.5324153372644549,0.3857967637129586,4.746573439276432,11.713386764179953,13.37387969742506,219.76199546851367 +627,679.1185583715298,15.092688948454894,15.245865271199952,-2.1436288863189503,0.3392299113356915,0.2640487060397982,2.7115088381093,3.234776409777367,6.7261447779932055,41.38539768522523 +628,315.2173066884908,89.39819176957054,20.03997717402205,-12.587275607689826,0.4509763627282677,-0.13136381118097362,2.6220971471116226,12.78565868013483,7.594217373918784,103.54553183243992 +629,581.7679256467977,146.8530097113441,23.60150790809039,-19.269047602258272,0.43830099881634443,0.2473920132076945,1.2002461516179816,6.929748124507465,7.079815713089063,346.9260548150859 +630,1015.8690527476656,55.28668905136896,23.814885117006177,-35.722503541089424,-0.035948651502449934,-0.14346538294562503,1.734006676919764,11.888787229777535,11.131410749842562,259.3362416416936 +631,309.2276842412774,168.3184061601741,6.464768356277392,44.69351591413064,0.35231290755559513,-0.057011447376009605,2.5714998130526405,8.053855778444367,7.663234338892279,336.5169915240493 +632,371.17116436003454,184.51502229237366,5.382199659877245,29.902812058141336,0.026518315102783296,0.006729155830286049,3.265450464248305,1.0919013647065257,4.07071037630678,156.72374371745607 +633,697.0577686691241,95.7608508427878,14.279885283861164,-38.69133701298478,0.3676939211691423,0.3014446607839045,1.2417610158348384,6.0239122571095125,14.726490474396638,282.13764453373153 +634,735.4463869461214,119.18598809679334,17.13952384865301,6.437972885190369,0.36886512670543614,-0.101503074131999,3.6893377728174466,1.5558873436887013,9.265510280115617,45.19961179392834 +635,747.175071623232,25.723876140346256,11.943992997175991,-42.97652209525433,0.05259621949920956,-0.0020441447555479275,1.4666403723017252,2.919242448370921,8.68000582755266,64.92090679686484 +636,167.34484221621983,5.9295159728777485,22.106084169036706,2.7094025533038604,0.17560129108014283,0.09619373107267243,1.2930087843014222,1.6224658575717008,8.340288003143112,46.872650016872896 +637,38.0851385377412,26.130891254750622,6.326882140916002,-45.163425154862814,0.37815421504778324,0.24735018640804957,3.339696243191981,6.550144110622894,6.231640705070296,327.90638603028793 +638,259.3401882571293,115.39694237609416,16.261495716816697,-24.61201981130957,-0.042122409333439706,-0.25242163353598923,4.8058770116637435,12.4089300093412,7.979994329185587,335.07406266834846 +639,176.79994084798116,130.24943147936432,9.741208980869638,40.215426595890946,0.6251957479989249,-0.04383671037650888,4.275552200915983,1.0926380174033206,15.836259263385735,260.65926304327013 +640,968.7578088093838,75.88270412188899,22.03923285006622,9.49353541361409,0.20415466548321265,0.2083181724689342,4.8009188216142435,4.7153035565779495,4.550833366726617,343.5976375486726 +641,12.913735371612379,0.4063027611750393,17.355175744090428,8.29521060073936,0.2389164516552904,-0.20084324353911726,1.714849005077184,9.91076239010845,5.561340549252036,60.610086740667846 +642,143.6889208212169,85.26580724342992,14.696551781669486,-12.13936980218891,-0.02108763746779318,-0.29402046539815174,1.634242349467846,4.75518836366801,4.204934295015596,339.38733237555016 +643,648.3676154227562,142.0958400510774,13.639626738963043,-4.94027721542674,0.2951807995918717,0.11705081651355709,1.5196796513221251,12.920928447796143,11.213128480150552,329.02077345824716 +644,914.3312495198783,101.42537439052427,20.551449728627738,42.99115873730673,-0.03643364042502562,-0.23513484912724764,4.574305573925609,3.536199316387619,5.845488308424134,215.36303204068125 +645,354.47376554365803,65.1465605139792,23.286953031759612,44.98445525734074,0.2939144598929324,0.215469131410924,2.6255412433817087,6.739436113250985,14.14749669349478,242.82325002379588 +646,72.84358507991107,63.25686870556722,13.089998145722792,44.35418706999026,0.5233253759604416,0.3538130468119742,2.7056349670890745,12.036286138373882,15.39538789388384,294.79662120052757 +647,421.6769490411441,83.11744445454254,8.400154752574792,-9.730619416303682,0.4392858313183573,-0.08490738298406697,1.6554114402364029,3.074885367806629,9.047568113303626,42.522788706704084 +648,451.2694525512631,34.19265656750764,10.99861842754635,45.31948014267276,0.2574139254384541,-0.015596226370471089,1.5526825140769993,1.2731864139919864,4.843285257257461,305.98551111500393 +649,28.3583098109126,1.3228250510004553,2.35631815758263,7.668077739072153,0.16819081739820924,-0.2439713833053525,1.7419249824143246,5.479090592953001,4.8856096315477595,142.74531206276401 +650,43.29771943454209,4.310571707631668,17.22416490874566,37.911171611930115,0.6042971493804031,-0.02626257199628107,2.360863309869849,1.5057890176805429,13.506571458357312,151.4000025961489 +651,150.33399163005416,103.25674466513911,4.010289291629734,44.51712139268621,0.42729512961994176,-0.03531328041405968,3.1288839842093292,5.810766082895476,8.034155503295837,42.51210268654396 +652,368.1818717208828,176.30561522542615,14.929877035483747,13.429873745560656,0.10920071611482023,0.1028822615560902,1.5942932570527173,8.285065648350923,4.424428770881754,287.7261064711748 +653,229.63602313222535,25.107321702399513,3.0417418321675274,44.136575418247745,0.17850832694866164,0.14732286126610677,3.4061700706544533,9.165338445032482,4.940512754954256,142.85556557101066 +654,404.3486326512112,19.89877497965777,21.809610756639497,26.087534909025678,0.36784024690114125,0.07350760956919494,4.482284213886139,1.0668908785341515,7.719231584473656,143.91639291624645 +655,560.3921540447267,69.51403003155274,22.503303796848783,-11.358176911102248,0.2608733284417688,-0.1781724636434999,3.3770821682480463,5.940340758836165,13.76604623950848,153.5071125920691 +656,630.5446655605858,145.62888728688353,20.57768150969151,-4.980832405659946,0.1230157746629648,-0.002722450414571753,1.610373962958082,1.1723000691278782,4.145781110675934,82.61804094348771 +657,283.04437042475274,127.73603398273615,6.278010042949245,-22.08746733589679,0.19762613304547721,0.17307800688043135,3.3406813598869824,8.697498779671577,13.889842839760792,145.31726272357923 +658,598.5052278237532,84.6662552960849,16.03729852923002,37.20451606631124,0.6178820106807246,0.11013765341270426,2.7681497134539983,1.5711620811762383,13.652051422982241,307.7759663378989 +659,410.396865039282,176.1069154570251,7.457729206240545,28.225777204132797,0.4940792534060171,0.3120097439020714,3.0372757795122167,12.85298457270907,12.40109035443164,217.60183624560625 +660,393.96770082008925,166.7905898531693,11.439804219670043,44.19980082037215,0.33907285135495063,-0.013370906485408118,1.9495313844605566,1.3903173405455023,15.381154739254129,218.39182703824255 +661,93.99556614798489,51.80666353783931,20.015809951992132,-16.014433404406063,0.3516765050516003,0.23430606918231128,2.94009934485633,2.8171493396756566,12.016419445903178,324.0059517573467 +662,386.7848553207777,189.87159827183993,21.11183465271933,-45.973875200632996,0.0919767338799911,-0.16702685530371472,4.395737216521079,2.847623006864075,8.553563455096587,132.7101858290119 +663,777.1864673954261,87.43560844961036,16.905390470687713,-24.7886309358598,0.22595554215890512,-0.0659578176886178,1.3367629847507474,8.115026391497423,5.689421200658572,171.65668117267504 +664,577.6898989737489,131.21189207369355,22.28359353627114,12.240542978238402,0.32130058834212694,0.24781491670546124,4.28245354211893,8.066754599400415,15.11159763572243,172.23566121331035 +665,684.9004427992265,57.089867353563704,9.826722135060702,46.75383748911436,0.19785491413792822,0.15704140362425434,3.7547509266426076,9.544807159496223,10.501559890174686,277.0272207504295 +666,115.38178612318342,101.4187359209515,13.546177651212192,13.186364127773523,-0.03284136343198401,-0.029754233876578606,4.328481974926736,10.517960914359348,4.062254314060909,100.02399305282428 +667,86.94832040618253,27.84379148507735,22.14014444819791,-30.76410987450662,-0.019125695396920737,-0.30430443021138615,1.6711529920763408,2.2723154152705733,6.063014090870135,33.87551297949737 +668,340.4160983085434,180.00047245597432,3.8250128185584247,7.32591275793623,0.13594128614264311,0.024873420901891097,2.4048587541810464,8.5550168081384,4.304069541306873,50.896542622026324 +669,46.15103313061668,42.516078078472624,12.205930660809933,0.31344259404442454,0.19329409301308748,-0.23876606787100113,3.5682042515308883,1.811928505550455,14.572034056363488,226.18240059512527 +670,795.988270149245,110.36247088985029,23.30760958215331,5.764398099409114,0.1800521362648448,0.09896146873957179,3.192362585181728,12.539529797020098,8.56946419698869,137.22037939971574 +671,142.71869214945872,1.8971593730025207,8.70370085720139,-45.14611102913067,0.3361910996813135,0.22437336427680193,4.496814631190007,2.2927236262431796,13.528702225237602,143.38430710897026 +672,893.6517931097509,41.38816524943908,23.012762399979216,7.358534531456044,0.4938522945002922,0.08722867014839353,1.7330555391501425,8.469196975041767,16.55339005867382,266.832438889359 +673,494.28583826404207,2.1546979048876453,7.982140649375103,-2.2041320615388784,0.07218552798746995,-0.2521545498433619,1.8307650425558997,11.710433291355962,4.916547516131655,334.7054954127633 +674,585.7458329899681,2.9284640137145708,10.389708243154596,-41.61075686968564,0.47265447178725895,0.21730346226170266,4.03150679611426,7.800261224770758,8.536231267393342,105.12964049483543 +675,123.16702416904238,102.50037838281122,10.635930814176048,42.78821458622143,0.4531930709944745,-0.05297648606286137,4.754312172463496,11.830113421209589,16.282435485237237,202.21083359221333 +676,132.6760183167493,3.408568059446618,3.2582511272509063,-46.09736664542643,0.4337426684821617,-0.11373673916109484,1.6722666192453586,8.120387537202568,6.827864440168551,176.27075594180414 +677,681.5888456723017,145.9938255320227,17.97049672914719,-43.047088513442034,0.45627592648312787,0.35280165916657696,4.4686489811185615,10.033521293049368,10.559724876392588,313.0384379554261 +678,381.1871823162088,7.328818692467339,22.769562660482904,44.728324634330335,0.3959450275209391,0.23820022649614553,1.4650806160165701,9.525786232945622,6.400465774341859,23.54084905790907 +679,172.7819829464715,63.1183862262036,13.663059378571939,36.61359532763373,0.05266730391733848,0.021853427731228336,3.2016944391881044,2.001271269282603,10.414904964156865,330.35150063985196 +680,323.0813392647184,110.02944737341393,17.762045561369483,42.831166771148474,0.32009556634496544,-0.18694363626456012,1.299121726826405,6.391818316164664,8.968113256101947,129.64139658837348 +681,848.8501869067273,72.12275648342084,17.751960867039966,14.087874090257202,0.4746327125378652,-0.12220117513500917,1.3763745449046287,12.246141193369644,11.812779073222789,138.27429851222675 +682,509.7861584012628,22.036773827732947,21.678373688256247,-33.73671521383206,0.47133371182977557,-0.09672967073186564,3.901007498218001,2.1009393427876084,11.509513437943511,307.6637595079709 +683,558.9675972634972,104.32599397306616,18.896746008053903,-9.2159718351907,0.3821332243643665,0.23353338226275938,1.1819928048653932,6.425251796814038,6.36841444541682,8.441636379780482 +684,516.6210939946033,4.274346538504912,12.206324537057078,-36.96709850872038,0.632145578105097,0.11980015452715465,4.607109024914828,5.898879537126494,16.000116968838743,287.37644603574586 +685,593.6572957130713,89.72599574504508,9.354799136929273,-38.11162514688405,0.24546582520680382,0.22271594136586853,4.564746386518967,1.1178633181992115,4.98923927973297,164.31839603100627 +686,388.192467570713,176.5017176967567,23.535512171858976,8.855469664022301,-0.035617521083061154,-0.1600127400354194,2.728393180176714,5.225168453707276,10.724145744813939,145.07882642836088 +687,32.65378253460562,24.03752339325863,9.624837862112896,2.852054628643508,0.35571619455898335,0.1637293534977602,4.803418015126086,12.79704816375341,12.89815641589446,117.86490281177807 +688,442.90682768064033,58.51402329880296,6.10930055626562,2.4083066199444687,0.048845370934780905,0.016027507977601607,2.93120248645236,1.8176772466219984,3.8839602108721887,81.60886802611084 +689,356.56187468253876,90.53232336435313,21.220385294368256,-46.30951732168215,0.03225177898497582,-0.2301083070086793,3.257094180206363,3.184179173669139,3.6508181502808568,291.4417525368081 +690,742.1954685571259,47.6820627469156,15.206523106814151,25.98336454593887,-0.029641475339502545,-0.2613547189938076,3.6756645971547544,1.3824446051994326,7.491224480707315,8.021367845801965 +691,589.5254426967587,34.14573927045814,11.340316500209449,39.02304506041547,0.10781486899032887,-0.03222039474506566,2.4037236043994534,6.522073012416093,12.858696876882641,120.59914258838226 +692,43.48931786587492,5.466705374402599,0.9542605392542461,-43.463529952938316,-0.04199554517293502,-0.30787216701464304,2.7067562981139384,10.99063059499019,5.414769864430389,152.1295755227542 +693,574.820423760376,0.8677892200486872,21.468525672486717,-46.62036111139596,0.19789694321118817,-0.017009885703756278,1.7831286594074367,6.806344559780766,5.4127711080697125,329.76761761526626 +694,168.71081940820477,87.7019845703522,12.907563083794518,-40.86345552809593,0.07519854721978657,-0.03841906845081361,2.6590709088926667,9.060883744073083,7.26500432251814,354.15545833530354 +695,362.54076785516787,81.15105270502323,5.606249400858619,-30.591839907053412,0.2959520545018559,-0.1536347592138551,4.533497126836687,7.328383035039492,5.11355927315185,305.30872486277485 +696,126.25620154929938,72.24926507903602,20.41358290043739,44.25463212203448,-0.009193186207965817,-0.27959664628775327,2.7715915720066686,3.2496658981730864,3.7539974441167314,56.515388931483734 +697,401.65716134578855,186.0399473689978,20.089116959074893,-41.90825204824554,-0.018626829110790347,-0.05281284376719059,2.7859750340381733,2.676685999305909,10.950135632390612,326.1000241946558 +698,870.4059579699722,84.16865284928542,21.092817660654276,-39.417451995193765,0.41947210380363104,-0.12710444218651187,3.5822302702172015,12.72139264043187,7.557294129017853,333.51358566846596 +699,207.82090635347421,31.94444187485807,17.83520938507651,43.91646935934406,0.27811106670764607,0.15592434940476313,4.733195254553423,11.919710300443109,7.643296638734608,56.79080252892345 +700,25.455599496846503,22.117261058493806,22.12823398471499,-33.66014360146726,0.30870081949341244,-0.08465742168817986,4.7053841773174945,9.75324719171604,11.571162397821848,263.13374175965544 +701,163.8952827512832,113.04479794897351,2.6014670066398122,-5.022253741631488,0.1316986657547431,0.13367302357243677,1.6377180792594346,12.542626185109036,10.874179309202447,216.30040630981173 +702,645.1304354807684,21.455995307374046,23.872644170793706,30.53475314363979,0.44839539262413086,-0.11630027463322262,2.9725323553919845,4.3982109587052,8.057516660544682,267.02580512836 +703,159.85309958282735,96.9638146875773,3.231580029636662,42.50254878138209,0.48924365478463816,0.31731905449441417,3.015624261652756,3.1494291010236584,15.68664648287672,286.04306737297816 +704,231.15409181772986,139.65143916322975,2.1043695275794385,-0.7434106365062689,0.5473577590428722,0.3444432587333645,1.3926118291917844,7.813871256698558,12.36029769600919,311.6199556946929 +705,697.8805178841089,20.527944451945018,20.819810931283023,-3.5295794957992186,0.5110476666751316,-0.07259770858274406,1.1907643652838942,3.5669206846091894,10.693425863947528,67.86575340179779 +706,442.41796587258926,153.40030433215836,21.853653362545106,18.85546240584314,-0.07075635392523352,-0.17889178546748277,4.536605258951971,12.360601284327174,10.024370981304589,47.50005575847075 +707,320.03740010689927,182.32304416512378,23.94731858677934,45.97164762864924,-0.012397597425057576,-0.31256260662105123,1.483003265469698,11.666417787102112,11.487033873481758,258.94680519248533 +708,317.84337216344954,173.22470918247,12.468965486619812,2.416835366265218,0.6343116131748835,0.17920605059292044,1.449243560844855,2.092339801826374,14.875061029311746,290.5311775844996 +709,899.4401082539841,112.14670177356862,18.533292563402842,-44.08757973810306,0.138674045517297,0.12643997560831044,3.9771691295867893,7.685849110107185,4.351627055235556,205.15243133490114 +710,391.0351117029382,71.98802960497154,19.79095875514242,-34.15693688320452,0.6074787153584144,-0.06124518951770225,3.2919409562057504,7.455375752510536,18.34299526992743,259.4577772913077 +711,752.1558212621263,128.64793289062294,22.426631391953887,41.12452315605117,0.0742383684978447,-0.27547382347431515,2.3180683577757133,10.004048441234723,5.048086698635604,45.46551774608479 +712,44.15203141333702,2.158551118024527,3.692292550012921,31.27590968079798,-0.013453993919756546,-0.1343644677484872,2.128585144679584,5.704627077645573,8.26343102173955,327.1897222787253 +713,317.5714086561753,145.8505506808469,18.3886080699857,25.742059317650785,-0.0036537433767122873,-0.1944798737700014,2.638825184060561,1.3114870850731957,3.6438731403039935,241.71690308368122 +714,472.4145816244629,24.224432936807,12.24482790512012,4.521494174703996,0.4867564902113485,0.37827656817205985,4.57983981538126,1.852067537816415,12.833458279589319,252.27568103879594 +715,358.1225442298518,172.9918947232123,8.547439638913993,-11.822805325239074,0.3992881221993435,-0.06909767545489065,4.44413660463835,2.2006143314548394,15.765929994747724,268.8438968135399 +716,1031.8003971250819,58.54157701747616,21.636462351239597,-4.353309190442211,0.2916317337947749,-0.021745329168963157,4.387020449988849,6.473308432641261,14.486030046328333,294.4365028851253 +717,454.8767683515168,7.8478424586614555,7.70864960316954,2.036174616847255,0.47149422946522423,0.34034722621767627,1.5766958578702188,6.210915691217806,14.976437707119194,257.59281540340305 +718,434.9415438948899,125.5833657847229,10.525428289966682,-45.59413990781626,0.1987883307221704,-0.04312211281465694,1.36609384323563,3.1980772418367103,12.137159484549231,202.42494762140745 +719,742.2678908082033,80.67621965650672,21.412029311968947,-44.26622411436526,0.0005658790173813516,-0.26618920255991646,4.395100838726196,12.705108435018971,3.9830625727452187,206.1566552755701 +720,209.23997311424003,105.84695732303891,9.902053856128418,-8.496882912925535,0.23575624256039102,0.2322638693932086,1.2668147593249617,2.7651152741221856,4.924112131883229,294.4188591974264 +721,114.01781467859813,66.45802449716365,19.925261122823784,1.0871244771891568,0.3059774921635092,-0.1710613989138002,4.393116175987187,3.1544368316194706,5.7255003154286435,17.63411469098301 +722,310.97925071913215,134.85446362190396,5.065774070787353,-40.0061617804814,0.21706005117033234,-0.1726306808938613,1.6567304071804863,11.632438919673,13.871374789273741,301.93855403977744 +723,129.9588848111879,110.83627392022188,0.5945571521966908,25.332464491189015,0.20417707461545603,-0.10797548934710119,4.079943114399834,9.49782044025576,14.359035227105787,289.5183637275496 +724,567.6636505335542,91.33378315166632,8.322790974294163,-39.11016813710101,0.671671638619178,-0.03719388123852396,3.482553794322251,2.2334551479411173,18.292735147981283,245.33202465195646 +725,20.168066202582413,5.066355359482493,14.771610868091699,-37.93107418225311,0.40730848796936786,-0.06665619138094875,4.566074710463277,4.369607665761171,6.629275469649755,349.0027319372699 +726,719.8129839786801,12.122712014919768,22.406624352384913,-15.60101030496741,-0.000628748330182366,0.0035820679932225263,2.9163679634652255,2.4723425951753595,7.792006279401184,161.9012684061825 +727,417.7415565101387,20.920263456819256,22.46035206517363,38.35700914884859,0.6536028936311339,0.009725702310297901,3.8984285884885406,7.927216739060765,16.99205463013287,256.73465650061115 +728,595.596469954886,141.74517905730292,12.973841372106426,25.260255705087886,0.1637073735502086,0.09865492485423327,3.2712174546347983,7.180774175696072,10.058689872101912,64.71170001499065 +729,125.83938874467138,20.1066419128628,1.5084947547783316,-32.25560792849805,0.5152228742201979,0.18124827246754366,2.344242775085138,12.942031111077954,10.19994095363226,334.7928727651182 +730,322.2944690465926,170.5582346355856,22.70278152155594,10.164184738631008,0.39954149293902297,0.31535864740187564,4.097637432550124,11.94341405280931,7.067612611638856,322.17012189800386 +731,374.39030810737313,164.23439664460682,23.118157131973554,12.640003842591007,0.19603568198834886,-0.17217116185239986,4.194131510286735,8.677854850516837,5.341049870610117,178.4662385930424 +732,648.468694129546,112.687220067038,12.86377191130145,-33.27486638406912,0.44528628220484723,0.340988803190406,3.162597452658005,5.628489481144111,8.998013996949904,86.36025929414097 +733,471.47576452218027,28.426603168287752,6.205391161718118,30.748454008860733,0.338849561067086,0.292994376124938,2.1799697903903734,12.585017221917823,5.954837392645856,313.7434652627132 +734,480.538577286495,20.579609043842215,6.640527323827451,6.318210105688799,0.30595691330230956,-0.17371198443196498,3.903612382001083,10.865938686116968,12.757285433854143,264.78188127553057 +735,829.7060425520594,45.80507062134797,22.968838214442847,46.58179796025922,0.4060034113645504,0.28635812647601816,3.9888612876002663,3.609121039283661,9.662897511214673,293.9690930515533 +736,532.1213484202272,101.35839504039636,23.782778359269983,-24.26837468154409,-0.04337800797088197,-0.05170370792991885,1.2289894498713845,6.696178481694815,9.479114046998266,299.4500647224734 +737,649.7025355916578,146.62186644441627,14.251019033021382,-24.037573580054655,0.005131754637892727,-0.00625780217346239,2.320745956231014,12.60271128559824,3.7310690754664866,224.93459992349173 +738,398.3830107651032,46.6760600814964,20.392696567555475,19.971209912490423,-0.06472763349328861,-0.18649547891004606,3.4343182634739557,12.736401944521054,10.462751179553404,152.10961666255866 +739,491.56801893495236,5.41441755269595,21.95456993484042,4.648278413469022,0.4381629188027891,0.3501912742985122,3.1701699996386505,9.21395064871779,7.805061606253016,120.98066666977276 +740,311.8592605911874,176.78033744728452,7.440306712522737,-44.12968317008833,0.30386148872125307,0.23830098364947133,3.682449761511675,1.302472479844106,9.963943111950574,316.17624008188693 +741,786.8004297871444,123.69663154852893,15.079479399557677,43.118114410494854,0.15254488950712386,-0.11341537682533459,4.610826820399445,11.842635757527145,12.744775351748203,144.8816859527295 +742,39.204899190489,23.29426568333594,16.53028605002472,41.72193191502879,0.35098515060954627,0.26647290393180806,3.9815251631891133,6.9406326298554655,6.3324902047185,225.02937279958925 +743,474.25738053696807,166.84487800922597,20.605983654672606,9.17509476628679,0.24133916891961166,0.17053536145879516,2.0793613713343433,4.044913559110009,14.79632931093587,292.55344121552986 +744,1060.9109474517613,58.4925011691986,22.807299239434585,5.135607929109817,0.27434240424505896,0.22175746548414427,1.9043838373924378,2.0381614371216976,5.621126713184023,326.6837466878749 +745,683.3108634526963,9.001332570345694,12.04461764690115,-19.734123183064476,0.31347759993117447,0.08586575583408551,2.6858822282135275,9.543571965650042,15.214023180498888,176.44537593283317 +746,644.5949807267166,48.72479447542273,10.825892750588597,-36.93328618842457,0.07186080532687321,-0.1926409002198492,3.530074957341692,1.8009761301127267,12.57458433669844,204.8917607235738 +747,712.6793919348291,141.5515422693288,22.994609435773583,-44.851252162609,0.08588343885635945,0.09222745738542382,3.0577814309541878,11.945307753888175,4.418018996005418,59.22659682947455 +748,596.3098801947264,17.94929413423128,22.58427097096373,-30.709252246528273,0.32223782276228646,0.23631910629092306,4.199882037850346,1.245931361568202,13.449880396179008,145.47890218891337 +749,544.4397162931908,2.852589720247455,7.161633443682609,-46.06813463904573,0.2178374500459448,0.13416216952727467,3.7704786688621716,11.475971034589433,7.737616144601306,345.82740866532123 +750,883.4452196988935,110.20455016705904,19.92452873084946,32.379958313780506,0.009965736509669393,-0.31457147829194626,2.1438501492877347,12.205581620771099,12.172502228687188,293.565848361549 +751,253.45505265176152,30.518477353423545,6.650637246545331,-0.6267313566799757,-0.06757839240548529,-0.25911524792325547,2.6957846181912726,9.182485322543936,6.09932173393989,37.72937051898854 +752,419.7809230790031,173.1640422144448,22.256933810043964,42.78321330579331,0.5353584258171408,-0.0970720895244867,4.217209301729253,7.722101716228097,13.44031323831822,179.5677137884889 +753,60.32435182063074,9.359357428517841,19.470010182180555,11.738852991917625,-0.01982192665051513,-0.020713492677580603,1.5230526219820832,12.947656249257998,3.4079910965250204,246.2565391104387 +754,490.8366330678176,35.749815537457884,19.462059099448823,-44.89935463342669,0.2392651990406034,0.051429299469516854,3.209364244773937,11.261447377459158,5.091061049651206,198.47141177638505 +755,420.3295036025307,115.98225745771542,5.465158406676656,-35.80866097900766,0.34943559490697684,-0.005150616424576149,2.5154256800722363,8.803722022136327,5.878776877954321,120.44234613489515 +756,112.2888691743735,96.95412644391789,3.201395721862576,-37.29482204416065,0.5168040843777487,-0.048458447283620754,2.991628695383925,5.852937535324468,11.438578343480415,272.280381402344 +757,270.89047567768364,92.42776749343544,22.761150550112454,-37.0164550043237,0.34656265963889116,0.22014557949614416,4.018284342167024,7.514337242182355,10.912843755634869,142.49360067078848 +758,411.06366377028905,184.84579334793767,22.12506495573537,29.338866508248373,0.23815091506594765,0.24000269935431534,1.2092693247534994,7.62839843516349,8.19742601588569,75.7025908444436 +759,1085.9204416172831,59.36312166195373,22.827483684729813,-11.90854944971759,0.05903194143441169,-0.0683269205801551,2.314520375785162,11.09838966215404,3.752692854679734,74.91492131308456 +760,95.38885189012838,0.775758292565138,7.183048690359108,11.298892877234081,0.5027288298757854,0.2391162459152642,3.4557380932125596,5.477568648665341,9.05341942920041,339.1877992976715 +761,908.2538719937976,109.91073618207949,19.366518012899057,-15.726429746473656,0.3912429424223252,0.0357252612914849,4.807460233738653,12.329422360137622,16.085136380701066,211.83949421599073 +762,665.283783093543,25.99153461174829,20.90383228796805,-35.0935705425816,0.40862302927705674,-0.0070920023772443885,1.4535441321103355,12.553710733102914,8.37791116417608,28.350723511944363 +763,21.29109768008016,11.976594350219337,2.2365270376108928,-16.72508624765643,0.20240149925781686,0.097619321208186,3.4864564811811167,1.3424475318645852,5.793497260751271,220.98371859728445 +764,230.84751469223193,30.93415992698102,15.80562800568774,-38.68564928932191,0.25591769263865083,-0.1726278022172813,4.765857818714183,12.944221624209996,7.483065673493989,44.89080008856756 +765,649.6075345141012,48.37972593215364,22.67450491154764,-36.12752712102878,0.31548774037282246,0.2285243055439629,1.304588914127008,11.550905503721967,8.977296936286608,340.0254039877728 +766,278.2253681158373,97.69713790444982,8.063144893959961,11.021868698972241,0.4221108145686689,0.26639472214689647,3.2509932021719683,1.425310448115086,8.203275526593394,241.81057651036076 +767,563.5836229217803,152.39539258300144,9.555723754255865,24.992760840362195,0.2207039423894952,-0.1886366208912131,2.9159627783310773,11.268205778758363,6.114175658182035,189.64968131325153 +768,198.2960888913557,134.68688399489355,11.573185834164311,37.7729376708521,0.5228733328523675,0.3647060627046534,4.775028102644334,10.227369656417029,14.095518239641455,300.95804141023666 +769,318.74180761690883,100.57031288529114,23.50414217525729,-10.346162292857073,0.4453944953302661,-0.1320171074892544,4.500798214179154,12.819263909699927,8.094148677448972,279.0642800715705 +770,931.8681265884735,94.2869934613894,20.197444169333398,41.47171594957547,0.382672662446289,0.32031997458493827,1.895302508310349,12.34308405302251,7.548340920429647,354.19568834762185 +771,796.30539643624,25.88851950486954,18.47328792299922,30.952460846922918,0.06472920723127189,-0.0174673435776172,3.2474454173970013,8.382788076037718,5.938011937577925,352.7580132801412 +772,397.33698871537314,86.85656523678512,23.613379122533658,20.904925380588935,0.17199901447726712,-0.18331770415906717,1.338774176610573,6.873554967186542,5.485827486894797,338.1200930918547 +773,452.5631886320482,181.05807950315986,12.388945046482561,-40.57024922409656,0.5726536148240532,-0.03830603853002468,3.6280799206174343,5.9510952463799605,11.890363767871408,122.79831250774274 +774,23.58551420911227,8.483343365403604,6.999979724596839,31.244285243235097,0.44696457779043974,0.21642634277936507,2.0686186846210495,11.845727664911484,7.874578015423804,31.82623615204281 +775,222.18633233769467,49.352938200599006,2.5248492808688385,-42.487488223346006,0.15921417174147506,0.051548089798104324,1.493294957367196,2.9215718495862335,6.255484852765126,158.19720939485754 +776,238.19966435441177,130.43709805947236,15.72327660076459,33.03577974543683,0.3548883295444443,-0.019368661816099808,4.337820878485608,2.463972978507845,6.915551473219843,333.2421316503753 +777,334.3352607762795,179.9555986928036,13.643740905762428,-39.30861427872785,0.6222525986774557,0.1934067869982638,4.204057158407648,12.74965673633148,15.538179662358377,254.135221128023 +778,824.7596095429931,92.24411593467468,22.228725096446066,44.246318691425685,0.45693025777770757,0.3526335074257169,3.2482425589877995,12.240471401193776,12.926754551022055,128.47299293609515 +779,366.1111765502412,178.41010463513487,23.26118306239964,-25.842469213970407,0.37317837336451776,-0.13506079879027982,3.1198683160466087,5.907535881903197,8.140820347584913,22.40385746349562 +780,597.7389330699378,83.45516434153973,12.624553371008286,4.348183208820615,0.34421971514777616,-0.010817676290267808,4.386737532527265,9.041924363738952,6.3731135621439465,188.75923744314733 +781,156.56502030288385,96.26257288383063,10.030126300924117,8.337857985735411,-0.02429102041129052,-0.029852969486098058,2.0889096690281272,12.29791562965405,3.932884489524416,348.8681460099036 +782,308.12786622876416,1.0639116811020084,23.263117697518343,-1.8454150009418413,0.004852486007333123,-0.11357846037622024,1.1994605587110316,6.664350849110722,4.207588053690054,170.0235872566724 +783,511.49326470537255,142.70083614369915,8.424274081758085,12.887901278090858,-0.03547121069816479,-0.06199954065082758,1.2974234789294168,1.8818150777402785,10.823637770518882,154.72578533527894 +784,540.7947969585625,71.75386115843384,10.731097394457901,43.48853048679722,0.33217318707616433,0.20108696201849668,3.87408809312058,2.065399057123887,6.75878979537452,41.27902822924658 +785,306.90913364445845,133.41826864260216,14.686665149809485,-45.91086086983282,0.30235741847229003,0.259482549348301,1.9793374888693793,12.833506871327044,8.630027255571424,214.58321077299993 +786,41.79605586365219,0.4291057882550879,0.5374369482043093,-30.64512909571106,0.09184991549768788,-0.05527377194991584,1.628522241822875,11.571040112532286,12.266668039717102,262.4979011041922 +787,336.4894122544242,187.9830874738815,5.044367135540166,16.758656100862197,0.2454948471436409,-0.20402974349154734,4.426258575302529,9.7826946412619,6.857565896784798,8.911753343710002 +788,263.3524926345529,33.019561547197696,4.390392253622518,-8.452816955433946,0.25304775337166385,0.22379411302067215,3.2528521140421036,12.535389762038903,6.100728605915477,113.71244401765007 +789,631.8277308141378,3.0849948898729904,14.128978526699056,-4.431504770324288,0.39900989245314455,-0.12607799119313823,1.2761709423099468,5.27339250488605,16.059401551464347,221.40054243298667 +790,644.3794665422438,77.8714715115632,15.898972895513912,-46.35686340476856,0.02790809658334542,-0.17863461618425305,3.2719623645456313,12.233413469149786,11.407687544621737,293.8392829149734 +791,619.2567304238555,118.74832820718369,22.857767012728246,-45.31793063406915,0.5491832229513635,0.060703731882482015,1.721749711058414,9.281935380520135,12.303680440881799,195.88805993758936 +792,203.64387741399716,77.67702629170505,1.8142460877227777,31.575655665700125,0.016676949010731787,-0.3050908972329293,4.071393100885408,5.7029994054400674,3.829174558953837,207.78350874669738 +793,164.08745747889438,48.63953161301517,1.9469791110642913,-36.22440105788352,0.5620590380826366,-0.05822064494563711,4.2538340795799465,4.197786656572377,11.68177035731695,95.99008430086589 +794,812.7217937395646,70.71872225706025,15.734738093363973,-1.372880308594425,0.5300937947981731,0.3656627017440805,1.1961534727751593,2.2505164181386323,12.472992493226807,178.2904062992465 +795,164.245830323603,66.50388256848535,23.798309071044887,-1.2710833201705327,0.4878602386379717,0.04841298763199853,4.367276067903284,11.163279300343055,17.00959512732723,215.1078562938647 +796,504.9721434625195,139.66593710053397,9.052658746340661,31.80913602282625,0.03882398574660241,-0.012696181131148065,1.330269441747746,9.736639109862676,11.276077863518438,216.18641562307187 +797,10.086903709018506,1.7827125862764372,23.639757335582154,36.52902368857396,0.022067448066401277,-0.015002824926309,3.9791712493605305,5.073690342909764,11.244237662216298,74.93679078043778 +798,677.8038282269604,134.00257572509383,22.54790207447254,-42.15554746039299,0.40943407397243975,-0.11230116380953195,1.4863141349285844,3.160658339813028,15.95933350069311,234.09415719687186 +799,706.1761974441746,122.63067694213707,10.74439529450704,-28.897973366917515,0.22153765486121724,0.17358039856495217,1.4174147539941953,11.561806105309817,7.466316410618541,23.296196949253485 +800,287.24705645841146,36.746999895743954,11.950096818423333,45.91676162382812,0.2881039101844035,-0.09963054273878097,4.481539161000259,7.862071072193053,6.143392653837988,332.4967445496309 +801,695.2053812791709,64.54868833214654,11.009641370327161,39.76404486354325,0.4758084823594365,0.23753774796948796,4.47672168106579,11.06990070703029,10.766935548931496,101.65163767441567 +802,217.67205838290033,114.28537364511425,11.744007902572012,26.972147743712313,0.6255785237602738,0.08698719624618728,2.6783922407424017,9.426713934313092,15.03656835598207,166.14757005960078 +803,654.5388571878309,51.92101436737095,8.912707322790432,-41.894935257155325,0.48586638561794615,-0.0589823471278666,3.0129123436650156,4.299503708809713,8.742129152378997,180.61822429185924 +804,575.931139051477,1.1301588762371277,12.71344879626687,38.570694501316126,0.2799362095196979,-0.18894808959975226,2.463613515355482,2.171046988664891,5.439409373404224,49.088750671491866 +805,531.5022595965033,61.29390388903195,8.089231718011776,-46.27625408380745,0.5280851713739426,0.05241509693878199,1.208634043275231,1.5156924530617184,10.763462440489011,335.50086577059676 +806,283.5133981647514,27.79494420331038,19.05820067971457,36.84223166697103,0.523258007159061,-0.07961740836850961,4.760619504397336,1.4147676017396127,13.512969488876468,297.04401121893113 +807,23.19997120978779,20.894603843091407,12.61669681397433,42.123347608424154,0.008054660443871361,-0.27522436507209264,2.2992699138944133,9.853261840564173,11.750319154068983,171.04493849562036 +808,360.4365602630949,182.79927633707436,23.10774734279067,-16.22937411730237,0.03278734553197728,-0.1575085473211877,1.3374365013814589,4.301122867886365,3.557978506411487,229.84144950006512 +809,25.14013893076204,17.62289227888122,20.68400840274535,45.92022853649654,0.375681309375001,0.2570273709374184,2.034633994554486,4.96832828462188,7.630154025221815,350.3812622123475 +810,156.8933283146895,90.5316588479665,10.410012272200111,-41.4454961481937,-0.00039559732427132954,-0.22066631026738975,3.938100010628622,7.271110002225953,4.952589485250513,116.46078822493581 +811,213.72813841111417,146.48686002998795,2.7757374205574816,-10.876328810820887,0.1680490854878266,0.16478820752296347,4.759673268487018,3.8516359052667086,4.354636706050856,309.1769224258225 +812,583.6153247556284,4.741924789976984,23.74936328723665,-5.122826449625343,0.1989782746026491,-0.0956124663218127,4.710526870593204,6.756930668471567,6.603226104121585,208.12227297877237 +813,52.863170945079716,20.340797913005037,15.302796794277745,0.2914130880550658,0.5042729856932074,0.19035074853084571,2.2518331606993405,11.398967167879755,9.6954194664368,201.12932548928998 +814,94.74938619240606,89.2370676366108,12.053211633945676,5.491050180727079,0.32778597650938124,0.2581929000253304,4.724722191972687,5.692704878350934,13.205571355069846,195.521876442426 +815,659.2244412859166,10.798987981932491,23.077194452067673,-39.101959722109825,0.27419684415274803,0.21133672335118775,1.5826831031285624,2.493192787582833,6.707226447256291,185.84018156394924 +816,376.06863138929447,60.959584334205104,23.86919067047163,11.58552321228656,0.02575984307614161,-0.26131785023987875,1.2381694158478032,12.31671004926366,4.9366821582142055,83.47119394804585 +817,195.9008587960591,131.52482987459743,2.6853411511091965,-7.090676546238335,0.43586026302156833,0.3356191767428602,3.735769776028201,11.938807768011415,7.485955376194148,242.30570434091413 +818,256.7187208250551,157.92446980093945,19.668566229302176,-8.20758875764674,0.14070029386974248,0.13014056360416948,4.790060026873333,12.174456543167668,9.30841445198963,187.414926694953 +819,346.51302862285695,74.33848105786569,4.91931001067455,-6.550228347660386,-0.01416176718479878,-0.03459539952298757,3.5681774327483087,12.774123368842455,8.224639788157603,245.08456949016517 +820,391.71217614722525,182.71542999247387,5.028260722643557,-8.694635888144134,-0.03249687444896499,-0.1777802218411267,4.242115997511295,4.04892205906812,10.593755124901342,164.21345511739864 +821,506.90100845807507,107.08388723035091,23.3839951793085,41.816900171428514,0.46873371592951996,-0.11447749897819898,1.1881798706024203,2.2569913189046398,8.683995675765829,341.594795194327 +822,199.60142977300495,44.72002963937203,2.4493246977680347,-16.38651949135619,0.00750866767946623,-0.26810481405081343,3.9698713487808446,4.951455653110085,10.426901814701399,245.38784310077418 +823,105.139273256595,4.386607351173739,22.079619192021024,-1.3786282445911553,0.4522495123500234,0.021249850131298376,2.9555613138631496,5.8708109688351,13.652470109629515,184.7561458833954 +824,613.3860330595182,78.64617178248292,8.657133770720709,42.44299795267462,0.40691208976086746,-0.11497678404658651,1.4832735818486935,7.206747002817846,14.317038056847789,244.28564475032715 +825,433.8431122996009,150.7018289456249,6.2373769958798,20.807589994485298,0.3701841880519351,0.2577462173180353,2.033850335839791,4.272549042330926,9.004853190915544,22.958058554379452 +826,54.94497793445534,16.131704337395853,1.3169264911833856,24.648102917015024,0.08515679499340793,0.014842468438550693,3.752774317200199,5.207718827182495,12.276092096479026,106.52225220439685 +827,871.7625761516737,107.125891122307,21.464389139426117,-42.798033051472956,0.27476071870106644,-0.14187663420700708,4.790381021587383,6.489159667945721,8.981126042714035,326.43657344771253 +828,178.71947845906195,131.64515949881508,17.84660053330039,-9.36898688416862,0.24821097561454908,0.1308895968795148,3.3829944517596475,1.2343420127850901,8.071304721993593,56.7045856809684 +829,277.41217474627655,144.6978239530039,23.454260107666506,-22.915530007278694,0.3645752219932953,-0.16069705551788782,3.1111201478855586,5.401050712884897,6.726298469860539,335.1943072859891 +830,795.291786400374,80.94429223456922,13.036629983920598,33.63531700249463,0.23544825194049407,0.01300123782927437,1.2123738330444924,5.653636915314598,6.586539510968499,15.008048290234424 +831,834.866457620202,108.16466635951969,17.36890901762201,-43.8955265703076,0.13530026522681393,-0.18461077135446868,4.778459382959328,3.280430778953158,4.685452393220828,80.90858652051557 +832,749.2635476801008,106.44711181083598,12.153006160815334,29.066042909860826,0.020514828941056606,-0.03742777791112256,2.0440125854424345,5.008436411756582,3.798352698612441,199.0896789353266 +833,303.5753140371215,140.9369644316003,23.198746369040904,35.19664092746615,0.4951735030222135,-0.0024920950490044946,2.5365870205855394,2.2698506191295253,12.245078193949904,158.20645580634292 +834,934.3076103188528,50.789323827012154,17.801593714514055,43.67267451168652,0.5860981270271396,0.29422054722836827,3.7926263198496404,6.655360119603639,16.816831777640402,232.57185907697422 +835,643.5931185202678,4.543171338964086,23.529424772958926,-40.40650117644726,-0.03539303506713888,-0.19026313949129012,4.489383533149576,9.939407325374116,8.000942218602741,325.9424516055584 +836,29.84019010002279,12.386960366287967,22.747952453117172,-22.885536247699253,0.006630868595153397,-0.24817834828240654,1.5883766487672446,12.648757043101389,12.302926573689522,117.21880579922846 +837,646.0567963503358,28.52528614783765,22.127972058356136,39.19627550634786,0.09028136947001096,0.011719310877438549,3.089530550308236,5.622757893222495,6.4871107909934205,50.45367492139995 +838,184.66257246054542,111.62861377221564,17.28085545879989,-44.905904985979994,0.346949951955105,-0.07676009264623113,3.079381205789957,1.0869137133804265,11.982326055487565,317.54826498011016 +839,117.28330951590517,53.42868802758729,17.19089042253505,31.636004458519352,0.012068953660225798,-0.06097458210832313,1.3002962521460393,10.765516564427934,11.738999111199503,317.2533313270008 +840,157.39283254548855,110.03873986136068,18.64316706749601,7.122531338528866,0.01938453973091467,-0.09282556287113,4.707480156715904,6.803197242601535,11.591947683192993,234.99262129196615 +841,182.16603055468883,32.253609209688435,14.519537136149708,-44.830710515482224,-0.04198834387137571,-0.04470572707258297,1.9838071324235909,11.848774906897056,3.8132136879556766,147.69335991971516 +842,521.7364115744527,157.15187088139285,8.364899072915842,46.08197325091243,0.06064511399356813,-0.2882769963871169,4.044847338166518,1.039265605223556,11.963005920651575,187.69815121178868 +843,393.6288045939693,35.89537508650673,11.634712753188166,-2.001343874577479,0.15585454708593655,0.13732330967849932,3.2065892823893813,7.182849709675384,9.733755866943204,313.5671160999902 +844,445.93501734600585,74.39916526844101,15.299537339845486,8.983129920929876,-0.030227757467462348,-0.3237456746098452,4.34635549402079,5.131733923595706,3.9939669424091155,146.05468517362578 +845,1029.7042934977785,72.48838397709308,22.974857626685868,21.39488911247429,0.5927924490678721,0.06335780511172118,3.074285800858445,2.468457427088932,13.61591952104379,168.1939519678079 +846,149.64578575769164,23.88172305203596,1.4071994205263572,-4.333423902839947,0.5419066227150467,0.3315248337445404,4.583077507295266,12.772504458283354,10.500663464833687,332.9431773116465 +847,812.0113193699815,47.6974002147094,14.371232135354834,-8.363048740886029,0.41358178504339926,-0.08812786931003783,4.631945922595232,1.264595770124956,13.948362423527152,166.36575347293163 +848,453.0268449823047,155.82819297729247,6.47103038247324,-45.64712965585721,0.4664868145342257,0.25705321354190497,1.6171596443856913,2.104707000934917,15.841381797846964,238.28048064324452 +849,60.034481106423,19.599359123799278,1.8683639008130144,46.006156109990386,0.28593870745971217,0.06596385424399442,1.3375096015926038,12.528496034378788,13.684820671710725,146.23007817462886 +850,743.875570243757,21.43226514728729,11.977535441996118,-21.61730173841228,0.1375681701687183,0.06544923678413622,4.705171751050803,6.22622331592653,4.214842861141152,269.46735208922746 +851,170.6712718364187,125.7843181788537,4.021414751738344,-27.660412332655298,0.03347255191203376,-0.24189765169425262,2.4924106474023446,1.837818174981094,5.030770240362123,253.04031405460418 +852,468.62023280029786,29.73230085511461,8.78688232825866,45.97623124670808,0.11309932908291075,-0.14597714907182785,4.348626787357816,1.1324011921762118,4.093526392961275,337.3982613162069 +853,49.844648965985755,41.20759959777453,8.246356282810318,34.821463839934836,0.34346077848940915,-0.16164705375435884,1.6277436646987216,3.507095783646868,9.744346925714353,46.523538454667175 +854,301.4111813995724,33.29405798527313,12.182528221499348,46.79130443500044,0.3206063940692272,0.2748310060430405,1.1853624537970358,7.334444057145901,14.973254404540292,182.6232188969584 +855,149.48121069116272,99.36776856688043,22.86235886686079,-44.89693532631582,0.14967356960809397,-0.054653375557635164,2.3948466243762,9.524817917640306,14.082023610201432,194.48236188809125 +856,512.8862869788773,168.07139365448444,16.063072389589784,14.322049883451328,0.6969749535328923,-0.017434628361330418,3.2344276734050474,4.8153898678668465,18.11226538482245,270.75228130188225 +857,281.2593400825794,100.34459436086799,17.08252687194033,41.8388254371048,0.3009551589379401,-0.1469375315427088,4.807014421406918,12.766670452931375,10.649758915084728,327.9238212229883 +858,168.22593052473266,71.04131215323451,14.345225265998106,-46.40864604516133,0.008076594036349569,-0.30239898398351317,2.2272014115101655,5.874793001468282,10.987950990454497,185.38803113655936 +859,163.82598607119206,98.29592629045268,1.5341744726961037,9.545503649637055,0.4112668152875669,-0.13939860164021903,1.6091841720938351,9.656854255906303,8.735019790878294,269.57631108246676 +860,78.56265873163457,77.30167757310682,1.4496974442349326,-25.689572704672013,0.08429678070156547,-0.24703751518329511,1.285657306825184,1.283330569440821,12.4350152933895,118.49780966814446 +861,663.653060042452,140.94124188429242,18.824271209078614,30.247640390646566,0.21200779900638494,-0.020052071836304697,4.145271847779122,2.467549807956463,13.966201609939517,205.44928854961213 +862,167.85793132217847,86.32035629736896,12.839520120711335,4.026417479042401,0.4473295377641874,-0.010656260906505344,2.260875839889737,3.6254878944956825,16.591858770576806,253.8151050469461 +863,429.95783101897933,51.6372270443353,15.070342034365984,-46.80465679786912,0.45660479536049325,-0.034347456816418376,4.227914773770334,1.301633820772786,10.919827770639824,67.6785915896412 +864,39.12497352215611,28.282421765630637,18.84685052775121,-29.721133376922104,0.24808053514215878,0.025293777985719912,1.2351189528743474,11.945698378177227,6.495156801475314,348.26198979971724 +865,858.2763855375423,108.19766473372823,23.196607383938595,42.94738976180044,-0.04249799921546016,-0.1004533279986567,2.8670495369697377,7.16830820816516,10.026821495217845,179.40174604200567 +866,638.0370735566673,145.53542813696146,17.18016214652338,-33.35766713531003,0.461020436640978,0.29286510954615225,3.978858857617295,12.634810491531466,8.523270736719272,39.35054604652463 +867,53.33949271217439,30.843967619635908,8.316475660929848,-36.71995065160985,0.6530872619031751,0.014244915840927463,2.5054177910891258,2.631231662293944,15.409791036175555,183.61581254770866 +868,55.08172226514034,41.9750153979482,23.29599841638971,1.2036999831336885,-0.04332033590552674,-0.2734492175592415,2.6854803114803207,7.568865106543998,11.288625228241312,291.94702230829705 +869,316.4519159896648,5.077029477113475,5.373533982133298,22.95655402607524,0.2742905178687606,0.2604609970531048,2.553510868763097,1.0902705943725208,8.718779220557847,68.12064876312833 +870,129.07835124433407,33.34997329490643,4.25305607792201,-46.10665865758948,0.4405946219470832,-0.07621027487517068,4.429293431399021,12.65420882142104,6.772865382258015,207.68113020229785 +871,325.71286082698725,117.29462595810222,12.585195254769694,-44.59419221618426,0.36728505551603335,-0.03503770351265406,4.724371051001091,7.035187112240764,6.561109802484582,111.7718351432502 +872,282.46296400533237,162.7956264953164,18.258882697149964,-28.539681748226393,0.09967969736775444,-0.13712199057976965,4.7874647718781755,12.99201930238357,5.871690910579474,28.959475356027014 +873,768.6547862740381,118.0338468551304,13.575932412890158,25.94388569868346,0.5189054788507057,0.339258276292792,1.5218710654933019,9.40037819445715,12.869112932030133,116.29619065548589 +874,485.7364772714123,170.95204595203109,8.119811176016517,-46.04725195945286,0.33263623154469146,-0.1001291188306973,3.6343173828301953,12.254643724717177,7.4913209925938045,226.58304207328877 +875,370.825391614952,193.48630002369254,16.34490574274934,-29.323997259678624,0.5380627620324655,0.3904852642185554,1.3501388068911544,6.745419471972783,10.916159798182324,123.85477782100881 +876,932.1766131702644,103.75673338463847,18.24822215953162,-9.316149428671515,0.24793608067888606,-0.13082224001773435,2.467919539167521,10.302960371681515,12.82787852263621,283.8423555254651 +877,607.8101080428783,49.147460201321366,9.329137798479138,-12.340884970136656,-0.01411378074213964,-0.22334648954491904,2.226157923985747,6.205711023451296,5.486321743406691,232.38675338708603 +878,689.3131793130914,23.97689720079896,18.58819852714984,43.42913659013578,0.2709033901122332,0.13607867108788935,4.717413924271749,11.758612635803141,15.208016298505468,204.30843784161686 +879,180.38514296289202,111.9687158721639,6.581145041640195,-10.586736526790702,0.33288215450380476,-0.012588897557129108,4.57221730165565,12.285222847880792,5.585607074016255,36.87063200537647 +880,779.2920245097605,119.68269711674425,13.325720828457312,23.398545636667436,0.35947794343444966,0.15648256740788064,3.543169515120921,11.983267050758952,6.134565609803261,349.811066450806 +881,208.59609842820737,88.83241011050617,23.103772048673243,-26.730579008067824,0.49353031681893567,0.3191482904069191,1.394410723310954,4.939066991042799,15.858533994436987,234.16708362256654 +882,307.7214176172626,99.83619666094012,13.742116369627066,28.516159678221086,0.0615122491250064,0.02994021131439606,1.4564057594420912,10.638162998719812,6.0754755990706375,6.299953729070991 +883,917.4115554782696,82.22620765105674,20.24747655037471,44.37915795601782,0.42094288192971935,-0.005500351626867628,4.508268788320407,12.118601999442777,7.991395653550596,26.506703913686916 +884,577.3479052123089,135.31535263672896,23.246471452881963,-4.206777858838848,0.00861103214280294,-0.0061648298340146734,3.1990175492812662,7.633629994292068,8.651094074061987,352.7777145481712 +885,590.118771905621,109.94528542336963,13.64025219549735,16.056713491440874,-0.03404567240081407,-0.2212158979878739,4.4882154416716915,11.111609788929183,3.6914797098050838,277.65829296084485 +886,111.26772403924981,59.577385787390796,0.0767117585345663,4.601754525500944,0.060605224634005014,-0.2323871318118378,4.807765101499183,2.9967379601445994,5.224456051470737,51.021768812508434 +887,852.0585533547915,33.20555139801519,23.673753184840876,-20.63626951950925,0.1340459222397533,-0.10441750307215766,1.58119422040852,5.6692448312556145,13.93588252289023,138.8998830652011 +888,1116.3960434363537,74.81314288537695,23.869690636881266,23.811066024757892,0.40407613783101226,0.29245215503171046,2.600628124659275,7.203222144466908,7.646761385173056,121.06997670205581 +889,763.602617727713,99.56163659884365,22.647896001057685,44.41302958428932,0.05400514900822921,0.04109652186953122,1.314483949212043,10.869295405234757,5.740704882368691,240.66757091627522 +890,95.45203074693343,85.8978689913383,9.479549135207648,33.412828261311546,0.2606721704568533,0.0901764797431891,2.511514460550649,12.30059276833293,10.778123826623148,328.2149427360088 +891,541.4648772335611,1.4501080918666118,13.028864416956685,8.789145408898797,0.4931024667571464,0.16848932566887803,4.787337030000801,6.717252545379284,8.804925489120691,34.55429693287926 +892,797.2624737014149,97.86737190829027,23.752889083972512,-37.15274937799023,0.2810120819408637,-0.11560480804816436,2.625305938928449,1.2509616163114627,5.080117566261171,146.63655417130065 +893,78.9702073091802,20.33197517430892,17.207326578105075,17.141112035817585,0.280135186466707,0.11259532029082236,2.661262193211062,1.2350648683130727,8.01710344154519,203.91872568159425 +894,1008.2104524909853,87.0002355969724,21.881028140192814,-38.7576562381306,0.2861875617902304,0.24341563794744187,2.2683612424070017,1.1017866160706293,13.179531317433337,294.69283767280126 +895,636.4747195708951,6.390086824058603,9.725050379483882,39.461258002677354,-0.006450077532026546,-0.09268983463903674,1.4307595357664487,8.617522099831048,5.648464238024896,228.49643348626006 +896,565.8515919700126,103.6433802771533,11.207697271790007,38.878600640655335,0.5385504755098738,0.3412976758323453,4.791533857077514,3.304757308909916,13.250997123833908,163.1573417406363 +897,869.8699146195651,96.64172443614991,20.35693450396749,-40.0925031560995,0.6060311830865176,0.22624930726028597,3.5099116354993356,8.967866634090958,13.53879269616766,147.8312074371519 +898,58.57585601885553,25.320733113051183,1.7117451779957145,1.5392330896347417,0.6177840373382069,-0.06379661319770485,3.9054944321273517,12.625193523181947,15.542099088478158,193.45969142034494 +899,725.0002847120472,112.11794883804362,13.319763113953584,41.45281179938689,0.18820974496659115,0.1670114668073025,1.795491942039605,1.0445948839135897,9.931487537607648,190.59717757496924 +900,41.7709367816763,32.102398692828295,7.177819621680427,42.570819228757486,0.5252492753512247,-0.06590046718642967,4.7786231098106144,4.334127429335093,16.477847208488168,229.82561894077304 +901,528.6374845188166,1.5569525157539716,20.62826418895989,-17.124988659905895,0.034637196232104,-0.08826202864344332,2.5344512066568705,9.942215187808246,12.780627963703154,300.7311123517299 +902,260.95264584470686,111.6647953553785,2.7520694272130592,1.2116433557162267,0.28881875150102854,-0.19074864439847336,1.3494789780659824,2.4434774895869937,10.556099033534451,318.25043395941987 +903,263.3153977427643,161.39240652968093,3.0720039679311997,-43.62269796370745,-0.02677512425193488,-0.029504146638862805,3.376698999784238,9.695738136256159,7.6154900990824075,287.4342420239186 +904,763.1975459603402,22.34507578038702,20.742095367592267,-41.670567276363485,0.013330834224854635,-0.22473448616798866,4.594258805661385,9.131831194891019,10.393722056937051,82.74373548052458 +905,543.7489871307774,48.5780340256043,20.295936182113497,-38.097783167762735,0.3623689573290101,0.10149623361205751,2.801884151162591,7.1602395717615455,5.992294267553842,14.987106964290508 +906,414.4228357668236,142.4698215407558,23.88491432926169,7.432866042691501,0.5336021739518026,0.03430297393938342,1.3205849839222419,6.797165864660004,15.242282536519232,192.99434242652066 +907,638.5326690250035,29.612046294629096,12.482298946852925,-5.948195841557286,-0.05611784454362158,-0.2981975987511085,2.1931753085105585,11.200157338667267,11.14586479892363,157.35854653278275 +908,493.920733847277,12.522731945449298,7.180535148959196,30.248637112583992,0.01902774813916029,-0.008149932576469399,4.794287122799033,12.48161327414691,9.376489712724096,68.20306646360719 +909,920.7071113740047,94.82230166736444,22.68426790295409,-10.050385252279334,-0.05048616949164699,-0.20607989342467475,3.9920864384179033,6.246986428664227,7.364242359484361,20.214736510441295 +910,77.82021635744411,69.4941770750905,23.88377155517047,-26.95327790583579,0.3056875912981223,0.16202045640590662,1.6237596132686518,7.741167001138223,7.5516390918206024,224.5087896656042 +911,132.83843822927642,85.37139767914653,10.536898550791161,-7.409089488468943,0.3277425332368276,-0.17058523139369308,3.810381108332524,12.92732099306511,12.90639157763624,137.58627050103547 +912,393.5395244225263,171.59060786585943,22.342973641920295,15.762031779845394,0.4393950413752483,-0.11186250280280155,1.6313030447753307,10.659174520441901,7.485913230589864,84.64814783201018 +913,281.0610774678583,160.21352667623748,6.009694008231132,-21.867647157107182,0.5227032683776077,0.23238448922521843,4.65158482727936,2.370703016608303,11.316859848219673,118.56603462769363 +914,112.46334694825623,64.52008419049298,11.83458535014133,-46.72377979120544,0.5398392572813004,0.25292711932325934,3.5602920570136805,8.879003093799234,15.318728449483633,239.69379909982354 +915,251.68508597566898,145.40515573444574,23.574268748329338,46.48507572114771,0.05771800229636663,-0.017840797181185863,3.0949016491374937,6.26550789995016,5.473231063875247,80.6027265695516 +916,823.3824631836998,91.97132638724794,19.267795147957322,15.895504568789022,-0.030035762961385583,-0.02029887740270142,1.1872815871594513,12.780272278299345,11.545779785221457,131.85999330094782 +917,629.4874014997782,145.9027598533797,8.870527404524728,-11.653506909828081,0.23782100743718754,0.17243803426647436,2.9581729042063243,5.526005274232069,7.046034557749579,327.6393764958678 +918,191.59511279523954,108.00991787748313,19.827424094320953,44.89858717358274,0.541352120632224,0.38258090275773776,1.7358257279942002,7.912731629996004,11.644648546291714,321.00289807406506 +919,217.83654585941426,21.991927669167374,13.58955905441879,-37.10557303496861,0.48871260141646033,-0.030553555275096234,1.830209661452586,6.652040802016866,10.24555531012101,320.503043646802 +920,381.7889468237315,88.34302914780436,22.556113006926633,-10.208940539301246,0.10915144755134558,0.0923764404224891,4.026011335376698,7.389774563368536,5.4445045533556815,62.186494618923014 +921,478.35204578195646,172.9086780886979,22.048253272092982,-35.86498426565473,0.1813854027477388,-0.11419222407443416,1.4292731829912992,10.324109844471332,13.004115533503057,316.8993919193567 +922,108.90086067128873,25.017775378455678,10.70325895601848,43.18531663691921,0.2406106584899897,-0.2053562939563645,1.33128177681927,4.021435153501893,14.723842804150397,272.10147834816104 +923,422.7108192937167,79.41260008156918,11.174250990687483,-6.907468398180043,0.5989843935692146,0.05590213943549627,4.477972869149513,9.809453778636744,13.226384135177184,284.94014469689006 +924,207.5626416043691,66.40068245510994,8.725714685475506,40.1531690669804,0.006003897531686911,0.011455043130992826,3.2576826387285704,5.766586793222595,6.405124060014131,16.159270059599375 +925,207.19301641688418,123.38507650354968,15.833022822848326,37.982135520079694,0.4480180896679139,0.3035615681237415,3.3365379812953444,1.0561959607593632,15.67867130316737,205.9738569370794 +926,616.6553341976996,134.57438462494906,8.794504941788368,-11.05494501120286,0.5622232362915028,0.35846341579033697,3.456334555582229,8.641783406309868,16.130201606401805,261.6966868301144 +927,823.0455616825044,89.99812600607454,14.266539155619618,12.832373860862361,0.46946552078204484,0.19324184258521332,4.274636826066611,1.1483182122003046,9.54658719748736,326.18040545882985 +928,56.81915547073494,14.391505066610888,0.36667692605275154,-15.053875091029497,0.11479223855053415,-0.04269589452019146,4.160663503251431,11.981508057308318,13.437708870462547,309.5246687093357 +929,696.5472452398045,123.17477697389369,13.68064749658815,5.8032339877886585,0.38694346597192225,0.023599391715816764,1.2080709399034217,1.851561455989812,6.68645732036787,333.96390705065346 +930,138.4343449748536,5.217424823226223,5.461999637720983,42.130689615473855,0.10345359928951857,-0.05264474373385192,3.2015977831073235,11.052683951619253,13.744777795220818,284.5924752341585 +931,43.21229859743771,27.345411711313222,20.183233232852658,-19.793857895896757,-0.05821653013776869,-0.09245101353146296,3.2330145901214022,1.0975781303013428,9.843966911162525,273.22543244131253 +932,257.933477562032,149.34896016254308,15.973964773274231,36.40072227853362,0.3743415005573616,0.2288439080137285,1.2467843431517127,12.867637256360073,14.817107466222192,206.99132788789518 +933,571.6303835123998,94.83448498938303,17.922507507949135,-43.464013765416944,0.5702494451551648,0.12528758436738074,2.7564933988796447,4.691095172166414,11.633882480251595,301.89776564043854 +934,514.9758560864525,2.011654496788133,9.472707814500021,46.94812626081216,0.44144950887487644,-0.013854012979931996,1.224543700595172,7.433581233756314,9.09894075807808,118.4097419280155 +935,513.1567467780812,72.0900129221852,18.504658001247666,-41.92208651126661,0.3956024681978236,0.19509426875892139,2.451227549659384,12.680755238085212,15.776127953449755,269.50729679454906 +936,62.33666799686415,51.999996310159545,0.36136260687044464,32.23806099616891,0.5785330270634985,0.13167103689100146,1.4809921953726746,6.732978855439734,16.1101504997147,193.09982441130043 +937,135.34215136159474,0.5878790566372143,12.608487508528036,45.910120501518605,0.10492372170445467,-0.14540893201140168,4.75236502230205,2.9203946277483235,5.656458348457763,90.6126664802087 +938,329.32372937182726,180.9967768027609,11.716160498994753,-27.986204803976328,-0.02829876765645517,-0.18604547244039493,1.6477011443719787,6.014075189323535,9.581888711260879,116.7562423086761 +939,1072.9244564308522,66.93201761566372,23.22403315326882,34.87714470696716,0.2104265709047189,-0.21690272707260216,3.37260831096171,1.392857912140411,5.02224124049593,307.3949142500923 +940,406.9213949645591,120.71497111197054,10.049397285305117,-40.553420695244974,0.04363251613603421,-0.3006999291634064,4.757704469511873,4.959770774881991,12.603243174959257,296.01835728045637 +941,467.94724935861996,8.681860093970178,23.7877321534394,-6.774300176784784,0.2541450196903505,-0.18621337541446664,4.565512150489101,12.908101418071059,13.579717255855769,201.85346985680394 +942,338.09888406647644,108.91421769099107,19.24244459416231,38.40547225231262,0.4509489120943241,-0.07996524564675878,1.2608904330752502,11.91949388225873,7.434423759998168,350.494614357488 +943,276.7880624490784,9.149478384033516,20.678297714227206,28.255490612378196,0.2477036538326714,-0.1983762272554993,4.661996365876536,1.7044054148952554,5.091876363435207,295.10168924527267 +944,159.92774292320635,105.00474962819506,5.793710199118298,9.141062761117908,-0.0005661136430013536,-0.31004836455113677,2.921177174836699,1.7849439949951826,8.903977377188404,85.52139676135691 +945,73.95645096903277,0.9378997534387081,13.86985271520841,-10.341408286960153,0.5355157469476552,0.24403574570422498,1.4173302143886777,3.788580806333025,10.5984322113631,73.00380467650419 +946,352.57853922542864,93.13667465633671,7.472375355280319,43.60419847098338,0.345230275852505,0.07705755652713875,3.799585189038341,5.9657609324393475,13.728789580190757,169.36138777272 +947,282.13280408452397,1.4380720463643546,6.907353635750504,-35.37555362039031,0.41320698109390913,-0.051723988205802374,2.735414011945293,12.129798641597027,7.903148238539595,42.67231306197342 +948,120.72375321130573,23.27362571881727,13.677779991514374,-35.903184375039885,0.19942759142214672,0.18929769240585487,4.506871593121151,9.032989336081888,5.314192429890437,113.15922012871613 +949,541.6406522016956,154.99281829006569,15.810399553666072,-13.152986286548355,0.47086897313925524,-0.10501688694222516,1.2276875079876715,1.0501295668176345,11.1788284743402,140.75998120432405 +950,1096.0783780563884,75.89035999553666,22.916482057392756,-2.5849348884549386,0.1701790080184214,-0.19056978030537206,1.8057371349345834,2.0093583620981574,4.494736823231664,48.85057748028443 +951,115.25269326027268,29.250773241055185,22.930057089416618,-5.625231565451642,0.08090724093138639,-0.09454847828645307,4.217847240934948,11.435823360858969,3.735574014893898,168.87275729512376 +952,86.48019283183764,32.26930142749121,1.5973666005494622,40.663064106393875,0.41218675498858404,-0.08862079427773054,2.0919732997137377,1.3098223139096858,9.126573088991254,308.5052109481407 +953,1036.9393556809325,90.26936685339375,21.115116390675816,44.60309863002428,0.4107227593341826,0.057362528537339585,2.463321842687683,12.724743015270816,6.822577733452826,182.80167299180624 +954,164.05015249655187,21.64840859783548,17.330403188620146,-25.68634979321992,0.3686054124156075,-0.12393003322905022,1.7360545060916266,5.8600846108269575,10.369734608863766,70.89664205827263 +955,73.01825364280481,48.88336418012497,14.986146478287903,-15.31999867780933,0.6001434191560532,-0.05263767809848491,4.324756344274283,2.341802497029403,17.040574834974564,264.3159067550798 +956,542.3360761801338,61.387590630969065,9.763181983019246,-35.03359175203714,-0.06365167724105347,-0.16431391207211127,1.4548478375384852,1.2039200864999253,8.686448092964543,354.15402598031716 +957,970.1105141283457,80.38099152331053,18.80883670524386,-35.016326339263856,0.029468389689489713,-0.19763583427229311,2.4598298973051635,10.766846614783075,3.9897343410760815,347.88848009694 +958,674.113665217663,146.62160874629,9.930692853916883,-23.68797378343269,-0.005128853951743298,-0.052509348948660495,3.2437884313666476,1.7446953943620387,5.4857535386388445,65.18873288044372 +959,315.5018315929893,177.56658317186063,6.360201730927761,9.20831455331723,0.48646194546798993,0.0001497846379839296,2.7070726728435623,2.7784880491358273,8.63315190614873,323.89233832815256 +960,184.64637148816723,99.88432334195737,2.6357450836297494,26.075626285810884,0.03151738033706912,-0.294133519884624,1.7578721758201934,5.762319605935918,4.493276588094409,205.52152260084975 +961,541.2176985482847,19.156634868964037,22.382724339632396,-9.695806552492684,0.4839735155580547,0.13038325746110313,2.883585414156671,12.778747132814487,8.37191164363281,355.6198320860719 +962,531.0257947563047,119.57218196496308,11.174659875676305,11.478771188481971,0.30363823421167113,-0.19474093555124364,2.3027441120549748,12.360051813854614,15.510499458823034,176.16640379927549 +963,302.7551256966162,175.1616882342996,13.02677223280855,43.3364678941776,0.5692101822284193,-0.041711901582227096,3.3949794233379667,11.99511939744058,12.379458554895285,276.2618579310866 +964,343.1202536972739,188.5365944695737,9.939095039652935,-20.598204332745777,0.3764704188314088,-0.08642319759941663,2.621532345042894,1.3993761724711247,6.439678431087202,9.339633689481278 +965,537.2431303276238,134.90289318969164,22.881138285196563,-35.32930287674124,0.4865085620851265,0.11881464839644951,4.5824681769676,1.9975831516839269,8.966938522239204,340.3850371425486 +966,818.8828272538748,25.72922511521969,22.731954695851915,44.67895731875548,0.30519333523691483,0.10255152755483732,1.2023287041041866,5.057610933866362,5.457496242612033,267.5598240005573 +967,382.92221630363025,187.64672014132753,20.677375964370988,26.634312980912156,0.2657641662067476,-0.09210251848541504,1.406111151271824,8.093263536952785,10.7335917044819,339.2386824705723 +968,737.9419720924484,85.05551027879875,20.23598982648383,23.8781091028018,0.18711948802493966,0.10480646673690913,1.3823304186204821,6.4058795518649445,13.178473003589497,142.50407893457995 +969,731.3330953222433,132.9349828365708,20.27309091765982,-30.490927105721948,0.1813470108348399,0.18211258527210744,1.4376402839600282,2.2773618302592666,5.421595715122656,275.1055276965052 +970,582.2920976392254,131.57927226355923,22.078213516386352,7.391038351611897,0.497585089890457,0.3583869363534204,4.502674746301871,5.665319260734934,9.200796801801214,329.96593794767807 +971,990.8248551177317,72.82728560459401,22.87578866939439,10.981447159949795,-0.03883944806277117,-0.06704277686228333,4.602550673834463,12.580703124997298,8.566901917816157,62.66823321235277 +972,80.96308959716119,19.88895771311349,7.673758783014206,-14.194410790452515,0.012716966999016172,0.01988101004835846,1.3614168218859763,5.57430500641227,8.04590848746589,283.8000888451945 +973,258.06140308127027,113.09146056076081,22.236832283825688,-41.202190848199855,0.12215615167706124,-0.10778281582482527,4.742603756405056,7.095727396395244,7.176018831520645,222.30528828257223 +974,616.5498784449326,67.74164946328825,23.671577068889952,18.307964225578857,0.0829688037514144,-0.024532413049248913,1.868142965963807,1.8928325435625086,4.794561616458059,216.8829277217253 +975,443.06143676847114,177.7556651896717,18.0654688187784,-45.185630199460434,0.015598529783428822,-0.003696758906541975,4.749008761787981,11.873086823315324,11.968083907115892,309.652047445738 +976,459.5618177464009,49.811698138106024,12.90143329967025,-38.33717437388639,-0.01110951400979944,-0.002534808130032873,4.176649784733134,6.009967340496852,10.792975296489011,81.05252765547297 +977,211.25443583775294,14.17802460687484,23.13551795278267,-1.9668486788501909,0.3153425623020678,-0.15180178579359768,2.3008391155399166,3.4174509364931716,11.169636515984536,333.39952394660435 +978,235.743418044545,135.72905259910416,2.073450418869247,45.88606736766641,0.35884157071577016,0.1772737318647934,1.8441036793566756,10.442755457132876,13.6113193657088,239.61624899256557 +979,187.01410732311243,102.06782248741011,6.137511559902385,24.04057862376922,0.4650769864108184,0.20838720868103228,1.2555753046901785,2.548920941947123,12.127999394837081,156.53468518490908 +980,130.59118108663486,83.37543837429835,11.892207229729344,-27.006210874333302,0.2764385380310571,0.036703133203733695,3.5078865928804133,4.12627832485775,7.27930461489014,226.18333894620076 +981,691.0736558188993,25.403763760417693,11.593306327039155,29.229560671875177,0.6074151313595403,0.10159865765993142,3.78588538883292,11.187860748845974,18.3248683961705,258.0706530807229 +982,246.89693328129678,103.97397632433093,12.697337022004444,28.562104062127062,-0.041530624789914,-0.2086504918525235,2.5552140680707214,5.736727164641795,10.136417681558141,234.90990989248013 +983,577.5960912849742,72.0593737927192,18.7290799966537,9.136073076783084,0.5061693213250682,0.36233468069710945,1.9988876627288694,11.8274262389149,9.57210655279439,234.04063796849277 +984,200.2419668368873,31.591307782881312,11.24689651725414,11.279955629628823,0.040866613398878884,-0.3040148542057961,1.482924443425113,1.0312881275146557,4.018146901342938,109.26969049832995 +985,142.18357911894515,85.88289610247094,3.858017299340988,41.23376143615033,0.16551535062309986,0.03299867815241786,3.412925869513294,1.0941143496897252,4.959972379851338,258.87497080807805 +986,383.6668674850925,118.0286098028305,6.462911939521591,-0.02187580418954127,-0.030312818386965083,-0.30218575012705035,3.142580667675971,11.779956475224166,10.789511250312136,79.16731223046278 +987,213.4936901077827,129.37483214157217,10.033012913532806,-1.8105323487963147,0.2841473704345405,0.06428114368759691,1.3727020713044025,7.5268908186810375,13.698888267759546,154.93217359634116 +988,410.35875503024687,181.3035092879147,10.316324392484526,35.769073156904156,0.24840237082177524,0.2052146311640874,3.9488961696818405,9.482318173505423,5.101213918471007,267.3034560408867 +989,454.08243304005475,68.29154102363029,6.32046000741181,-40.11019497409612,0.6340007893266643,0.23817999647865812,1.9550706911728912,5.883718960964977,17.469173185773588,272.26046187993137 +990,322.6648222506049,164.056661954196,14.156657175432095,13.383167455934924,0.04261656781393937,-0.2960737486632915,2.013027665250785,4.265018904974566,5.421434923206749,29.374805250178202 +991,125.14553219291983,108.03884036970247,15.72688038708982,-39.27541960770964,0.284341198122563,0.1354065710978331,1.5761325768082295,1.1849879155464806,7.784146691422277,117.05443448781993 +992,205.97968069393207,57.80820693609567,3.2824561903135985,42.52541593043988,0.5432343533117966,0.057702790624689804,4.388422113243508,11.852625550785739,10.501896411550675,74.73061307542415 +993,580.5685345740333,49.729798656037836,21.241603442856015,-3.171232556110482,0.4429723232662752,0.31010437583393496,3.3707311494513323,2.039836355476353,7.787730242615453,236.73881610896998 +994,550.1344354061356,103.07915341472393,7.8193929022274755,-12.331218609799244,0.4897381251675569,0.28981009116163253,1.2696933169406626,10.134101653230918,16.390656131983995,203.58042157231685 +995,378.8653836584623,159.7774595917611,4.496977564161616,43.38329213367912,0.4330542129734004,-0.10332454439013675,4.59621614056535,12.36908864696897,6.768215277282834,288.9772236087402 +996,78.3104818957457,11.814930562663633,2.85611235967683,-7.306918747363731,0.3800479772246391,-0.01683717829153697,4.660707039421935,8.527697786290549,6.242422421238875,110.46653983343143 +997,382.53571201118274,30.587386372126513,20.57611119695335,44.4745184002021,0.1897034628850408,-0.21696846042742945,3.326901971100896,12.196446342363828,5.486205226731738,330.5256413926733 +998,508.8571853081814,149.89630794700057,7.9266499460729385,-22.943186970420935,0.3509577376365052,-0.13773683271512838,2.9672877058438396,1.8237008095883205,6.708287960789772,206.48965469754637 +999,243.9886143520054,99.68959490996232,19.982964252725935,-33.41683912122986,0.19020254803276215,-0.021176717928122868,1.2651882429345023,10.516105841294012,4.723410493094022,59.435227473819474 +1000,108.166161112694,3.410462575397095,22.892284205344055,-12.507081483338787,0.08907208119674807,-0.18399675634769525,3.4936404305163364,4.221739246846732,4.816032555222574,148.71391612995774 +1001,105.70730442852067,87.05880231143318,21.064656557123723,44.415998406171326,0.16835481427993942,0.13046889863578998,1.3891921537095413,9.21168392610875,10.076085667206282,177.12335355422917 +1002,858.372310643705,100.53708333139544,19.530638697431463,25.297297787537772,0.5768512592242497,-0.021655936574509815,3.4960977964095026,7.912214253799676,13.382148773675773,267.91469423378584 +1003,188.61637154366005,93.3641891398936,17.491000779769514,42.95207666866003,0.2183206974832146,-0.1990946841654908,3.9993654450515264,10.33056546416737,8.515659602616473,93.10813871900349 +1004,359.22508916140566,189.0500526546166,5.6752966265246645,-6.390993581616783,0.1819240660111457,-0.22188884935323672,1.5699570415120134,7.177268914887367,4.73077431267766,300.59911587107945 +1005,37.344566531233696,4.1301579586103365,1.6615699390419874,22.53811380041904,0.00935483319473314,-0.06310403540813253,1.6613376021561694,10.640146666902139,3.6264818678387876,64.15290907651584 +1006,153.7776177475747,49.8592261091823,23.504869269254073,4.810883861958999,0.26003048660007766,0.17205565305265685,4.464607579412686,11.203714230732299,10.544265052695373,309.7699664241889 +1007,589.2656334580789,98.58064359976599,20.947877828280923,-46.04657677184911,0.39313281235364284,-0.14986429978134336,1.5951402675929258,12.50230864969347,6.804068518605069,257.03420639326697 +1008,266.60829580617946,158.31122924942602,6.546466444898635,26.495000019074425,0.46625019102893106,-0.07475765385606586,2.6157267134282955,11.202759299627584,8.83921994893365,37.30440699818958 +1009,239.45397406503622,1.2768417668944751,14.570887349222879,38.565038803429346,0.252999850135335,0.20711725123497965,1.2277429853222563,1.6717856684227552,12.547778339387673,267.95840389467696 +1010,623.3767867721298,130.45669354191585,21.06094387009543,-7.997065650552912,0.06651459431099803,-0.00828525286599563,4.784854826800528,2.3631904334106926,5.757379560490655,176.5651573237736 +1011,492.0805556508394,98.83712819318657,19.767751791872854,-27.824490188664747,0.13097030501908635,-0.264006998649189,1.2238706781660946,1.8947755018647094,13.260700734177119,314.2261093454407 +1012,97.65970393240681,77.45922545004314,12.082524441300944,-43.755964838119425,0.4705436004420386,0.05491586737610443,3.3154003214505225,8.936930539932025,9.640568810521643,43.43204722321582 +1013,395.2526353657075,188.0522455557729,23.782705884438133,3.2395633055399458,0.39981494066741874,0.3204604720310375,3.0698252691430534,3.3137560845622174,10.195687283980135,80.35171666129816 +1014,242.72208198876933,17.342844172901724,10.158262026642578,10.56175062264333,-0.022665611977577757,-0.3095950422950038,4.486883991148596,7.255415461474493,10.044478981847874,57.12469310173765 +1015,233.99074632982456,88.15139602493609,19.792086154323105,-42.34205093582265,0.12821663985084503,-0.21800087975203197,4.78879478851017,1.4609626177279185,12.962848519650557,189.0620769370314 +1016,764.4276581912177,131.80502795038936,18.33483829178627,-18.66782587723981,0.01852060095117186,-0.24512528371779757,4.669087708239184,2.1279876688534274,4.631374286229132,352.4493182777129 +1017,201.2667753029943,9.881255149368842,1.5519920070099595,-21.897679553640902,0.4140125777075311,0.32257359986462814,2.9860740724729053,5.939874907734956,11.713739814573648,91.98337538930393 +1018,206.95002276920252,143.7077195867722,1.6913468576563047,-19.953952051740114,-0.053744604546485775,-0.18311684289699837,4.492196885857546,11.374321144958053,5.399523213074273,52.70081189170421 +1019,275.1589830243281,12.242980931013868,3.2073221962296135,42.9589452736039,0.4042742291587037,0.2513688081422118,2.11357768005736,8.083133661736252,12.431759936392456,319.34700610696075 +1020,460.8529055852627,90.16843244759774,20.914010235588865,-41.54770776674454,0.6622878202959556,0.07190944911398384,4.543768713240971,12.976870534961849,16.4880326862583,280.06476245712844 +1021,379.74864528092905,190.95902265030352,21.227720157674955,-35.76320843877016,0.417824401853859,0.2627973982334563,1.4465026096730342,1.2154744556997885,7.945966723598463,15.264223637733636 +1022,142.89014546737818,108.79328389301912,8.308362981706246,37.88097010962261,0.4120355816388036,0.2985812661274984,4.1869177984995325,7.5980120954886,7.593076005339135,18.985750896201626 +1023,618.0389014905091,41.19869201661918,17.26879181822433,41.41135892399197,0.33470757720043953,-0.11268562775860244,1.9850496771118602,11.26192440589568,6.4601892878676335,36.858469184766754 +1024,285.7779945418471,149.46162736881828,5.916369315500242,-2.9489281930384337,-0.048440799200176535,-0.24655767201257825,4.233554301329645,9.326414252558997,9.983810583937059,285.6927844440813 +1025,436.17517274869925,176.44964336904133,18.99216384210636,21.652709400912315,-0.03378874782215664,-0.058131408903747295,2.6391890195789047,12.670774078681296,3.7397008889670498,339.4058804763134 +1026,1010.58363391218,61.98687374057699,20.819059396103263,7.415301153599998,0.32211923058048547,-0.08803093859102828,3.434396108694485,11.283836793350321,5.530297105593995,266.3246091572887 +1027,256.57095330244954,44.319656637606194,16.30975318243691,44.63806754025582,0.16960677282145903,-0.23677025629814943,2.48085087755413,5.1614837665802,4.0906815245585175,279.17899503953464 +1028,611.035244887066,71.35824734967943,10.788513199679164,-43.62184355946428,0.08895876104308768,-0.27781411749669754,2.652572410963603,1.393961798721699,4.622051520944402,119.24768471251156 +1029,844.0732812001941,62.28085635067555,15.192415996056027,-13.368282672934264,0.4502087413735868,0.2211980302284539,2.7199700174726766,8.042941051754568,7.863103568762616,313.3511306547915 +1030,551.2654810432248,154.21605385006282,8.909652967729016,-9.716268410087295,0.496181360083331,0.2115111599230743,2.0766711546585648,12.531380942268491,10.650654059325895,117.88307751298522 +1031,382.78148970721793,61.88898196116962,16.841087428375914,40.161287242056915,0.39060749975232295,0.10207291653238892,2.936636225411425,11.400653034324769,9.92771024791088,183.8910078267675 +1032,155.77812802560388,121.17441369947005,0.8797877375964649,-20.182428442088124,0.03398726620950103,-0.018824890938256733,1.4522578805474682,3.702017998532747,5.9331955567134935,33.832035320752965 +1033,418.2992904014274,18.96899860068902,6.949578116594154,33.4537190815479,0.28625299589819786,0.15311793983792565,3.2970295650614503,2.1903186331406843,14.942738467176573,292.68637097432253 +1034,127.77120279723852,88.20636486750723,14.97718572837076,-20.516795191989946,-0.03714952187793704,-0.3058821298851864,2.1091384363490886,12.828220385661352,3.9361694907965985,52.181244315652954 +1035,300.788888476256,4.135434429146169,23.54193377616373,40.84125378451216,0.06798827578920529,-0.24902979880853215,3.2001070768765247,9.105847461034942,9.45825161577323,33.12057942042397 +1036,692.7091174292917,40.283567329360956,10.190346578308336,-8.078448264674428,0.486429910906541,0.08127098237701413,1.3808469498394378,12.493498400076666,13.604925095081137,313.1598272667297 +1037,222.06452828768482,62.347224307631315,1.8661345224253814,-46.34902203862478,0.07208200195188245,-0.023839419219448765,1.6539132982082378,10.04712017379093,3.8659881434668875,232.47048173277176 +1038,165.63450987717155,45.78892772505388,14.636369937948936,46.4376118278673,-0.03199249564090122,-0.1016418105252907,2.4510197157393083,1.3866853564025736,11.110034785740885,110.9860560722843 +1039,796.595931330275,90.87833283773627,22.07382282756296,43.31628070524867,0.3844336272434824,0.1153008193811178,3.753075226491368,5.261371555890814,9.538951935482899,37.34939876624533 +1040,418.9218912504388,31.84356516856454,5.51851910418479,-44.664386007162754,0.37728590733556766,0.3036192769190213,1.8169158674968813,6.447451551712659,10.225523737099138,314.035035187947 +1041,972.2253538840033,94.80844666364808,23.41745923993181,-44.16873726927032,0.29617812086990014,-0.14133857015459284,2.666145696264035,12.3045089472676,8.259311210531758,64.06430553353874 +1042,138.1475937893768,10.012653760221564,10.561853517371748,34.746927263368875,0.13279589639632122,-0.10046035732288319,3.501526326942976,11.984831103068988,4.3543013528038115,54.19915493840369 +1043,95.46137865919107,93.59154080342164,11.83783335096587,1.813965608853998,0.34174660819896857,0.19804035247455348,2.5809364052567747,8.75644264867889,6.30886813609783,110.31696493301354 +1044,491.1330667103157,164.1402236313252,17.449092176351858,39.47142802578344,0.24019185626671136,0.1654624555162964,2.9741726556145363,1.7570834686291625,5.080743043784992,88.55143677527474 +1045,74.2054138889827,49.56750296729278,18.143899603870057,-43.73432771004254,0.4446951358849537,0.24052836821409768,3.008124265944483,2.9630607193420238,14.031140540397258,151.54800077015605 +1046,784.6254316104364,44.18329275608428,21.055441255474896,-37.44138744817257,0.1192252118190663,0.09749563383169818,4.488035892595025,1.657402657031148,7.963827942267438,262.86528047015696 +1047,474.65636640846566,3.570353321098688,14.447399084103164,3.5256785921486937,-0.04455913262439209,-0.30179222082595025,4.054372093708958,2.950354020123492,4.793119395333962,334.0343863766928 +1048,445.3511026287899,5.23040837961725,12.075786530988154,-45.634487123324625,0.29293073259927604,-0.13966707194428685,1.9132982141031132,1.1095923645658425,7.6921149263076956,317.0246201043263 +1049,298.53526556930177,21.9167510956425,3.375039838320902,3.0112046452895385,0.10538642930970964,0.04838931237452382,4.330479658902761,5.357383135185101,4.976979580001579,347.64440649504417 +1050,722.4563889640438,13.22927553398606,15.571208587590316,42.93230432817644,-0.01656587482566782,-0.07314597322191313,4.559710071655183,4.429056075326746,8.086882492331354,133.52128258101249 +1051,1085.3504626482932,77.01197340840122,22.804681204295935,-20.105064869746737,0.521967063828917,0.3776764046515501,1.3333001377857678,5.800777900474423,12.49724831661028,281.37802265413916 +1052,391.244731179969,189.57310513558505,12.795954999977056,-37.67564661207329,0.0405284864088271,-0.23807600252648453,4.7415548147427495,9.839048785167368,6.651159889785194,210.80598216402848 +1053,699.2348561274342,31.079381691377602,19.89240570728117,-9.141198274231897,-0.047824414623969705,-0.1824040001886809,2.974883559623839,2.0236322448837836,10.436693662174054,339.7456993281288 +1054,356.70811000344395,12.581448619521888,7.243630702032984,44.46759458386833,0.537916789443254,0.22437947006549946,4.175421349567197,2.339392441243085,11.46624735804268,146.19590421965438 +1055,710.5978491765263,137.3048329166249,16.94080212254125,-14.214153341095354,0.6241090141432715,0.22821995654879584,2.5588954145242573,1.3152020043153265,17.591939864818052,262.9951106546833 +1056,461.23047911276973,91.91177218699622,23.857495525951272,-34.93575199144324,0.48559958693062755,0.25046199795504126,2.8143837598672627,12.839780952837927,8.734467983353271,158.69124534624387 +1057,425.08153184809964,5.75486337425051,13.665353644190304,-33.063502429795605,0.4722065235369902,0.23537120114817184,1.2847063397850922,9.71553921428183,10.531322041648057,151.76429029585697 +1058,359.8568800200644,182.54909006714246,23.34121258514614,18.150618034238548,0.5225081928383247,0.3122636747042646,1.9991630143461947,12.195478030854922,10.791578885233267,110.6995516821718 +1059,73.36487981585601,10.061805297437955,8.333475225897248,-31.20835854852408,0.04730997580496481,-0.027951298761220045,1.9826293925380365,5.730592834600277,9.613259893774178,47.23139488934783 +1060,576.272380115726,153.56480139651345,21.65565560383221,43.95419574237074,0.513447370906972,0.25794868861934733,1.1822928807202573,4.081520917183063,10.42211517168652,271.00937331214817 +1061,46.37955388301778,3.5939900495700785,0.010254670465532358,12.087088645950864,0.2523535770122174,-0.0346976980692042,2.527963851746105,12.95789960232834,8.50760046414306,169.6594314295852 +1062,125.92936635319401,85.05668434333465,3.682262474333701,24.72564753132623,0.11451649219883257,0.11519504090224547,3.579014511417964,12.563885054343665,6.7814467018141205,12.571320349755831 +1063,694.0616354338832,57.18535659249066,10.274746462947537,-32.210274137293446,0.027278919640187638,-0.26233039937107083,4.251909003213929,12.14306774598772,4.582670665438055,319.9200403603293 +1064,500.8579259376472,47.676283204210684,21.755101416679256,-20.596894643594517,-0.05340383387319791,-0.2798394761394691,3.371488294050377,7.8586949475922605,6.857070746226527,215.79717102783016 +1065,453.72976497280035,154.42190187694658,5.692850251710338,18.221080443577563,0.1184516695152034,0.12176944433578091,4.30239791315877,3.3677172147747765,13.159829260016435,128.10516741309982 +1066,44.09076714443482,37.680096544421865,22.62729955976181,5.845559642724027,0.42093314854864844,0.1326501503932052,4.111888424733599,8.690080987163707,9.400629377460493,95.44412602123485 +1067,358.84450767934885,182.0595980885634,18.17877022416666,-7.451914910193885,0.2176215541889211,0.17166263143006638,4.322452138073444,7.657010074610397,14.213582668575924,307.1857886008075 +1068,1036.7529737344341,72.24088058203753,21.77429550746693,-33.350963966144064,0.14373963788737226,0.04640699084108274,2.4610083451259706,5.495312434332508,5.60336505648438,333.87693049984244 +1069,380.2628417430762,70.46961508455513,17.394553484657216,35.08221232007922,-0.05001380383035492,-0.08725115221236257,1.2225689975442284,4.969651861680116,4.094569170656948,76.0232850478555 +1070,353.1765420869267,10.543418359855869,23.141165844472056,35.911222450723116,0.17063683345479735,-0.24432290623507827,1.6738470262474254,4.172219646869005,7.548707151305605,22.779594487227545 +1071,475.0608150020175,40.542099571245664,8.465186045265074,11.176780834217091,0.33351666354441356,-0.13375796066278206,3.6657255852066006,3.2415481252077196,9.300010573875834,205.24085458285205 +1072,548.268700929747,159.3862159466782,11.973929964337358,44.746127083469474,0.23503116253169293,0.1772455868163429,2.825596230953521,5.705239989153475,12.959405834125135,307.46079846446486 +1073,280.16609111924436,101.54650192461932,14.165186953806554,-27.55855899413367,0.41202316751685064,-0.04398084557518972,3.209042685647125,12.976156140793485,7.529759914475797,334.08224679032827 +1074,574.721142882866,157.67858910056435,15.263122240575491,46.786806300370316,-0.0562800985236662,-0.1392017339694813,1.3889666083975825,8.072795539585819,10.770394059951538,63.72016923444852 +1075,754.7062244443763,73.25663492936373,12.022399059364403,-11.503516849858045,0.16019409178332106,0.1577273019997693,2.8538034602087254,8.120652071173861,7.313972497898817,164.68171144934743 +1076,796.8391493166018,121.67177020874229,14.152928734294402,-40.272199676440394,0.32709430247560495,-0.10478022014741012,2.5877655263426753,3.084688573415182,11.144195062234306,86.71529799655202 +1077,238.99748591183732,151.0561127472102,16.043663398308674,25.440371612942485,0.45963134423199725,0.06079492435726763,2.0009684640604126,6.5165019500448125,7.588746981618735,236.5785770105256 +1078,65.07646977443511,22.507116593851123,21.565088667066966,21.11850106136039,0.43601679879192,0.3212909844891136,4.558893069426381,2.7705231606201393,7.908076882950903,330.5105951478684 +1079,743.4257214615933,107.71573428517677,15.692464411236068,15.736763989424581,0.027849889970260458,-0.26718622607352543,1.380884904956881,6.583505690525771,10.17670370562104,262.13449461641443 +1080,719.9831738961615,44.009746424492285,22.014315658990355,-4.529497392617998,0.18610949100986618,0.16018399287774437,4.2925235550712815,1.2674237646910627,7.313043672907309,42.764027741553136 +1081,430.25740537039235,92.41399159683743,23.521639802473274,34.73656458415141,0.06171998145331124,-0.2918856141152968,3.897935458164472,7.165636387734243,12.61064331921136,165.8172729046761 +1082,222.8681219519534,142.96866259354104,5.782290883493469,-34.67747221218588,0.41118529908753443,0.283909855074085,1.658856741629016,12.634192020783788,13.207345826975882,315.4922457789704 +1083,288.5544993842629,16.167291111318747,8.222813279323379,-28.583574233122327,0.42036696838271975,-0.13561826295664398,3.3086830411163364,2.410528826954229,7.044776271537066,4.900129062482277 +1084,161.92706317947471,69.7481080115653,19.353176946717603,-28.163736886532934,0.5068528014394053,0.2816057740002293,4.697085314147337,12.778362687309915,11.356241674244243,88.85776389870918 +1085,150.80670123479229,120.6808977736216,19.609679978670155,-18.10393301093931,0.43192983688981634,0.037081830962705675,1.745390998675033,12.917044152022243,12.879910303927957,217.00915121960344 +1086,476.3305855467915,84.40206607169225,23.572900374945068,42.734863384878295,0.15990965703604887,-0.1409952117636489,4.766024271543413,1.211136605734765,9.319359580189293,88.2498140010837 +1087,482.44049955589406,77.96030776382885,8.010549236799452,9.51134135604152,0.04414350943473304,0.05608880014279588,4.496540919805315,1.4893082046198607,10.032461495247826,321.49659181636724 +1088,149.16934969603437,37.79350068489675,21.805272601223457,-38.292157045679794,0.32091774472132856,0.25875665237084594,1.8679583252414216,1.5421850951989877,5.3916053420339285,298.6484055650116 +1089,353.35519609845574,193.27665558220377,4.274804704269253,-22.55392987232743,0.24796959988955497,-0.18267540853147082,3.0427346235689026,10.484421179627093,8.866417393401164,64.20839884018072 +1090,364.4792557672714,191.46482574760793,10.64293806539611,-1.7743835753601829,0.3804542455970118,0.01878477507677001,3.937070727278183,8.792376790057716,9.17662001360721,169.48648888282332 +1091,131.38481240044302,19.067268002426466,10.134736564851664,-28.351756370974496,-0.02768300263811834,-0.19743396968874882,3.7596411922364013,11.858331404408913,9.330041517501698,120.55153394417019 +1092,119.30760360341823,96.20396694925451,1.026095999147037,13.813286776298455,0.23884145581499966,-0.17524144120371313,2.1621085361487467,9.463433336192017,5.5278713061508284,52.748836875896714 +1093,1121.0075631457826,66.63716356432721,23.425440575882718,44.7768618526226,0.07696997205995874,-0.19123441023758597,1.464339535521558,2.8826002336046708,6.86679138178885,226.0252216234086 +1094,791.602503722526,128.99542410483974,18.055380220903434,35.5072030625397,0.27969675580044806,-0.16559791271617988,4.40174151275041,9.336303600037239,8.436529346959471,351.12629537242 +1095,583.7590947494585,28.642310267460783,9.916351331621007,46.40841547915706,0.32701788406547283,-0.09636142154597185,3.631502299426308,7.828217098625986,5.447627086243955,154.55194173458707 +1096,323.87704850825014,59.01286408263295,7.732004817718425,10.163090709011783,0.6339114449753959,0.2541670075345556,4.010751399058723,6.256690267265414,17.707785836214768,240.05312248494587 +1097,116.12218925296122,79.68245778953512,22.376838529209635,-4.403475562846836,0.41914381086300284,0.2316201338430452,4.5118977425437885,1.317008850012347,10.559964351633045,135.37404334919282 +1098,309.2836131910085,169.20388396439952,9.177870223002092,-12.325090190994416,-0.0007529046068486811,-0.04112933767055715,4.23691534890138,12.671292501064459,11.195435920196582,135.19024357747978 +1099,288.48088291052176,63.74464069052662,7.7572047756472635,7.7261368570180124,0.4078052483100754,0.3324647741861925,4.633766273859765,7.635032162256097,6.520347524299007,269.20604720627153 +1100,171.92820402780336,30.742531516318017,20.182089728370453,-15.007514019492039,0.1832352384863083,0.11640913620857668,4.575205945597489,5.099546921844282,14.044793691083383,287.0423631994816 +1101,199.66839908787327,124.656170543014,1.5586652617125591,-33.96762360849547,0.5279911892615056,0.17963380168238036,4.807098621279028,12.028643322030568,15.768200252366452,255.99681420762408 +1102,754.3480210533205,84.19346295959869,13.45054533003666,-21.55403805218222,-0.04507857885571717,-0.08118800512052504,2.0180046019975637,7.4612992597568,10.20421700590257,63.505381864446676 +1103,281.54241667102605,168.09978496190186,2.7990157136964546,10.04840803004317,0.006716958666637102,-0.0671110884193421,2.8685032696020683,2.3067472050953883,5.443880457656807,345.2783901645985 +1104,112.50353802488857,104.35908901263271,0.798273853983942,40.32504292556111,0.6187759458089845,0.1698727860329045,4.291477585686198,8.787456208418487,14.157525530651348,279.6033372536096 +1105,282.83383163895957,0.838901346261252,17.570165945177823,-45.78615340337975,0.1880273244094386,0.19979770983745143,4.498721418679031,5.4052367287995144,5.808857617193308,265.8911216215905 +1106,765.9193930180413,25.105999358015975,21.64153256083627,45.17961406934586,0.4464150362918784,0.2864287140936263,1.501044009137102,4.34174911203485,12.230414838839515,109.91397003778992 +1107,527.2571915641996,154.27488815385448,20.990830755758715,-40.918176842253615,0.35034252593806015,0.23366601845327012,3.183443829280942,12.74889871967609,6.250099401852239,355.13291685124676 +1108,423.88127895301426,64.335392156542,21.548658728799975,36.61670904966252,0.5120895521694904,0.2771120627576444,4.254257682317386,6.967893497287741,10.892843533325504,159.5861121226423 +1109,442.36001246489644,181.13862976360576,21.44354679343934,33.23181272342532,0.16047495394786937,0.13235815846377752,1.277411199319048,1.3632743985890845,10.837210963977375,153.7934476294766 +1110,628.9319178565719,7.548748048648452,17.487866947481486,0.5460248326457489,0.4129834139631128,-0.025850137496359116,3.0895896902875712,7.6911667802896915,9.545929826657613,103.8413614918703 +1111,192.52929067644146,14.707379269940693,14.48519063232204,-34.365971569248785,0.49518366573447536,0.16742521265688703,4.286909261503844,12.753049973636891,10.956349856144918,275.7094838043322 +1112,66.44517930986643,31.75546165664562,14.982458282697284,-40.940514333597456,0.03706383555356223,-0.09036733339876701,4.150960837435916,11.005601107437212,3.809364118218906,333.2557167535304 +1113,200.54255475182686,100.94662889558624,4.2435220376971206,4.1121307491567975,0.09053452626666962,0.07177775966199818,4.558368502859604,1.4851086774449913,3.84785998491728,150.45670943687574 +1114,145.44486815552244,108.91017639847183,23.0559938270619,22.56048465206844,-0.03243391139824232,-0.2444264933076261,4.733377473913627,11.726466471094737,8.32074532533349,333.0832513563112 +1115,475.6480353080826,28.4534202570384,6.962197442131301,-46.718570821348166,-0.005179405655765898,-0.08133821111100392,1.890406291962739,12.538082551648259,11.588406132544176,103.49355462132208 +1116,42.351505689826155,10.82596689513188,12.982563647865067,29.717241845735344,0.24078381236634516,-0.20101808522327633,1.254282311691689,12.676864125241593,6.445068453559578,321.1732499210089 +1117,162.03895246228544,0.6485725608577328,2.3341777076089896,-1.637513139614434,0.3789311094329232,0.1647573526805648,2.616021658227448,9.28808683755848,16.17516585768567,253.8103319758874 +1118,339.94696537287757,12.230448506152909,13.111175660740653,31.19986162517965,0.3957596458861192,0.2743219856009537,3.4147836353517755,8.564661978273403,15.503272000953034,203.0964440575847 +1119,341.45614438595516,104.93018821145566,4.7682880132138195,36.97010965918601,0.10476872726954821,0.014416772546303636,1.5502345067057637,2.7987739283277335,13.746799308798684,280.25213778164306 +1120,552.8021663668173,16.61596558010853,9.139438105893857,-43.126461451564154,0.1694724281307669,0.08107467660039008,4.029891025996712,12.613254913167346,6.968355731856285,66.59634235253861 +1121,755.2082983488982,130.60865517517402,17.05803915361885,41.79631162266561,0.2859777037385587,0.20521014869536142,4.572970880143007,10.738133861245636,6.75339732671498,188.11158229910725 +1122,78.71689210647729,6.980995443153125,1.4503272352636298,-12.061621097401819,0.3137057628533301,-0.17784817957169188,3.017380363905543,4.87361729392346,7.479525179150459,307.1076121346214 +1123,259.68862743718165,135.33155554248506,5.407721862822852,-42.142843541922694,0.38198747981458936,0.2972045785563712,2.9471374014904814,1.8626144385687677,9.280205292035053,134.1813569188781 +1124,131.1751706236726,20.30138001259796,9.97248674596871,27.486026926001244,0.4172464308653365,-0.006477608691485226,3.953805866228536,3.392844751062114,6.631327867304158,8.418111903544473 +1125,71.92810653755608,35.62486537838678,8.078127569360984,-20.748466641368296,0.2886637089453622,0.20317356215319687,3.034255718795851,3.1482097987590993,14.627242760862297,243.408355746999 +1126,616.0014372401922,50.82745616735494,23.313957603688657,36.177870723786825,0.41260086284530684,0.06454516205478383,2.1583129696258587,12.775039015232469,11.350392300822262,323.9601055876084 +1127,114.9836302205435,106.03387118317858,2.6847662832965002,-32.81981729671088,0.5941880695851323,0.21237454437178788,1.2940193659586956,3.42596478288646,12.363330564880993,104.98506302930072 +1128,557.2343963190275,25.125698349659732,18.917364634117064,-13.109086615102768,0.05486492733499275,-0.2904327615394879,3.8746344372304726,4.082282108806716,9.955698523958322,54.47719613615399 +1129,905.6806062162743,46.2248502473585,17.393286279360503,-2.2409843648120216,0.14165942324817893,-0.18003923513946518,4.342230249496121,2.1693980555195873,5.1071291851517575,235.21680605267488 +1130,355.79363113427235,57.574470233087126,14.748227660653473,-1.7305176526969248,0.2491818204651124,0.16568322400426894,1.3321183568582042,8.965086320563188,11.89820745090769,322.57187330970385 +1131,71.25577844387418,1.779472873485617,16.089855743728155,-0.8834889892043591,-0.06686586068817124,-0.2191882780887402,2.1354933036924613,6.474644617126979,9.041780199440076,118.65735672985336 +1132,146.34016873729345,40.42453540478151,16.14555238973967,1.9662740197191795,0.26497654599221543,0.2361171479691963,2.219631356968117,12.993480831138124,8.710419357263767,19.236248284792982 +1133,709.337093148692,55.30366040987935,10.641332416626101,-26.182189107717974,0.27258097973611795,0.14853345865647,1.9699267775844174,1.24983496970494,9.30848852888191,188.35308300049257 +1134,60.09583344421495,21.314477467558934,14.86369982153218,25.175538261367834,0.6090092081341643,0.12221160779463819,1.2612443489896144,8.462822442839975,13.008300195399704,295.6071042869895 +1135,653.1184294069554,84.47199808546122,10.534056527312698,-29.217487965659636,0.5139730452046368,-0.05341610573954797,1.5648916922734246,12.244117574078228,11.135996479948885,141.94246904892702 +1136,356.463002770819,154.56216579886836,13.622615015959834,-46.12544174062712,0.08265149752852928,0.046356224604971075,4.6872894905388565,1.7173044263829995,5.618565378093426,34.75638343639106 +1137,940.3489648699772,60.30128904850795,21.8636489143357,11.607792367612362,0.3878189412115235,0.271134486088665,1.8586648017743288,12.586417501972267,8.34216882177683,46.44283328888042 +1138,400.93177857888145,8.030695043678987,6.9502912625362505,-43.46315713052122,0.08038827445745787,-0.032393880720385904,4.221080706202973,1.8748876553516447,3.732759708841178,255.41852464422024 +1139,851.314182570303,116.82663457041134,23.09209969360452,24.504478542306117,-0.014355875384259496,-0.0877395179507614,4.584226536601414,12.896847259681657,7.8125989123215085,283.36956655014495 +1140,744.22727387197,111.73635572244898,13.013381616573017,40.45938901152496,0.261642611546003,0.21888042153519732,4.646096597093563,4.251899688455874,5.095816645449663,208.14463112135545 +1141,508.2887966265542,7.38564210145746,22.634145664061293,0.9148836501838602,0.1293938599448805,0.047499790909891315,1.2509955520194476,3.815686802273037,7.537016374084677,352.6810828572837 +1142,207.55045286015886,67.62206894665725,11.945555033945823,30.254806013476355,0.17292713862948517,0.11080103120990076,1.2911617199942647,1.909716619641859,6.9889646537702586,109.44768752152565 +1143,396.56178905029884,168.10589305706083,22.702862427630734,-24.960098314226684,0.5471131577498327,-0.025504239911804283,4.188220237593452,6.888330734504503,13.373534272380299,308.54548327220124 +1144,340.67481302556627,53.022194392366465,10.809873658248879,15.551434099706412,0.3325528262430488,0.06268622599520568,1.2971955868675256,11.891969389887945,6.787283324040691,175.7832340514323 +1145,490.7411344347214,10.32891883500337,8.559949493381556,9.27726898112524,0.08893307072020261,0.0608988999493108,2.6333000045858466,1.9626391641565348,5.107719655163464,353.65690902657605 +1146,375.8160295965963,188.0932384659017,20.293836000569367,25.64723627960926,0.07027278140876368,0.014147500913746391,3.552929363602754,3.228525774714588,9.53119157175163,298.1759395403427 +1147,219.2631510614772,15.460536781732657,23.051289227959835,-40.63051665915122,0.16701728681707412,0.16294699391859357,2.931949131908423,11.71198409977113,4.931338331830105,35.52778261699324 +1148,299.1029540058839,104.02801205317868,20.242474743740075,-14.988892797982473,0.5322850872295327,0.18651093710959138,2.333234174252665,6.618200285099903,10.757955943649488,97.2887679748813 +1149,237.0450091017861,124.60416555846524,16.916481150644902,-14.39071225162678,0.14197727196171722,0.05288988531789973,3.006954955357566,3.2256213056826244,13.796060910303316,213.5027736121189 +1150,389.5633470281505,61.71112192801995,6.853026793281005,-22.11133055978678,0.2446637450556603,-0.20006016748432842,4.345872278080017,8.926939503974191,10.31939942477559,53.856064299611425 +1151,580.9235890829729,147.1677922387172,14.659588972290377,43.917170624226245,0.4926634378984279,0.3065288305194817,3.3853774159136574,7.677844682140682,10.207396593927758,124.78410233173253 +1152,241.32473745243075,154.04358818787463,14.0639040289678,-10.944067236775737,0.17448050204937304,-0.06278475120583676,3.8673084486496814,1.685434278171061,4.518905870944414,319.71213461168463 +1153,351.48823361847707,103.74721792454184,15.988042564903166,41.822634364464804,0.22828270649045534,-0.22666396795426502,3.474159850181688,2.315025232287648,8.194872214518469,173.95352781748915 +1154,50.22898435296928,36.62689392404806,20.71168088048979,21.7412647312549,0.03462098100187512,-0.2539359703401732,4.52886015991348,6.610364143490445,7.4071484616512,320.29043479966333 +1155,14.098166318684253,3.6103238374106925,22.765941521171573,20.916259373625067,0.35894293662360244,-0.09068684261600085,2.519611920313127,9.37436203552247,7.045481515148052,205.1279716330643 +1156,305.1043309547013,170.32675688560929,10.009481932935131,-14.009842170829153,-0.04243690473103842,-0.04180590966560627,3.892310538029524,7.665278671455383,7.467360136763771,11.621429969946485 +1157,63.753944145298505,2.261507014986223,13.145991409029248,-39.68367860684491,0.04140671651353166,-0.020903641557982244,4.5168626928265825,12.54137956700589,11.900011156645165,290.1165829873225 +1158,630.2636342098914,120.87340684909731,8.946383294204965,-29.488978849834766,-0.0015474498568296968,-0.3178598913676903,3.8166257092046685,12.10039100835732,3.890152148440757,53.747479063650985 +1159,561.0482399941748,15.88531662182921,23.68700025279797,-8.098928954242595,0.6318009686726004,0.13699739416965823,3.012736976420876,11.06744330636716,17.320264272477488,263.06953587243873 +1160,101.24894052176904,1.7780501952831986,8.378035590961597,-41.8964355986149,0.16024521226337923,-0.2147549629753181,2.591053008355637,8.71680019656794,8.802202002942625,296.0268090169863 +1161,105.53515728981819,80.1491236738523,6.451365578115832,36.71863758737781,0.05515960186748968,0.0027102116886698058,4.767731944900846,7.341620167385846,9.855260697671063,173.56548305498498 +1162,128.39578051816423,106.20238999408458,21.82076953730576,16.929336934162826,0.22899253662229774,0.018040445664724347,1.2576253507219057,4.30393478887339,5.479814069122719,23.301580828450323 +1163,159.30562138700435,90.79369664419158,19.750779906974273,-7.158023337137706,0.024472154761475906,-0.25697446701543064,1.260098034116431,6.816779327840544,12.217587615489721,139.10180174291267 +1164,350.3049715310297,119.46128050002973,21.076623509762733,5.254950407258498,-0.024194884016114075,-0.22469379619893115,1.9858771380314773,11.191330259727298,7.682557753953901,262.0017887374159 +1165,359.19262460129426,173.71094688613135,20.71074171518194,10.086433658461083,0.511992644582345,0.06452084027619331,3.692774810608223,11.857466746603647,15.486293070093557,202.1926001426837 +1166,432.5314428622214,65.96617425421148,6.252464558508216,7.470739026564807,0.3580706959366404,0.2114722023602424,2.509713570608316,10.716751595126299,13.260872721606653,128.8936536047762 +1167,241.46438387081267,135.52370668563802,4.229513908954333,-0.9409949407602838,0.12005141132923257,-0.25529910995040933,4.012954844151422,1.128976638877314,13.68343596837464,300.6843764860217 +1168,717.1294476815704,44.19580945112432,11.92352252360483,-40.06998098129066,0.0313214092773136,-0.25634911205793565,4.369872353077984,6.40434925221573,5.962628193560439,191.8086033327816 +1169,461.09472347839255,150.3685170040653,22.213316470627053,12.234618826378039,0.5324319273998056,0.38376644645076546,2.2146591487949454,4.166682931913325,15.273284206022806,184.1075688261155 +1170,884.8639399657034,92.82054587258376,22.069439868493973,-16.624892004306382,0.5888806047281404,-0.06939176227862914,2.651089584514543,6.150647984957233,14.038813627654081,144.4363401658886 +1171,605.9454724301573,7.329319906399652,14.602631196353517,41.55842180903926,0.034092410433613676,-0.07374169104427214,4.161700206396254,12.517369014648985,4.295707556607675,165.67861089693395 +1172,708.2996433833899,19.44111072859486,21.736766531426863,29.995820410322636,0.12704577197862016,-0.26404961119518067,2.995944608650782,2.6563058510909876,10.366857039492515,174.2611267956469 +1173,143.26009758049747,106.11453620799495,23.001553539698364,22.631673379554954,0.12373186797908196,-0.23606192528301895,2.1107705441514284,9.501818567062493,9.429564830002764,38.48130674538769 +1174,164.44500343086364,38.37170882013903,3.9214305900718807,10.171270071020665,0.4378367554594821,0.05871426000835095,2.8151827632167232,5.171345680351874,6.925562608473512,130.93557026626033 +1175,298.35420228566596,162.80679618370033,15.612638137806314,-25.48765033406664,0.26954345470314467,-0.20300810422355006,2.50440752630218,8.567484824592237,12.835742492185172,208.19004821563234 +1176,667.2807670794137,97.28123848221183,14.454844291062836,8.035014953588863,0.258497958429581,0.204114143122825,3.1293361615003468,10.08325506905426,13.90372650556478,276.24613299810613 +1177,697.0180166477893,10.791628748345332,14.4236753664686,35.89026170850869,0.4364998763271124,0.14484507633953914,2.218577567156436,6.633681830395802,12.34816628671625,269.7162866405446 +1178,773.512899415299,43.95744863125541,23.53181644800397,34.80319167299234,0.21713615422556792,0.09513207774965593,2.6905218436302456,1.5071279314437653,12.251385671758946,281.11068139387777 +1179,645.932643935173,10.526962819254987,15.253444353682282,-46.9087007431524,0.22330179894250968,-0.19935135291013806,4.06523107346255,3.2159979818704905,6.75490986603629,319.85873036508025 +1180,935.4848971078976,103.1709733538852,21.526551482445498,37.82802163015042,0.2567387574481128,0.20575157255174553,2.8046251478374886,5.596735649057608,7.412689013480682,349.4545214715799 +1181,512.3512597643991,41.84938897866348,8.704692306617126,15.505672331415958,0.06696845591216481,-0.28802021281010964,3.560799712442302,8.897624542097374,6.0301451577953245,328.3716229313312 +1182,950.3076340812061,60.821811134990085,17.857690238699057,6.452481714858521,-0.05279646205882903,-0.08883058502578853,1.2145305805935236,11.219498830048694,7.818377170297362,291.56090390812074 +1183,1023.9871784150595,85.34770110395793,21.936573393594557,-41.95544276727408,0.1714609661300316,0.08481620257498645,2.459156538768835,6.870601125366873,6.439479894195134,89.46033947262326 +1184,781.0209569718406,99.03679297277986,23.08077443889641,-25.708550775761672,0.3997260875039801,-0.13153547598174933,4.484303288441158,12.950152613485336,10.585546289856108,100.20639599514799 +1185,427.2410431958695,183.29447833125644,6.749184907572845,-11.754380832914158,0.2564164917691326,0.08395694161576245,3.079649555745288,12.668132011375246,13.625795796414675,264.4027317375393 +1186,285.24433203526854,65.77971476965837,23.44568370927307,-43.76035586623519,0.6085293434599331,0.1986127894545215,4.0755518562305095,2.002053481153878,13.658243505876703,274.87720970363904 +1187,458.658965283656,22.279449088479616,22.450953016171024,-18.439053595435997,0.30149368629056705,-0.15119178832901192,2.0831392064959666,3.260057769702745,5.797442128599236,188.73961989657542 +1188,368.43162390908884,129.04579975656338,5.302970293395484,10.432963205693149,0.36657861572850003,0.04994170178769619,4.787671200183848,12.838439018676787,12.541614601614048,319.1662510358494 +1189,531.2776880316237,169.7016747523851,13.056865792697543,-12.359035021102414,0.48400586461258144,-0.062046778387082835,4.7959044712800365,1.5653941515054077,9.636473319433158,126.94384580903134 +1190,414.50764516332123,86.23050097850127,10.96972095067844,-40.22986899212753,0.3969059976101563,-0.13428033216916258,4.771298068441354,2.3442077400943333,12.392923888736641,299.4334743705535 +1191,357.959198056139,184.17113728241793,6.636435951479173,46.98972452451028,-0.05024623187623088,-0.27478427115961934,4.790466747756505,1.719591532164164,4.166775969905325,119.21445645098707 +1192,796.3213797449263,111.83637359663292,18.666977969363558,-32.29342126104437,0.44457955102953595,0.3400923291698454,4.35702566216759,1.1538333195479777,8.053204929694608,167.7279657144802 +1193,650.0552274103032,129.95241747721346,10.126569731225523,33.06046458042481,0.4247017573299153,-0.09431116655198574,4.707687523457393,2.249708656682661,8.404238828227697,188.64441211427442 +1194,386.5789890176012,176.23148106648904,14.416687491353365,27.61648845280226,0.2482130933652389,-0.1885967617643637,1.6843383148703865,1.51754378970448,8.30910898193464,152.67227986364415 +1195,740.6469694600348,117.04687384676792,15.062758991610453,-37.72586322488775,-0.05742207967815231,-0.2866946672939644,2.328074056171685,4.893373055818989,10.945754271239963,236.912272018122 +1196,691.9396433299717,132.02854771312903,20.71829583805661,-1.152761761652684,0.09178043640034993,0.09530234516747982,1.9249061052859748,8.686204663058561,5.492747036373532,65.82202717418733 +1197,505.7182695449567,168.21503024553502,23.023490657542336,-22.686858360804354,0.3369509242481297,0.06653881143141638,3.94041106989118,4.107822723799249,12.722346171817701,128.28540601332918 +1198,832.89073256405,69.31744052258367,20.502693947201703,-44.84230139741521,0.22626740113632682,0.221216551320982,4.61390157903338,7.28242861588026,11.948830777439943,293.7479405734456 +1199,883.5138542190089,34.35109102178741,21.373846712322944,-8.592525189153733,0.4928989704693977,0.288495552507455,3.5631213650422255,4.2056420654524445,14.937634400432112,264.1998333883915 diff --git a/tests/data/interpolation/target.csv b/tests/data/interpolation/target.csv new file mode 100644 index 0000000..1be8537 --- /dev/null +++ b/tests/data/interpolation/target.csv @@ -0,0 +1,1201 @@ +,PC1,PC2,PC3,PC4,PC5 +0,-56.296703,19.766054,-9.060352,-17.101809,11.151433 +1,11.230969,8.330605,-30.37628,-14.834562,19.256445 +2,52.43523,-45.60309,-20.15078,5.716933,-1.2719345 +3,45.27874,1.0363812,-29.31458,-14.504548,7.6242847 +4,75.60121,-9.482025,-26.391598,-13.385847,-0.20154366 +5,-69.87865,9.134312,-2.9615622,-12.737695,10.06456 +6,48.069736,-60.17828,-17.60707,15.067625,-1.57352 +7,22.045578,-55.894295,-20.589233,16.655191,7.9780426 +8,50.82058,-60.436386,-17.753702,14.814792,-1.7469069 +9,55.39622,-72.12095,-14.223597,23.050003,-8.055293 +10,95.75243,-43.304,-8.877888,0.4925931,-17.222406 +11,-7.719028,19.698946,-26.662382,-17.935535,20.118551 +12,57.271843,-48.644024,-20.349792,5.823318,-0.47238213 +13,-44.115105,-42.71283,-7.804113,16.25289,13.567037 +14,2.3845117,6.085947,-28.179415,-13.4539795,20.563442 +15,116.116714,6.9407406,-14.330919,-19.190006,-13.932862 +16,-100.23309,-31.37548,15.447482,16.29252,-4.691476 +17,-39.718594,-22.532053,-12.289366,2.3389034,16.644693 +18,28.029469,-38.418705,-23.391457,4.458528,8.263604 +19,42.197617,42.543316,-31.802223,-18.531012,7.6495576 +20,11.648364,-54.806633,-17.727154,17.623455,5.980704 +21,-10.3192,-46.282562,-18.863344,14.841388,18.112265 +22,109.104515,-43.867958,-4.7597156,-1.1396707,-19.580883 +23,-134.68422,-21.208471,29.798206,11.629819,-12.771251 +24,2.6705058,-52.077766,-19.871775,17.341568,13.4893675 +25,-74.34891,-7.6507487,-0.04226815,-3.4473546,9.285753 +26,129.1387,-13.614919,-5.7917075,-15.818644,-16.94831 +27,10.109049,-52.57993,-17.273098,16.271965,5.4687433 +28,-69.96817,-38.20271,2.2926886,16.322643,7.5078583 +29,81.06858,-18.070671,-21.947964,-11.531273,-4.727164 +30,-127.52849,-22.319025,26.588818,11.453212,-10.022869 +31,86.32892,14.281502,-26.877743,-16.45838,-3.1616073 +32,-59.316814,-42.31978,-1.4612925,17.804995,9.688741 +33,-62.24086,19.135803,-6.276368,-17.731354,11.991939 +34,-114.08182,-22.76807,20.22537,10.528665,-5.3027134 +35,-41.641106,-46.728542,-7.853092,18.790068,13.031187 +36,-41.72467,-42.90344,-8.724343,15.958032,14.512591 +37,-41.426243,-41.33245,-9.12675,14.910947,14.82199 +38,-147.74948,-18.071218,35.55771,11.218884,-17.442678 +39,-85.83973,-34.172672,8.870422,15.266063,3.0867758 +40,127.91822,-43.387447,2.9494078,-2.1802256,-21.762445 +41,-89.824715,12.70726,5.581456,-13.418853,3.5357866 +42,-110.59496,-23.413805,18.68301,10.260593,-3.5486164 +43,-48.838394,-24.581514,-8.964049,4.482096,15.497544 +44,-69.10557,-39.05586,2.1023355,16.87421,7.48181 +45,-116.39467,-13.479867,19.85479,3.8038077,-3.8231885 +46,11.616741,-53.26562,-18.169538,16.432878,6.8424864 +47,-72.31468,-7.0096626,-1.0288422,-4.5829077,11.336217 +48,-64.50858,-40.44819,0.32841676,17.262587,8.769249 +49,61.934357,-66.513145,-15.20125,16.970856,-6.2158113 +50,109.40211,-74.139984,2.654201,17.306427,-24.651716 +51,-100.21555,-7.4684668,11.544071,-1.3553206,1.2752632 +52,-128.45143,-18.00711,26.315178,9.17662,-10.66016 +53,-23.407825,-44.21305,-14.694656,14.04395,18.237654 +54,-118.084045,-26.108654,22.844912,12.779296,-6.8091154 +55,-53.8357,57.226128,-10.205463,-26.284866,7.7337494 +56,33.5947,-70.26508,-13.199513,25.05716,-5.669179 +57,24.930677,-38.67059,-23.166418,5.007813,8.482612 +58,12.858014,-55.22566,-19.020922,17.773397,7.501471 +59,-7.048228,-50.410107,-18.237303,17.140932,16.361744 +60,19.942385,-44.556007,-22.569618,9.006561,10.342399 +61,1.5674375,-19.01128,-24.632353,-2.706505,15.800999 +62,92.437,-40.77637,-10.809687,-3.558833,-13.16019 +63,-57.317406,-41.769703,-2.4677293,17.249105,10.348957 +64,-45.636616,14.602271,-13.439092,-15.603674,14.725689 +65,70.0745,-30.859491,-20.28784,-3.546116,-5.5012794 +66,-58.566025,-16.825222,-5.6954436,1.0110317,12.895332 +67,-68.84848,-17.85647,-1.3386023,2.8191087,9.652063 +68,20.545067,-56.49272,-19.349669,17.244492,6.245423 +69,-132.3181,-18.9261,28.225231,9.46468,-10.6592865 +70,-18.871387,-47.037834,-15.389425,15.405947,18.013067 +71,-27.536936,-18.428848,-17.575064,0.16635387,16.831244 +72,-76.18478,-29.713144,3.5350878,11.239379,7.112828 +73,-30.169186,-19.155466,-16.431196,-0.98373586,20.122631 +74,-39.798477,-44.93966,-9.05347,17.164114,14.327317 +75,-32.574093,-48.217224,-10.7647705,18.419035,14.838685 +76,-87.701164,25.408638,4.31085,-19.082869,4.0799403 +77,-82.81878,-28.183186,6.505087,11.608581,3.8587794 +78,171.65718,17.637318,19.916239,-15.231806,-19.985271 +79,-85.396645,9.519536,4.0392094,-12.792381,6.547911 +80,65.901665,-60.04565,-16.98935,11.751296,-4.0617313 +81,84.61383,-37.418846,-14.317427,-4.01617,-10.007229 +82,-137.08533,-23.517422,31.459187,14.433647,-15.541632 +83,-16.403635,-39.297604,-17.460564,9.61856,19.167421 +84,-3.8419619,7.9106436,-26.736395,-14.262069,20.408318 +85,40.42985,186.43605,-31.88861,103.65757,4.2278543 +86,-149.95348,-11.801708,35.312496,6.535219,-15.797296 +87,-52.47716,-30.574984,-6.5488067,8.308851,14.494774 +88,-145.13187,-14.035937,33.405106,8.159434,-15.367022 +89,11.4710045,-57.476818,-20.555592,19.942812,11.487437 +90,50.80286,-59.87582,-17.928236,14.370442,-1.3888019 +91,-129.30641,-21.65674,27.297808,11.231703,-10.585757 +92,-121.48398,-23.849049,23.985392,11.930705,-8.175295 +93,-91.5029,-32.154633,11.098503,14.557516,1.4421839 +94,81.40262,-12.163089,-25.14199,-12.904362,-1.9583837 +95,67.39255,-49.78368,-19.239052,7.896446,-5.209251 +96,10.545011,-51.380844,-17.916588,15.3065,6.494532 +97,40.915745,-9.803892,-29.234339,-11.3097105,10.577294 +98,25.971027,27.61835,-32.873543,-19.754694,17.664745 +99,-125.834366,-6.6307974,23.199553,-0.10928125,-6.416948 +100,-101.164604,-34.05666,16.417183,17.991114,-4.9562545 +101,-34.199215,-48.27416,-10.4432745,19.04002,14.083276 +102,-26.124292,-50.473747,-12.414502,19.184673,15.303929 +103,50.107697,-63.19434,-17.472261,17.433168,-2.652696 +104,-120.1774,-20.122335,22.648525,8.661842,-5.9066124 +105,-76.27804,-16.016512,1.732963,2.2284229,7.812358 +106,-102.512085,-28.588068,15.885244,13.409744,-2.6422663 +107,29.81037,38.147514,-31.696875,-17.011463,11.299398 +108,-66.307045,-27.3708,-1.0627725,8.824517,9.1595335 +109,96.92208,-46.34496,-7.324575,1.5152504,-18.434252 +110,47.731316,-56.17635,-18.676788,12.237668,0.016611831 +111,-24.256863,-60.49119,-10.694802,26.495201,11.48238 +112,-59.316048,-37.808872,-2.4656875,14.825247,10.605416 +113,-141.2412,-18.156193,32.364445,10.330837,-14.539268 +114,-86.861824,-30.606262,8.643126,12.729069,4.0226965 +115,50.713306,-71.60315,-14.327889,23.559423,-7.3768888 +116,-162.51027,-11.693123,41.214542,8.749938,-21.666513 +117,1.8843576,-49.775547,-19.822786,15.115195,14.14197 +118,-0.6947519,-45.537754,-20.56943,13.687823,15.265239 +119,-42.8961,12.990976,-13.957329,-15.02992,15.002225 +120,38.545082,-1.3573451,-27.880737,-12.734481,6.185585 +121,-119.566025,-23.24896,22.999146,10.488713,-5.967835 +122,8.666648,7.311025,-28.803782,-14.432777,16.689205 +123,154.7514,-44.461563,25.670607,-4.637261,-24.734625 +124,-131.65292,-23.60438,28.855036,15.235171,-15.384636 +125,-83.9608,5.8841352,3.0499907,-8.8144,3.8550289 +126,-97.948204,-3.768226,10.088719,-3.9241688,2.3048563 +127,-4.6302686,-38.50809,-20.664352,9.559865,14.618188 +128,26.722519,-53.03399,-21.334082,13.496333,8.13681 +129,-71.764725,-37.401897,2.9603136,16.057785,7.0253487 +130,-118.99849,-24.078869,22.947268,12.6534815,-8.732059 +131,-16.399231,-48.092747,-15.910214,16.279766,16.94577 +132,-92.33766,-29.787851,11.012927,12.8931055,1.9647925 +133,-93.20178,-18.775057,9.933943,5.022565,3.1024125 +134,34.58448,-46.154686,-21.745237,8.489253,5.0280876 +135,45.693348,-40.17023,-21.497858,3.6336265,0.77833223 +136,12.519382,-42.487442,-22.574549,11.397868,9.616407 +137,-100.59547,-11.036082,12.076401,1.5426675,0.5530361 +138,120.03914,-39.869167,-2.7830026,-3.2312288,-19.935673 +139,18.466246,-20.729626,-29.089754,-3.9624436,20.07964 +140,13.3972645,-51.329002,-22.72725,15.354513,13.76543 +141,-75.68126,-27.055468,3.0170534,9.852437,6.6796794 +142,95.01758,-42.39398,-10.966164,1.4959514,-15.567142 +143,-5.2853894,-52.36346,-18.296122,18.71653,15.383939 +144,69.976906,-50.29458,-19.044123,7.082041,-5.029909 +145,79.544975,-29.510101,-21.51997,-6.4297338,-3.6388638 +146,16.027203,-56.09282,-21.80444,18.180975,12.192752 +147,-90.365486,-32.563877,10.776074,15.614808,0.08377498 +148,65.77693,-47.971478,-19.604174,6.7739987,-4.601076 +149,-44.299984,-42.87462,-7.519287,17.618084,10.830269 +150,115.724495,8.661257,-14.973091,-19.0458,-13.4317045 +151,151.4258,-50.63537,23.09378,-2.0143602,-24.693811 +152,-66.83259,-40.516365,1.4683915,17.292118,8.208438 +153,158.67844,-48.812626,29.705534,-3.5564082,-23.536764 +154,-77.7969,-36.603146,5.7522144,17.2155,2.6302516 +155,-13.740532,-53.97247,-15.131945,19.413397,14.145673 +156,-99.88695,-30.714193,15.076208,14.420382,-1.5279573 +157,110.202515,-46.144833,-4.2433586,1.1358756,-20.66898 +158,-81.67826,-18.542356,4.477178,3.855157,6.817066 +159,126.16685,-31.45668,-1.4536412,-9.061997,-19.276932 +160,-136.69249,-27.315754,32.0566,16.905397,-16.332418 +161,38.35172,-18.346127,-27.369907,-7.8634744,9.558626 +162,-25.153673,-50.82832,-12.991785,19.282934,15.782728 +163,84.32486,-48.264305,-9.487816,3.4347734,-15.518889 +164,94.051834,-28.962664,-13.456854,-9.568724,-11.289016 +165,-72.27521,-40.045914,3.8179789,18.828947,4.198386 +166,116.94894,-42.32331,-2.6169271,-0.43690675,-21.7156 +167,-115.60411,-31.56377,22.710196,18.075645,-9.778044 +168,-1.3148307,-51.511528,-19.230484,18.115946,12.551799 +169,-0.3139532,-52.100956,-19.882236,17.621483,16.614557 +170,50.415916,-60.71781,-18.46006,15.317222,-0.9314246 +171,-103.42872,-28.508183,16.30444,15.74899,-6.3758206 +172,-42.883995,-39.688755,-9.084898,14.114226,15.295512 +173,113.943855,-74.68089,5.484126,17.727983,-25.672426 +174,-13.467423,-52.649384,-15.431053,18.424883,14.5910015 +175,22.831385,-30.731468,-25.264557,0.80617815,11.538698 +176,-46.612476,-44.364605,-6.323837,18.727304,10.423859 +177,53.380165,-60.520763,-18.232265,14.5215435,-1.6052628 +178,-45.67165,-45.472355,-6.6904345,18.518404,12.780436 +179,115.1885,-45.35301,-3.295134,0.35425755,-20.554398 +180,-4.044443,-51.122448,-17.865644,16.782778,13.021171 +181,-1.8848984,-47.960777,-19.144455,14.231348,14.440916 +182,-40.314995,-40.38375,-9.769738,13.786746,16.284863 +183,-44.209557,-15.860265,-11.509519,-0.8632275,16.00171 +184,103.43885,-32.46338,-11.028724,-6.4204307,-14.3527565 +185,-72.7158,-34.349434,2.6726725,14.4374275,6.9179845 +186,-78.31557,-32.83102,5.1200724,13.978497,4.7787237 +187,-119.09223,-30.966427,24.303822,17.967833,-11.018586 +188,-15.855132,-50.92878,-15.213165,17.822191,16.234972 +189,-147.67535,-20.208374,35.807888,14.749311,-20.408636 +190,10.714846,-53.941483,-19.219906,17.44491,8.676195 +191,-150.19104,-23.799505,37.817745,16.009874,-20.563099 +192,101.869705,-37.835896,-11.7876625,-5.239225,-12.580386 +193,-86.608246,-35.193703,9.508227,17.616245,-0.3981618 +194,-17.687387,-51.3958,-15.252701,18.873678,16.223583 +195,3.1108298,-45.559612,-21.080738,14.161183,12.29075 +196,163.00624,-8.217234,17.744352,-16.152409,-20.44894 +197,103.33145,-43.23339,-6.532275,0.52708155,-19.478085 +198,-84.80023,-34.76589,8.505635,15.720996,3.0684066 +199,-29.084902,-50.32156,-11.733721,19.502508,15.131744 +200,-133.94284,-21.487143,29.483826,14.284384,-16.088434 +201,137.67754,-45.28281,12.021383,-2.0038822,-25.627977 +202,40.330048,-59.788067,-18.251934,16.061062,0.56643903 +203,-56.34914,-41.950867,-2.6759152,18.353813,8.087147 +204,-12.980664,-41.565964,-18.941458,14.947125,14.002392 +205,117.2505,-26.649937,-7.629713,-10.577968,-16.390417 +206,53.631905,-17.474058,-26.104128,-9.604272,3.9269376 +207,30.447533,-57.315224,-19.695684,16.560104,4.5015936 +208,34.39382,-58.102345,-20.05735,16.523186,4.0266924 +209,21.92587,16.433996,-32.247353,-18.783432,18.502493 +210,-83.20697,-16.984001,4.785634,3.7034438,5.602321 +211,-55.292164,-41.253708,-3.4434304,16.596413,10.793511 +212,106.77156,-44.762928,-5.5074244,0.23091751,-19.790213 +213,137.96234,-46.277103,14.495386,-2.1584146,-26.83541 +214,-99.88123,-34.66513,15.954976,18.230993,-4.6761804 +215,43.87207,-60.5187,-17.000753,15.69133,-1.3220652 +216,-79.150536,-35.771473,6.0552425,16.086771,3.7983754 +217,-14.549933,-45.713078,-17.316856,16.691729,13.61358 +218,123.325195,-45.871437,2.6207569,-0.15346432,-23.446384 +219,-78.47748,-39.639206,6.56781,19.274319,2.1305952 +220,31.23609,-57.629005,-17.024645,15.956029,0.46569213 +221,70.30967,-70.92554,-13.695634,19.515997,-9.217529 +222,-96.789665,-28.927223,13.350016,11.529939,1.8091334 +223,-65.46594,-28.036133,-1.4267848,8.346976,10.805381 +224,11.579195,-47.47468,-20.591845,13.830967,8.046928 +225,-98.367325,-5.288355,10.458312,-2.9741566,2.0055203 +226,1.3483045,-44.61144,-21.110725,12.824201,14.107463 +227,72.864395,-40.917168,-20.938442,0.9799968,-3.5468476 +228,-60.218086,15.208508,-6.85209,-15.884501,12.263871 +229,-5.9167423,10.863001,-26.677113,-14.980111,20.18708 +230,22.862764,-56.861435,-19.670883,17.022581,6.346064 +231,-39.174595,-27.475403,-12.154974,5.989115,15.468838 +232,117.756424,-40.94416,-3.3428066,-2.1979952,-20.179482 +233,6.874128,-42.966488,-20.016531,8.975698,11.056791 +234,-36.285637,-51.99279,-8.885864,21.979382,12.6493025 +235,14.657546,-21.630686,-28.40782,-3.0032787,19.979652 +236,130.8048,-18.410149,-3.6174054,-15.85212,-16.289202 +237,-63.243626,-29.457485,-2.2485423,10.231526,9.893664 +238,82.66651,-72.41919,-6.048431,18.70475,-17.52364 +239,83.56097,-52.334164,-9.516489,6.232793,-15.360418 +240,48.076332,-70.072655,-15.085526,22.528282,-5.476702 +241,41.84404,-58.89497,-18.53257,15.104967,0.9220527 +242,-115.43984,-32.80459,22.872671,17.74336,-8.390771 +243,44.098587,-47.104496,-19.483292,8.029836,-0.9356162 +244,-120.72947,-42.10687,27.274042,25.298492,-13.124422 +245,-23.693398,-66.52571,-9.445429,30.7589,9.803693 +246,113.58907,-49.101547,-2.8639815,2.6683686,-21.196283 +247,11.362067,-62.356445,-16.601221,23.516321,3.9122863 +248,41.5805,9.138099,-32.04949,-16.966047,12.104 +249,9.121838,-51.03793,-19.662905,16.272476,8.360454 +250,-88.13558,-32.359467,9.666225,15.601148,0.0649196 +251,64.33471,-50.224556,-19.037533,7.951458,-4.864857 +252,105.14806,-18.5805,-14.25708,-13.2118845,-12.168887 +253,-80.24684,-32.646664,5.9619765,13.741249,4.945604 +254,120.9619,-52.44257,-0.096896544,2.3129914,-20.269836 +255,16.47736,-62.82785,-16.406527,22.661737,2.5184207 +256,160.09903,-47.3981,29.204117,-3.4499753,-21.534958 +257,-115.34161,-9.353112,18.724709,1.4466356,-4.025336 +258,27.245037,-32.657368,-23.813705,1.7486546,7.8214636 +259,35.497288,37.21853,-33.42017,-18.598417,12.85598 +260,-8.137266,-64.70904,-13.880104,28.6891,6.9229164 +261,-76.24556,-50.62609,7.6706734,26.868328,0.029818194 +262,97.69661,-79.380615,-0.8191617,22.318007,-22.597094 +263,11.453296,-55.83679,-17.59953,18.476023,5.8813157 +264,-24.904917,-44.17519,-14.422832,14.701363,17.238491 +265,119.5505,-47.429916,-0.8836552,0.43399653,-21.1835 +266,5.1077414,-51.015327,-20.896482,16.812319,13.61006 +267,-55.502186,-10.904898,-7.461197,-3.3489125,14.546986 +268,-133.50475,-23.417324,29.72923,13.462711,-13.338908 +269,-0.97845966,-38.765423,-21.692818,10.255111,15.926018 +270,84.653656,-50.302227,-9.606309,4.1834064,-14.922522 +271,-78.6333,-35.690044,5.812044,15.657653,4.972209 +272,97.00954,-20.497276,-14.794526,-13.195119,-11.242641 +273,-121.69587,-24.360039,24.18863,12.05813,-8.061379 +274,-118.438324,-29.536852,23.690119,15.372538,-8.367031 +275,123.783936,14.433356,-12.539154,-17.002672,-15.612396 +276,-114.999405,-5.4223356,17.909145,-1.279934,-2.6662166 +277,-27.563421,14.527964,-19.91834,-15.765279,17.656368 +278,42.475475,-65.83766,-15.001957,19.970469,-4.285101 +279,-102.654335,-39.982117,18.185062,22.165318,-6.502307 +280,21.092257,-70.410286,-16.163696,27.640574,0.9799809 +281,-105.8848,-42.397274,20.18031,24.464344,-8.724568 +282,-19.940218,-47.801716,-14.855016,16.032202,17.745779 +283,-1.6480218,-51.961353,-18.681532,17.385866,13.529945 +284,-158.90785,-12.892909,39.74469,9.164094,-20.646751 +285,-63.335796,-47.415062,1.2284248,22.642853,5.9019685 +286,-39.105186,-59.46919,-6.29309,28.643463,8.256931 +287,-74.46041,-37.147915,4.084248,16.257486,6.012193 +288,121.26959,-79.64291,12.131602,19.59943,-28.858166 +289,-53.77712,2.8293228,-8.982382,-10.808353,14.664527 +290,-99.05742,-25.903488,13.72041,10.840408,0.26339984 +291,-125.87912,-16.718426,24.728666,6.835491,-7.1790843 +292,-91.23911,-6.9841766,7.3037863,-2.4072933,4.5467987 +293,-117.19111,-26.768631,22.534702,13.141233,-6.355987 +294,-74.25597,-43.862476,5.3200316,21.197435,4.16045 +295,85.10489,-71.13643,-4.5432253,17.711891,-19.002264 +296,-3.6784341,-52.070946,-18.87399,18.233732,15.945411 +297,-69.809074,-52.543186,5.1391106,27.58656,1.3567933 +298,-25.361696,-43.340134,-14.2929535,13.8843975,17.95616 +299,-66.95207,-52.540936,3.8626714,26.82838,3.5952995 +300,-31.006826,-50.668167,-10.527721,21.226763,11.232362 +301,-91.01434,-48.300804,14.08427,26.729256,-3.8480902 +302,-147.17058,-29.011145,37.391644,18.769543,-19.78599 +303,-116.386925,-41.19626,25.003073,24.335722,-11.732715 +304,79.86598,-69.145615,-9.303186,16.38259,-13.249297 +305,15.812526,-34.222237,-21.964884,3.916144,8.369968 +306,14.580833,-55.637733,-19.407782,17.89621,7.511039 +307,22.881983,-35.49611,-23.464605,3.8017163,8.879476 +308,-14.530633,-53.169876,-15.336341,19.391403,16.080893 +309,-89.83681,-17.900843,8.32498,4.5850973,3.7011456 +310,81.03625,-38.115192,-13.029197,-2.9790986,-11.257647 +311,-120.44326,-25.891098,23.912981,12.98739,-7.8942337 +312,-55.121197,-51.89814,-1.3376962,24.691118,6.995011 +313,-49.326984,-24.197615,-8.612487,4.5623574,14.950862 +314,122.621475,-34.65491,-4.630865,-7.0601735,-16.825447 +315,-45.749702,-36.151497,-8.120456,12.678605,12.763664 +316,118.81338,-45.559555,-1.4987061,0.43799436,-21.481781 +317,-70.8182,-36.27172,2.4365447,15.95749,5.684383 +318,30.625526,-44.921185,-22.147858,8.2106085,6.44598 +319,-43.852882,-23.717426,-10.729347,2.8938155,16.697765 +320,81.40909,-66.25066,-6.6321497,14.352645,-16.163755 +321,23.603405,-39.089214,-22.92748,5.61461,8.625971 +322,-130.81903,-24.327023,28.62564,14.073141,-12.9479065 +323,36.43635,-58.710484,-17.523375,15.954645,0.3428751 +324,-48.62877,-33.842052,-7.41946,11.259429,12.753383 +325,-26.893717,-16.29982,-17.93713,-1.1677022,16.989555 +326,-59.98698,-34.833126,-2.7723887,12.716114,11.399323 +327,70.1263,-76.343285,-11.827247,23.890486,-12.249216 +328,-158.19145,-30.274546,42.958633,21.445692,-25.29753 +329,97.30086,-38.963146,-12.057099,-5.354062,-11.458868 +330,-15.817738,-46.29153,-16.75161,15.609352,16.495201 +331,4.0050893,-20.242216,-26.080462,-2.4731708,20.387081 +332,-40.677128,-47.19421,-8.188867,18.928947,13.696602 +333,-76.658035,-37.433674,5.2098904,16.539442,5.084884 +334,88.51726,-55.901875,-9.585809,7.4650064,-14.55889 +335,-57.406292,-42.625706,-2.2823734,17.937952,10.097515 +336,191.71732,-9.274495,46.707954,-16.005865,-7.1158757 +337,54.277714,-69.84387,-15.934144,21.476345,-5.3881736 +338,-60.4224,-52.809258,1.0847034,26.006853,5.807427 +339,-132.52399,-33.00704,31.150488,19.64399,-14.842231 +340,-23.08058,-59.880615,-11.480604,25.912706,12.516091 +341,-110.63367,-36.569633,21.259056,20.335398,-7.7545676 +342,-114.54056,-40.900654,24.037851,23.903883,-10.928429 +343,94.778885,-47.32439,-8.617411,3.3255405,-17.465416 +344,-152.94945,-28.400335,39.988453,20.309908,-23.85745 +345,47.467274,-71.44832,-16.022228,24.151169,-4.4937367 +346,-112.6783,-25.817795,20.158855,12.308969,-4.881458 +347,-44.864777,-30.94416,-9.397789,9.288353,13.356931 +348,-16.310532,-39.36678,-17.521374,9.701226,19.035715 +349,-113.202156,-18.743345,19.02898,7.2200475,-3.2741373 +350,-95.73657,-35.249092,13.984187,17.768509,-2.1848168 +351,100.43011,-43.2611,-8.511417,0.3790772,-17.450378 +352,20.655487,188.47002,-27.363287,96.975685,0.1747824 +353,3.985092,9.509571,-28.426523,-14.767774,17.913055 +354,-25.597498,16.199839,-20.64726,-16.331562,17.622965 +355,-139.79211,-19.841822,32.04248,10.863834,-13.772007 +356,-81.87471,-18.040665,4.4253945,3.8877404,6.3059874 +357,-130.94847,-25.071245,28.856977,13.977322,-12.548442 +358,30.61778,-55.873383,-19.589808,16.147902,2.664683 +359,-24.82587,-56.641476,-11.561719,23.523592,13.761672 +360,-91.41774,-46.384586,13.891793,25.589708,-4.0423803 +361,-145.83083,-32.55663,37.46019,21.393793,-20.748981 +362,-4.6018047,-67.16437,-15.083141,29.431166,10.305197 +363,-153.95619,-29.84643,40.80573,20.588934,-23.335928 +364,37.43142,-75.59636,-13.498766,28.023527,-5.678095 +365,-150.14436,-31.361767,39.298878,21.308155,-22.570133 +366,-133.1629,-19.672756,28.78725,10.439151,-11.888666 +367,81.40262,-12.163089,-25.14199,-12.904362,-1.9583837 +368,-94.01571,-48.038,15.470424,26.902937,-5.132976 +369,-89.742905,-37.000866,11.305122,19.023682,-1.4737287 +370,64.82559,-66.83539,-16.562334,17.50578,-5.247723 +371,-102.29109,-29.158255,15.861733,13.785316,-2.4145408 +372,-132.10971,-29.376493,30.198387,17.180332,-14.148494 +373,82.23096,-11.764843,-25.263565,-12.43286,-1.9134772 +374,13.221844,19.44144,-31.196934,-19.139862,18.988802 +375,-16.981955,-51.73149,-15.000642,18.620623,16.609974 +376,-123.699974,-0.7581562,21.371067,-3.3508697,-5.9418807 +377,128.56546,-44.094543,4.363113,-1.7477882,-23.059526 +378,-150.61899,-25.759796,38.407192,16.904232,-20.387333 +379,139.91013,-49.00478,16.27911,-0.2524453,-27.564941 +380,-34.770195,-56.32042,-8.039467,24.991856,11.090059 +381,-91.35678,-42.971233,13.133724,23.313192,-3.2149734 +382,48.178963,-62.8233,-17.555834,17.519972,-2.2716064 +383,-126.72053,-23.31853,26.468777,12.532486,-10.680002 +384,-76.27804,-16.016512,1.732963,2.2284229,7.812358 +385,74.442345,-42.564186,-20.105814,-0.42026243,-2.7763486 +386,-9.283722,-48.951897,-16.873,18.148247,9.466108 +387,-90.52783,-31.15738,10.447809,13.816715,2.0106587 +388,108.69388,-49.741108,-3.9201105,0.96970385,-19.566492 +389,-106.607445,-32.403275,18.526966,16.531427,-4.3593206 +390,47.579544,-51.56949,-20.04147,9.798527,0.25543985 +391,-23.571955,-61.141247,-10.749677,26.690418,11.885191 +392,15.541813,-56.226154,-18.590927,18.341017,6.114502 +393,-166.64133,-23.442919,45.601707,17.970663,-27.35122 +394,-5.039601,-58.610615,-15.834607,22.740171,10.048866 +395,-137.65527,-18.479797,30.721529,10.117747,-13.3759 +396,-78.38162,-42.80671,7.15387,20.909847,2.8168297 +397,29.217073,-71.88743,-16.765879,27.811468,-0.014702564 +398,82.44256,-45.868656,-13.564361,0.6741639,-9.76719 +399,25.902637,-71.71376,-15.491343,28.09611,-1.435544 +400,42.05059,-37.614708,-21.38298,2.0347042,1.8717234 +401,-103.60368,-27.348028,16.1345,12.497258,-2.3237083 +402,-1.9143215,-17.20288,-24.849035,-3.4455729,19.873102 +403,-28.265726,-0.39066783,-18.918148,-10.394312,18.78527 +404,-100.82085,-27.77052,15.000437,11.200091,0.5196779 +405,-127.148026,-26.549591,27.340834,14.610254,-11.478924 +406,-40.71716,-43.78208,-8.925198,16.543903,14.71335 +407,-122.65176,-21.96399,24.217793,10.073645,-7.2406325 +408,107.97079,-16.464508,-12.204826,-13.672614,-14.203054 +409,-151.63521,-13.564147,36.52992,8.5219555,-18.013449 +410,-46.97564,-30.29216,-8.601175,8.623742,13.8784685 +411,26.999025,-37.305523,-22.604248,4.8113165,6.1402698 +412,24.834463,4.453355,-28.807882,-15.230986,11.939392 +413,154.08434,-44.31309,25.61127,-4.6777143,-24.983038 +414,53.670307,-60.385975,-17.820976,14.646779,-2.4564862 +415,-104.605095,-32.67897,17.699415,17.817698,-6.4271 +416,86.268486,-44.469006,-12.25526,0.4189561,-12.3751745 +417,-64.21151,-27.207197,-2.027164,7.5987954,11.078102 +418,-65.16356,-12.023229,-3.682114,-1.9327358,12.015002 +419,16.463568,-60.10614,-17.705656,20.738592,4.6763515 +420,-31.616234,-51.375538,-10.278495,20.59099,13.9972515 +421,-3.128926,-48.098454,-18.961739,15.535357,13.558242 +422,50.17689,-73.62072,-13.997759,25.101042,-7.811338 +423,-111.238914,-41.512295,22.532946,24.412674,-10.336849 +424,27.724373,-73.39679,-16.558868,29.082191,-0.3137832 +425,-59.823654,-57.835857,1.865032,29.841883,4.0855255 +426,13.756931,-31.508902,-24.4771,3.643256,11.52803 +427,61.00178,-61.545334,-18.102192,14.067575,-2.624425 +428,39.647537,-74.26244,-13.981811,27.200623,-5.9631176 +429,-36.008545,-57.764877,-7.7794085,26.485971,10.395256 +430,254.57945,27.87424,158.7995,-13.484289,124.63127 +431,-163.32674,34.511574,36.293633,-21.078886,-17.271442 +432,44.35487,-73.724724,-13.733895,25.815687,-6.9364343 +433,-84.47162,-25.86101,6.844732,12.570757,-0.20372677 +434,-155.60101,-0.94561267,36.35202,-0.25189584,-16.985306 +435,158.55008,-78.26112,44.08894,14.721903,-28.181967 +436,-85.43959,34.458897,2.1847036,-22.612164,3.4776423 +437,93.458084,-3.2435317,-17.154112,-17.010365,-10.917879 +438,64.953026,165.86623,-36.5511,94.287384,-4.163952 +439,-75.90327,122.241615,0.49186197,-2.638532,-12.703874 +440,164.12544,1.0040642,21.612474,-18.619465,-23.116747 +441,-130.71864,43.36337,21.751925,-25.64635,-8.985769 +442,-93.972145,-31.363436,12.527955,13.104925,2.0899048 +443,113.3121,52.530033,-20.322195,-10.238228,-11.509297 +444,-38.713207,170.0642,-11.980673,51.491173,-12.4422655 +445,-125.02192,-17.872576,24.517834,7.724458,-7.5163007 +446,-90.9159,10.689725,5.7338805,-11.454109,2.2564626 +447,132.47932,1.4455106,-2.9821584,-20.421219,-19.317108 +448,16.544237,-50.680458,-19.125284,13.713782,6.819161 +449,-108.52367,-11.785519,15.924046,1.9408374,-0.1934907 +450,-158.5656,-25.332527,42.08282,18.608528,-25.096342 +451,-81.24674,-43.35927,8.636628,21.627111,1.4060841 +452,-74.70418,1.8287479,-0.7468531,-7.0328927,6.222037 +453,165.9778,-46.863697,32.017323,-6.857191,-16.113491 +454,261.47516,111.69399,134.73747,67.97616,84.290474 +455,-29.219994,168.60995,-19.110376,64.32828,-11.17886 +456,139.12466,-37.11262,8.820932,-6.613247,-22.782564 +457,-136.40656,70.34389,23.43089,-34.662216,-10.594705 +458,-141.98553,-22.543182,33.615067,14.045408,-16.933372 +459,119.883385,16.404207,-15.6846485,-15.069096,-13.798363 +460,193.0008,-25.384972,56.414387,-12.741569,-5.295456 +461,50.015717,-29.098383,-23.861513,-3.4237564,2.2981708 +462,102.726654,-58.482323,-5.543145,6.0126014,-15.227922 +463,90.34774,-49.931355,-8.914793,3.7518883,-16.187128 +464,-150.36285,51.274296,29.50701,-27.522257,-16.799164 +465,-63.850643,23.612263,-6.2734513,-18.205978,8.70645 +466,228.39027,139.54626,44.175858,95.476425,-8.335445 +467,161.78494,23.840645,13.943015,-18.796524,-22.11435 +468,-108.5571,-21.381851,17.73902,7.9793715,-2.683368 +469,142.92055,18.795734,1.8286108,-22.179579,-21.351126 +470,-127.36929,-20.889206,26.295818,13.110752,-13.773722 +471,-37.008343,-38.713142,-11.033165,13.5304985,13.433011 +472,111.18742,26.133087,-16.637995,-19.539469,-13.411144 +473,136.53484,-5.342414,-7.289644,-15.424169,-14.553354 +474,-43.796852,30.581207,-13.554597,-22.432234,16.33331 +475,-23.828047,34.47709,-21.719982,-22.75526,18.316713 +476,-133.68683,54.422745,23.329494,-29.604237,-10.695615 +477,-39.34543,20.386164,-15.778257,-17.556374,14.426242 +478,159.55962,22.129608,10.320665,-17.045315,-21.369991 +479,-6.9271517,10.901806,-26.819546,-15.728645,22.066628 +480,-105.75243,34.35198,11.204042,-21.692816,-3.272966 +481,155.42427,-46.29137,28.838602,-4.6039243,-26.021181 +482,-122.200264,-21.994251,24.042606,9.65979,-6.435883 +483,-61.957573,46.18161,-7.811855,-25.751965,9.161675 +484,-96.66963,153.46146,8.257398,16.454401,-25.85003 +485,-85.839905,52.75471,2.6139379,-29.002836,4.268886 +486,35.31302,37.85202,-29.932814,-17.483921,6.252102 +487,121.39056,56.125114,-16.194036,-8.072378,-14.317575 +488,64.19004,-27.791615,-24.408148,-5.5424747,0.43246266 +489,-59.178772,23.782421,-8.025943,-20.150974,13.682155 +490,126.595055,-75.05654,17.06281,18.004988,-32.312893 +491,-147.34845,35.186443,29.179407,-21.936075,-12.954721 +492,-66.50815,-36.73846,0.4244219,14.852039,9.510039 +493,70.173515,-33.1099,-22.528597,-3.9003203,-1.418837 +494,-69.50637,47.8895,-4.1281366,-27.400497,9.791037 +495,-145.86609,48.957417,27.690807,-26.99163,-14.931865 +496,-122.45362,2.116064,20.462643,-3.874942,-7.4554553 +497,167.05101,21.365446,16.391565,-21.421967,-20.579502 +498,238.55753,16.828932,118.22314,-10.655365,68.75171 +499,-128.37209,-38.127583,30.171911,23.242315,-15.489699 +500,5.790385,7.5702233,-28.434067,-14.720953,17.433777 +501,42.51964,-3.5816734,-26.726633,-13.984368,5.159768 +502,179.43082,-12.263913,39.51616,-16.355034,-18.635624 +503,161.68202,22.687994,15.446396,-15.88277,-23.069283 +504,-119.599,15.6383295,18.573576,-15.104696,-2.4480293 +505,-101.70464,95.251495,8.37584,-30.471455,-8.886446 +506,-68.18554,44.197697,-4.2909,-26.794403,9.979203 +507,-82.65439,46.9121,0.8054822,-26.408855,2.7000365 +508,-56.812008,21.893608,-9.049164,-17.865808,10.727315 +509,63.77304,-68.26419,-15.988677,18.497267,-5.8877125 +510,23.535667,-14.8451185,-30.078121,-7.9061823,17.874935 +511,228.69669,11.7546835,107.94964,-11.067943,44.929737 +512,35.89693,26.955482,-32.95444,-20.226286,14.817965 +513,200.59622,21.180729,51.51241,-14.049451,-7.969521 +514,144.25806,-8.106282,7.048874,-16.242075,-23.178377 +515,69.74684,-64.11186,-15.592915,13.855884,-5.885688 +516,45.400795,31.622698,-33.016556,-20.361818,10.655458 +517,-55.350616,55.106743,-9.600613,-26.729658,8.867067 +518,-132.27544,-11.790121,26.87291,7.1491323,-12.606457 +519,6.3124733,161.90231,-30.884735,72.79964,-4.076774 +520,56.031677,-23.61662,-23.49867,-6.454914,-0.08507461 +521,-39.7325,21.441235,-15.913876,-18.004036,14.542898 +522,59.877552,151.3117,-31.818094,64.16332,-0.04708687 +523,193.49553,151.96837,16.271183,107.83435,-24.923796 +524,-114.21912,-7.384719,17.835135,2.092733,-6.2729273 +525,-4.1701107,-33.057278,-22.566513,6.8431816,17.854362 +526,-91.255684,-25.323843,10.191587,10.267875,2.0584862 +527,-53.781162,-19.003838,-7.526164,0.4944633,15.619218 +528,50.821056,8.358707,-25.938095,-19.214323,2.1934836 +529,226.29323,-20.274708,115.95107,-14.585937,60.113953 +530,-89.16833,31.08995,4.4868655,-20.779106,0.85199887 +531,-176.58986,-9.77961,47.589775,9.086192,-26.36611 +532,-113.839645,-11.138517,18.23108,2.9823127,-4.0366173 +533,-98.77024,-24.647585,13.47128,12.255221,-3.5972002 +534,85.9553,170.17244,-36.517082,108.35235,-4.5543118 +535,-142.58534,48.347538,26.057474,-26.42647,-14.50916 +536,47.615692,-9.87489,-25.727081,-13.187949,4.6014066 +537,-100.34,31.999773,9.394593,-21.745527,-0.27386928 +538,-133.09026,-3.440566,25.953049,1.1849418,-11.568391 +539,1.9618467,11.284597,-28.390287,-15.238178,20.240715 +540,88.96382,-35.33484,-15.340098,-6.4403877,-8.472133 +541,98.87515,89.98653,-30.939032,22.91662,-6.5909634 +542,102.65755,35.430134,-24.017944,-14.479815,-7.025517 +543,-123.129166,40.48038,19.462486,-25.345417,-5.7179956 +544,-48.460846,-30.518583,-7.9597282,9.258971,12.7183075 +545,226.4897,-22.7567,121.53231,-12.075792,58.49648 +546,139.68024,-42.756336,14.019872,-3.5825577,-26.209518 +547,-144.07907,31.119917,27.88517,-18.983517,-13.665677 +548,33.570137,-34.831905,-19.396942,1.672003,0.3666306 +549,-47.230873,168.69754,-7.1306515,39.695023,-11.841519 +550,-97.76823,75.826485,7.557879,-32.122066,-5.531977 +551,-64.93202,20.08026,-5.3639674,-18.212297,12.0277605 +552,186.36574,146.98848,11.418886,90.63469,-19.528559 +553,126.91891,-34.305775,0.6984325,-7.502199,-20.491072 +554,137.83897,21.888773,-11.075222,-21.74044,-12.257843 +555,-93.433395,56.869408,5.9872994,-30.45573,2.9172654 +556,-2.1727757,-33.074078,-21.850548,6.3539524,13.49366 +557,-43.457787,68.06805,-15.409789,-22.50027,10.412262 +558,-138.71808,12.363804,26.6827,-9.019965,-11.831825 +559,28.467464,43.39102,-31.535275,-18.765776,10.998265 +560,41.28275,-20.827835,-28.634247,-7.4533033,10.954362 +561,-105.825226,45.06726,11.54981,-27.16357,-0.7715981 +562,215.75842,12.927566,80.38669,-13.331545,18.023457 +563,28.877598,-55.603455,-19.83363,14.867394,5.51493 +564,18.335253,-64.27544,-17.221886,21.663675,5.8895698 +565,118.70243,25.5475,-16.521727,-18.981167,-13.341853 +566,-125.58329,74.87791,18.053139,-33.305927,-8.797783 +567,-112.32546,65.8622,12.931713,-32.69485,-3.9887445 +568,77.954475,-30.542072,-22.27793,-3.2526147,-4.445075 +569,-125.914444,-24.535566,26.305407,15.395272,-13.8375 +570,-84.47884,29.942554,2.6379447,-21.329367,5.06663 +571,-16.337233,51.67011,-24.05321,-23.547977,16.635906 +572,66.46664,-25.511808,-21.108316,-6.878031,-4.200588 +573,35.940292,-55.498306,-23.595402,13.147405,10.509817 +574,-2.7881987,44.72833,-26.429068,-20.707838,14.02389 +575,257.8138,76.96034,142.36755,27.07244,89.77129 +576,120.53709,15.143762,-11.81009,-17.107302,-16.998295 +577,76.865005,34.640003,-29.1497,-16.028465,-0.7745205 +578,-47.173214,-32.754574,-8.127754,10.266232,13.272185 +579,-128.21375,40.96258,21.428474,-25.363735,-7.861092 +580,-93.88329,44.864403,5.5833573,-25.695543,-0.7653501 +581,-2.456459,32.959755,-28.260015,-20.323862,19.167038 +582,164.01274,-21.457195,25.296183,-14.774348,-22.197836 +583,7.7483664,140.142,-28.3944,38.311005,3.742188 +584,162.76317,33.25024,15.895384,-16.141468,-22.54697 +585,159.07278,6.8234725,16.193151,-17.498903,-24.767422 +586,-125.55847,-0.5560513,22.129183,-4.008477,-5.0855227 +587,87.23762,-29.678883,-20.652674,-6.5954413,-5.4542565 +588,17.788853,14.116103,-32.09215,-16.952784,18.374966 +589,-125.00706,-20.17545,25.159632,8.681723,-7.2545753 +590,-65.62128,-20.302279,-2.520893,3.0456018,11.803855 +591,88.4737,36.29866,-25.647427,-18.979166,-5.727147 +592,139.25937,18.018751,0.3034744,-16.229763,-22.4838 +593,25.261919,-0.58641773,-29.47246,-13.293337,13.360496 +594,1.0188935,-36.495323,-21.78626,8.828002,11.745429 +595,-98.21479,38.22201,7.569524,-23.64251,-1.032574 +596,245.46184,18.223986,147.59634,-8.217811,93.19977 +597,-115.35761,66.33615,14.501113,-32.874237,-5.276832 +598,57.29455,158.13747,-34.215096,73.551155,4.3627543 +599,190.60915,-12.140524,45.37586,-20.846106,-2.1620958 +600,54.954285,-11.040308,-24.187988,-12.571243,0.4840404 +601,-100.5733,1.478251,10.459114,-4.756951,-1.1382679 +602,-82.74209,-24.610693,6.0358896,8.584993,4.5628595 +603,-128.26547,57.61778,20.619595,-30.819946,-8.593641 +604,-89.672874,-4.7706103,6.7765684,-5.698567,7.815147 +605,171.0609,15.1699505,17.562376,-21.99366,-17.381794 +606,-34.6559,11.308428,-16.75336,-16.171955,20.82357 +607,-74.43989,48.729538,-2.3025193,-26.149048,3.4885678 +608,-119.05392,-24.552677,23.104855,13.078366,-9.087222 +609,171.97241,29.132423,15.717668,-18.703848,-18.816526 +610,123.58525,-28.309225,1.7015758,-13.412644,-20.071165 +611,-75.68376,27.435846,-1.2676528,-19.359835,5.1014733 +612,102.88732,-28.414852,-10.099849,-7.345256,-16.13042 +613,-168.66913,-6.2820024,43.181717,5.4799023,-22.408417 +614,19.239067,-64.19248,-16.267727,23.62598,1.4032383 +615,172.96051,-12.386228,33.706963,-15.646334,-22.067558 +616,26.665106,47.9224,-31.643723,-18.891676,11.81298 +617,-119.21255,-24.191511,23.276632,12.007803,-7.7779045 +618,-16.563522,36.393787,-24.336792,-23.157877,20.506962 +619,-130.46402,71.36043,20.871561,-34.769875,-9.359913 +620,105.01763,48.11949,-28.331444,-10.4577,-3.995287 +621,-46.289356,-40.619118,-7.125587,13.942311,15.185986 +622,-31.03863,3.1760097,-17.999186,-10.632522,16.031858 +623,18.351118,34.208523,-33.201508,-21.15361,21.188757 +624,-47.916008,-43.33096,-5.9084625,16.643469,13.035911 +625,-78.57557,25.30844,0.35857764,-20.08554,7.5442348 +626,240.03731,35.45288,112.46647,-10.026646,57.708706 +627,3.7645795,52.637115,-28.970945,-21.12315,15.207655 +628,-11.865991,8.507493,-24.427856,-13.547282,17.49946 +629,-91.64114,54.900852,4.4448314,-28.550959,-1.2288036 +630,-71.73389,173.6282,-0.4032386,38.73483,-20.020626 +631,-44.65785,-3.016219,-12.311722,-8.639582,16.969336 +632,-19.565386,13.631223,-22.586061,-15.4824705,17.605995 +633,-97.96822,66.810074,6.5308714,-31.584164,-2.7897248 +634,90.743355,41.7261,-28.091173,-16.349165,-2.7543602 +635,-123.81396,71.20768,17.746414,-34.213665,-7.661121 +636,-139.50114,0.39115778,28.329874,-0.6600724,-13.608758 +637,33.431057,-45.35848,-20.841864,9.421573,1.9956229 +638,99.985054,-8.150496,-14.482768,-15.242851,-13.471112 +639,180.59027,-16.971071,34.35494,-15.469729,-11.258414 +640,227.12654,129.29143,60.653458,83.54462,1.8670855 +641,-125.77381,-36.94207,28.64498,22.18934,-13.835321 +642,-155.02832,-7.4522686,37.04596,4.441665,-17.837004 +643,-81.32971,68.183395,0.63370067,-29.552162,-0.77747244 +644,106.95368,91.47376,-31.344925,24.113295,-6.93954 +645,-38.000957,15.536378,-16.152826,-16.236237,16.260529 +646,-2.0909731,-31.621746,-23.273306,7.1886077,16.829157 +647,-84.58789,27.458834,2.6889548,-20.40415,5.3896136 +648,-112.12934,35.657635,14.384888,-23.818647,-2.1658025 +649,-139.40147,-35.48232,34.93675,22.640066,-18.95679 +650,-31.755783,-50.439808,-10.461863,19.477533,13.844389 +651,5.069633,-28.868105,-23.663242,2.7701666,13.811116 +652,-112.50927,41.984146,13.557809,-24.243359,-6.1560497 +653,-2.8174028,-37.33611,-20.860445,8.114155,14.213898 +654,164.96385,3.6760244,17.817131,-20.798529,-20.946114 +655,37.29271,34.63193,-30.144148,-18.056221,7.0855284 +656,-100.38691,65.24298,7.7894154,-30.84214,-4.7194057 +657,11.644444,-13.306839,-24.63588,-7.8941298,11.915645 +658,35.18441,31.835577,-34.857895,-20.796255,18.05091 +659,34.62694,0.64980835,-30.777193,-15.386609,13.649559 +660,-82.260155,24.552946,2.1615567,-19.962416,7.619771 +661,-8.741574,-30.736643,-21.032562,6.9783626,13.695789 +662,99.50273,7.467392,-17.116768,-18.0702,-12.5555725 +663,-110.42145,70.04828,11.867003,-31.75586,-4.023584 +664,145.38637,22.806349,3.1041899,-18.039257,-22.356739 +665,71.47593,39.965397,-29.102648,-17.921076,-0.34205654 +666,54.7389,-32.990837,-22.129253,-2.038036,-0.17748088 +667,-155.21121,-10.53675,37.56008,6.252758,-17.45293 +668,-77.50353,6.4595075,0.32210302,-11.425566,8.948993 +669,-5.7493324,-55.90734,-16.275602,18.934446,14.979262 +670,35.11085,93.68049,-34.38724,10.202013,7.67258 +671,140.30197,-66.7481,26.954042,8.463373,-29.635204 +672,-24.592012,162.75198,-15.881409,44.667706,-4.7344346 +673,-108.70609,43.845455,12.632868,-26.147778,-2.4001784 +674,144.27379,13.121962,0.76059496,-21.614296,-20.001457 +675,199.58772,-31.451881,68.34913,-13.173374,5.6648817 +676,-106.076675,-30.04114,17.849295,14.541587,-3.562081 +677,199.12096,34.87857,43.871876,-13.119459,-10.71897 +678,-92.01188,35.202694,5.135371,-22.346493,0.5480475 +679,-46.07279,-36.869114,-8.308701,12.346762,15.486908 +680,-136.05312,20.773129,25.8442,-16.561077,-8.368253 +681,-59.64573,123.34776,-5.023978,2.773408,-8.046625 +682,113.5421,14.522969,-17.407995,-20.547062,-11.219759 +683,-96.104706,58.794456,6.3721743,-29.191048,-3.2690663 +684,216.30951,8.985745,80.851746,-19.57702,26.848421 +685,165.86696,29.269657,16.085743,-15.012638,-22.234135 +686,-71.84171,25.937414,-2.6158962,-19.904095,8.705509 +687,192.13951,-39.605934,69.52105,-6.979847,-2.9097617 +688,-49.03411,9.916682,-11.548046,-14.392617,16.6016 +689,-25.736063,11.556689,-20.59736,-15.031437,18.10924 +690,9.671574,48.9379,-30.61043,-21.758152,17.289839 +691,-65.922455,47.71337,-5.8350916,-26.152473,6.669197 +692,-102.71128,-41.94454,18.649378,23.123732,-6.3802505 +693,-98.39337,51.86471,8.343551,-28.796122,0.22526923 +694,-76.812454,-19.817364,2.4459352,4.6089664,7.57419 +695,130.5915,-15.556708,-3.4020526,-16.419094,-17.224802 +696,-89.04878,-26.411488,8.808747,10.137309,3.6773815 +697,-57.995274,28.010363,-8.97452,-19.657076,9.661973 +698,113.179955,86.38084,-27.393965,20.406551,-8.8660965 +699,172.35405,-15.815833,34.03247,-17.96709,-20.291914 +700,139.09393,-47.15811,13.333508,-1.4447132,-26.052013 +701,-126.94446,-7.682992,23.802374,3.4190297,-10.192308 +702,7.5102234,38.821354,-30.492708,-21.873726,20.924881 +703,16.532854,-25.44298,-27.957993,0.50101805,16.751917 +704,-89.11582,3.4587507,5.4693666,-6.545822,1.6442144 +705,-83.79406,73.412254,1.7906027,-30.586847,-1.8436023 +706,87.97109,19.59263,-23.253746,-16.669928,-7.844782 +707,-146.03021,37.351467,29.277575,-23.166456,-12.506649 +708,-69.381744,24.866169,-4.0981464,-18.486803,7.63312 +709,130.26012,141.83083,-14.615038,68.6831,-13.99221 +710,59.229866,-8.2189865,-33.86836,-13.986199,14.557805 +711,-79.73288,58.519558,-0.3856912,-28.934536,6.167325 +712,-131.05064,-33.146564,30.45219,19.710354,-14.760603 +713,-80.61239,12.903095,1.8101308,-14.65118,7.891649 +714,207.90076,17.149164,60.008583,-13.413703,-0.036385912 +715,155.59277,8.815231,1.7665739,-15.95138,-16.039806 +716,191.28514,152.1861,13.670754,99.452774,-13.888799 +717,-79.37156,32.92283,-0.18833238,-21.554285,4.7637753 +718,-127.11976,39.005726,20.836065,-24.656912,-6.6158295 +719,87.39649,44.741203,-27.084795,-16.117228,-4.2897344 +720,-130.7142,6.879704,23.481455,-5.653173,-10.244477 +721,114.084236,-35.961815,-5.975841,-6.4005604,-17.59753 +722,-121.50863,9.357907,18.886292,-9.456418,-3.949675 +723,65.699234,-28.70444,-24.925356,-3.4949355,0.46189958 +724,96.374596,7.20928,-29.466122,-19.21573,3.0625439 +725,157.77594,-52.62521,31.968601,-0.08988806,-26.120455 +726,-25.150934,60.598774,-19.759293,-24.012575,10.4493885 +727,123.83931,-1.4218907,-15.670015,-20.040901,-7.7943277 +728,20.0477,43.904736,-29.66761,-18.69043,10.007128 +729,-43.562233,-41.554417,-8.470179,15.988351,13.551214 +730,137.05148,11.304952,-5.318181,-15.688839,-19.340353 +731,89.538704,9.410821,-24.243277,-16.967157,-6.003349 +732,62.06849,36.352806,-27.357952,-19.123398,-1.2348001 +733,-51.513077,24.353582,-11.643172,-18.89202,12.216744 +734,69.14747,-4.5108314,-30.135279,-16.542751,6.783376 +735,132.73285,54.378307,-14.084646,-6.7551,-14.877663 +736,-143.15436,63.596703,25.581783,-31.891127,-15.649445 +737,-74.73361,56.320667,-2.6980143,-28.430532,3.7712333 +738,-27.647198,16.748472,-19.867046,-16.861065,17.357836 +739,61.036827,28.488356,-27.06232,-17.98755,-1.6864742 +740,64.89609,-2.692718,-26.180866,-14.625721,-0.40113565 +741,141.2828,34.227863,-7.2316203,-17.498016,-17.008316 +742,91.203995,-45.049873,-8.477495,1.7182802,-17.424427 +743,-69.27146,40.7349,-4.3504577,-24.014933,6.108295 +744,-18.207052,176.08807,-19.757538,71.809814,-10.5161295 +745,-13.407216,49.95688,-24.053743,-22.897768,15.222433 +746,8.412633,37.4353,-30.811695,-21.42678,21.307396 +747,-1.2284632,56.393818,-27.37813,-21.61417,13.773436 +748,134.96887,28.814852,-5.9534316,-16.758022,-19.101858 +749,59.547,4.1862874,-27.006659,-18.056448,2.1378655 +750,-68.32459,129.49135,-1.8035724,5.1289043,-11.117813 +751,-93.16788,-9.018558,8.599524,-0.88831717,3.1853235 +752,147.20004,-1.234935,6.459775,-21.862839,-20.085169 +753,-156.1926,-11.008411,38.09805,7.34779,-18.98119 +754,7.846764,21.481636,-30.401083,-18.97621,18.836468 +755,-42.09921,8.070434,-13.869787,-14.232264,18.108953 +756,15.211983,-34.8001,-25.775959,5.357026,14.798496 +757,107.93509,-4.915562,-11.750307,-15.716999,-16.396553 +758,-116.548805,45.161892,15.038746,-25.547943,-7.418617 +759,-10.603907,196.70848,-18.88507,96.29304,-11.308069 +760,58.596607,-43.74394,-20.08807,4.7682123,-3.3476477 +761,272.5804,152.96338,139.37302,117.76156,101.18453 +762,-93.20449,56.977676,5.570368,-30.139135,1.6595324 +763,5.6916313,-57.144474,-16.692682,20.338188,6.103593 +764,152.70895,-20.565733,18.15084,-15.995729,-23.307512 +765,-98.21534,65.616104,6.793666,-31.074099,-3.6474714 +766,40.82695,-10.895501,-28.316292,-11.657441,9.485662 +767,-19.231112,30.727983,-23.020197,-21.775333,18.703342 +768,237.6659,8.891516,127.23832,-9.862196,71.510086 +769,187.69478,9.703871,39.0719,-13.66477,-15.752429 +770,-19.446123,135.33588,-21.330708,31.26952,-4.011803 +771,4.65591,67.339325,-29.140408,-15.723281,13.008857 +772,-139.05342,41.695393,26.036228,-25.51599,-10.491818 +773,116.980194,1.0449944,-11.220266,-18.787945,-15.904833 +774,-68.713974,-41.420002,2.3533041,19.230103,5.255733 +775,-139.13998,-15.156824,30.863432,8.080577,-13.393482 +776,134.66266,-16.498964,2.1162035,-16.46548,-20.606108 +777,167.25577,3.108071,18.540014,-18.248466,-19.99279 +778,89.60231,84.31561,-27.708502,12.347526,-8.533853 +779,9.453953,9.875764,-30.403616,-14.615442,20.080923 +780,161.13531,30.912802,11.279181,-15.108431,-21.971199 +781,-123.07616,-10.071252,22.396658,3.4844582,-7.7180333 +782,-159.87115,30.13942,35.234627,-18.961966,-16.68693 +783,-144.79662,54.448864,26.64605,-29.266853,-14.18936 +784,103.1296,26.633259,-18.043621,-18.09983,-12.626598 +785,-71.235146,24.533913,-3.1892986,-18.197706,6.3662906 +786,-150.01834,-34.789867,39.94231,23.351873,-22.399 +787,121.36805,-5.982723,-8.908487,-17.45387,-16.679901 +788,4.2666154,-30.70057,-23.53478,3.575134,14.46307 +789,-111.27126,60.658405,13.331776,-31.032879,-3.7237072 +790,-17.965923,40.70876,-24.35682,-22.922974,18.079176 +791,-69.98796,45.829006,-3.6997237,-26.560806,9.420176 +792,17.825615,-36.31737,-23.479034,5.0278172,10.27839 +793,146.25334,-40.887196,23.202492,-6.049572,-27.480875 +794,-42.84017,156.4389,-10.360108,29.51958,-9.482593 +795,161.15697,-26.679058,20.005424,-14.894823,-17.966112 +796,-138.25735,52.001667,23.75947,-28.32207,-11.946171 +797,23.942385,-67.39773,-11.692112,24.30944,-5.6906524 +798,-99.94671,57.27781,8.655872,-30.48692,0.83469874 +799,-95.675934,76.79361,6.5500946,-31.898497,-5.6545634 +800,122.54321,-21.638447,-6.591297,-15.133386,-15.719254 +801,199.12225,22.062395,50.32503,-21.065224,-5.9120984 +802,1.9904484,-25.284512,-24.707655,-0.39166138,20.627935 +803,17.44616,25.030428,-32.884975,-21.215754,22.265154 +804,-53.35604,32.482105,-10.00878,-23.43373,14.69987 +805,-96.83676,46.244728,6.7863655,-26.782322,-0.34454966 +806,218.2306,-10.661607,96.121574,-19.150856,41.577076 +807,-117.78233,-28.156204,23.205585,13.5961275,-6.6270795 +808,-138.83827,47.224102,24.652782,-25.938799,-13.602035 +809,-83.38921,-38.2976,8.655049,19.207674,0.29177165 +810,16.763437,-32.41066,-22.913084,2.293396,9.83826 +811,153.70766,-10.249074,16.71249,-16.243109,-24.564613 +812,171.40605,29.29388,19.169256,-13.538877,-20.837967 +813,-51.941093,-43.2921,-4.435316,17.344439,11.893205 +814,170.08702,-30.590425,35.179947,-11.646059,-20.829697 +815,-81.96002,71.005135,1.1734957,-29.722664,-1.3372297 +816,-148.9598,46.381714,29.783833,-26.547352,-14.476233 +817,94.323975,-23.865217,-12.622582,-9.759389,-14.172075 +818,157.13622,1.9768631,16.07817,-16.88407,-24.895662 +819,-18.454716,-17.941236,-20.506506,-1.8556556,19.28447 +820,56.565796,1.358635,-26.903147,-16.061975,2.0405672 +821,-103.98205,47.800323,10.043671,-27.391096,-2.4251091 +822,5.5755177,-39.99502,-22.569664,9.217628,14.081818 +823,-22.154,-47.250774,-14.763699,15.996659,17.773058 +824,-107.92749,53.62191,12.732936,-29.997221,-1.1362183 +825,-58.111706,26.401394,-9.129364,-19.704655,10.570365 +826,11.451162,-55.068584,-16.704964,17.566875,4.526788 +827,213.24384,81.51534,49.457695,29.66666,-6.526242 +828,22.062437,-14.90941,-25.683744,-6.99193,9.413453 +829,3.975515,-6.4070907,-26.549356,-9.615978,16.872341 +830,-110.142624,93.30752,11.5944395,-30.199402,-10.730521 +831,191.3322,125.16821,20.152878,71.80458,-21.318262 +832,-84.254196,75.15189,1.3936673,-30.151205,-1.2868166 +833,-23.261549,-3.1989667,-19.386236,-10.521259,20.389763 +834,156.70569,142.8062,-15.135668,84.73064,-12.854358 +835,89.71663,36.630886,-27.166311,-16.007637,-3.671119 +836,-153.11401,-16.73628,37.957184,10.120158,-18.10498 +837,-11.006088,53.763615,-24.29135,-21.984257,13.061707 +838,-8.871491,-21.372475,-23.007057,0.08528327,18.909773 +839,-160.9931,-4.6849895,39.215588,4.7006974,-21.107342 +840,98.061874,-25.625574,-12.707994,-9.473343,-13.468601 +841,-133.30003,-9.055352,27.057571,2.4786444,-9.113256 +842,52.109108,22.372087,-33.047337,-18.885109,10.480785 +843,-4.3929157,12.22789,-27.238058,-15.3477125,19.77236 +844,59.76119,14.399766,-28.489355,-18.20323,2.3925376 +845,88.72395,145.9136,-36.963604,75.216415,0.355409 +846,215.53995,-17.816458,97.177505,-9.868421,28.035969 +847,257.17313,143.83516,113.322464,99.81528,63.020382 +848,-82.96141,32.447556,1.3773856,-21.936323,4.553685 +849,-136.869,-30.731256,32.984406,18.75982,-16.855627 +850,149.16722,33.232388,-2.334865,-16.120815,-17.669807 +851,-95.49036,-18.771898,10.712094,6.1236215,1.727854 +852,87.03374,4.2851143,-25.23065,-19.67288,-1.9532751 +853,-120.88826,-30.97939,25.28203,17.108513,-10.604718 +854,-126.680916,20.814035,21.28075,-15.416202,-7.6137295 +855,-93.32956,-20.539406,10.457704,6.4682226,2.4603703 +856,64.165,22.519669,-33.35599,-18.515594,8.973188 +857,179.3314,-11.860508,37.02839,-19.209295,-14.856914 +858,-123.965576,-15.466525,23.915071,5.4988227,-6.8676286 +859,-111.698524,-22.38319,19.27047,9.558357,-4.2396894 +860,-162.82127,-13.915481,42.07622,10.283431,-22.847855 +861,95.613914,32.236485,-27.235535,-16.688465,-3.0995793 +862,-68.63641,-20.458193,-0.814254,3.8566508,10.512975 +863,144.72266,-7.1147494,8.547503,-20.756647,-21.399332 +864,-140.82944,-21.22472,32.70952,14.868281,-18.449057 +865,-5.630801,148.71965,-21.324888,35.818954,0.2883935 +866,140.43814,29.214302,-4.8393908,-17.445095,-18.42813 +867,-11.75319,-55.00421,-15.6073,19.395216,15.339995 +868,-101.26588,-28.069008,15.156316,12.744995,-1.3427572 +869,-49.3058,-11.19922,-10.204692,-3.41713,15.117037 +870,147.53049,-46.2059,20.443697,-4.3386793,-25.488266 +871,178.0836,-8.066205,34.210045,-19.05857,-17.082605 +872,141.28494,-2.9899504,0.1596404,-16.086733,-19.902948 +873,-53.944515,73.09456,-9.353769,-26.350086,3.6249263 +874,50.439014,8.075422,-29.450346,-18.940403,6.975499 +875,-80.40267,32.161522,0.61440545,-21.253849,3.3618634 +876,5.977047,151.95818,-25.304222,44.928608,2.2001092 +877,-96.832,51.65313,7.4012833,-28.670948,0.7886745 +878,170.9836,26.728975,13.196266,-17.191721,-18.300407 +879,163.76207,-16.683504,24.284634,-15.457726,-22.469633 +880,81.12098,46.434113,-28.867474,-15.496934,-1.6699181 +881,-101.8936,4.008527,11.184008,-7.1232014,-0.19331528 +882,-134.29108,28.424025,23.503645,-17.983765,-10.930394 +883,210.76294,108.4553,33.381073,60.052353,-18.377277 +884,-10.058175,46.415188,-24.55013,-21.11507,13.425209 +885,85.35731,27.791119,-27.876265,-19.085527,-2.675801 +886,111.72559,-41.82072,-4.4483466,-1.9866533,-19.900372 +887,-72.78352,124.7544,-0.08042301,-1.4070765,-12.398982 +888,44.8915,166.83107,-33.735638,83.613785,0.44838023 +889,-114.39037,89.06474,13.641948,-33.149746,-11.730158 +890,-60.56437,-29.331999,-3.229798,10.514835,8.909185 +891,228.01016,23.590784,100.15506,-13.204116,39.082268 +892,6.8763757,102.160866,-28.130293,6.9515257,7.1198754 +893,-54.493572,-39.830322,-4.050056,15.242568,12.186497 +894,2.5752246,158.1236,-24.650682,53.049088,0.23323742 +895,-134.81537,68.31302,22.86592,-33.636337,-11.441167 +896,248.6578,19.685057,151.42213,-12.001819,103.33863 +897,146.79092,80.03883,-4.24012,16.877417,-23.255278 +898,123.170685,-63.84194,3.8920333,3.8151748,-16.788378 +899,-79.39596,67.46751,-0.3532519,-29.780901,0.5404316 +900,188.3004,-40.644638,54.957962,-7.8510866,-5.538062 +901,-62.927994,43.47358,-7.243596,-24.684557,8.030865 +902,-135.64346,-2.9914808,27.060677,-0.9950423,-9.229048 +903,-26.60852,-2.471774,-19.28022,-8.387593,17.09525 +904,122.336075,38.526615,-14.219955,-16.810396,-15.378144 +905,-7.894354,28.71497,-27.084717,-20.392542,19.375536 +906,-99.98505,34.368244,9.360137,-22.944809,1.1760813 +907,-96.07592,55.142536,6.921544,-29.457235,0.8851064 +908,127.48456,7.3594522,-8.840105,-18.93943,-17.244871 +909,72.664215,113.86915,-35.681602,41.191467,-4.6550407 +910,-110.17092,-18.944235,17.795258,9.997366,-7.0103803 +911,54.453873,-58.168423,-19.134825,10.965355,1.4819255 +912,-79.405525,31.467682,0.16362433,-21.42153,4.3606143 +913,214.40916,-1.5188847,86.64755,-15.256384,19.585402 +914,67.53613,-41.704556,-23.177088,1.0531659,0.75873715 +915,-38.615913,1.514594,-15.051962,-9.819708,15.091346 +916,-105.720924,140.53435,12.885587,-3.0807478,-23.636951 +917,0.960379,38.872566,-28.778065,-20.485044,17.00397 +918,-66.06223,-0.4328274,-4.0984707,-6.1983333,8.191709 +919,-84.91311,-18.06909,5.696654,3.870902,6.230383 +920,74.141914,15.288397,-25.724157,-16.501505,-4.076509 +921,-117.97937,53.38469,15.593447,-28.62224,-7.621264 +922,-151.15843,-16.882618,36.966408,10.436509,-17.617537 +923,215.60278,15.95037,76.02893,-12.181198,15.118357 +924,-39.74755,-20.45278,-12.765358,1.4757601,16.275354 +925,47.023056,-23.32942,-26.000637,-7.4100037,7.1083946 +926,97.62396,34.450348,-28.145042,-14.324689,-2.1757102 +927,179.08723,49.726753,18.176914,-6.8751035,-19.597277 +928,50.780117,-63.076683,-18.542706,17.793211,-1.701092 +929,-99.44017,67.09989,7.165045,-31.768642,-3.6325505 +930,-43.35428,-40.932194,-8.627593,14.899138,15.342478 +931,-61.650806,-40.621407,-0.8632681,16.96905,9.659671 +932,-118.02193,17.19165,17.633509,-13.805556,-5.062261 +933,14.115023,34.749485,-32.09538,-20.375721,20.777256 +934,-113.724915,46.60896,15.2365465,-27.907166,-3.4697022 +935,-28.340944,29.049324,-20.108856,-21.106472,17.660213 +936,-109.44033,-34.421284,20.671091,17.367168,-5.718286 +937,105.67789,-70.608955,0.5850992,14.374734,-22.229967 +938,-138.6317,25.994814,26.238651,-18.096453,-10.315121 +939,56.498276,161.96272,-38.69774,90.80158,1.2755157 +940,103.716965,-7.3266544,-18.040577,-16.954079,-8.79069 +941,140.0557,15.41938,-5.900626,-17.504387,-17.896082 +942,-100.33173,30.453163,9.373913,-20.983088,-0.42393577 +943,138.71016,-23.745567,5.6949534,-17.982063,-18.596195 +944,-75.063515,-29.608538,2.9508832,10.700044,8.149188 +945,-97.77555,-23.418797,12.910229,12.057156,-4.5792975 +946,65.19414,-11.980142,-25.467598,-15.21165,3.2883403 +947,-36.910786,-26.58096,-13.168382,4.056237,17.757051 +948,121.58668,-33.959755,-0.24610701,-7.2205997,-21.3397 +949,-104.239494,50.347916,9.64414,-27.766449,-3.462823 +950,-39.58209,193.49913,-12.987284,82.93022,-19.250683 +951,53.375156,-40.46833,-21.311792,1.8330938,0.06835045 +952,-78.34242,-34.243862,5.380905,14.749127,5.116478 +953,16.450531,154.42085,-30.049755,58.197132,3.359307 +954,-100.466965,-18.17486,13.197066,5.6996384,0.15526053 +955,158.35422,-38.239956,20.966982,-7.653812,-19.565481 +956,-141.97676,59.39322,26.073467,-31.412422,-12.881704 +957,-32.217884,142.3093,-16.205359,22.936392,-4.1716795 +958,-10.808091,53.766445,-24.801136,-22.52706,14.097812 +959,-6.718971,6.465244,-25.763163,-13.75056,19.897215 +960,-147.97304,-12.038655,34.5814,6.621838,-15.882551 +961,39.688087,36.28295,-30.331549,-17.98917,5.9653387 +962,-57.66111,30.769985,-7.828503,-22.877153,13.689132 +963,79.54389,-12.419176,-27.353537,-12.941691,1.4125915 +964,-26.631447,12.27457,-20.182178,-15.08874,17.065313 +965,216.66844,19.763388,77.68458,-15.470589,17.759575 +966,-85.60255,130.60606,5.4578695,-1.0763901,-17.017515 +967,-114.89715,41.533665,14.750911,-24.635677,-5.9406495 +968,-107.43719,70.92032,10.415332,-33.075817,-6.1842523 +969,-95.79117,79.61575,6.4713936,-32.09298,-5.848452 +970,214.32797,36.575275,68.156845,-7.8175516,7.224438 +971,160.3588,164.67847,-9.524321,117.468,-19.932188 +972,-161.21214,-16.084377,41.52392,11.8686285,-22.724018 +973,132.55284,-11.824575,-3.3285494,-15.711859,-18.491686 +974,-101.74262,58.327377,9.159532,-30.132975,-1.7060108 +975,126.77834,18.89133,-11.276893,-16.138655,-16.82411 +976,71.48787,17.046312,-23.840769,-18.342947,-5.346279 +977,-75.324554,-5.729115,0.27351654,-4.271674,8.688844 +978,-87.98757,-5.2525773,5.702961,-1.9572847,2.8677151 +979,-112.464966,-7.6377106,16.932653,1.5712916,-4.4682655 +980,24.723001,-32.37525,-23.994598,2.1929736,8.2156925 +981,119.079285,12.600389,-21.86416,-22.079351,-3.2063284 +982,-100.8097,0.036508255,11.270832,-6.3332543,1.9616112 +983,-28.627348,50.58564,-18.466053,-22.706478,10.890417 +984,-152.83047,-3.1118605,35.284733,0.3075423,-15.26559 +985,-1.8659825,-32.855804,-21.879509,6.2607822,14.212658 +986,-45.13921,10.962013,-12.554609,-15.359904,16.61396 +987,-124.36853,7.056143,21.567602,-7.015423,-8.402845 +988,89.86258,16.56253,-23.564781,-16.652187,-7.2095547 +989,-51.428097,14.026516,-10.774974,-16.5096,17.05634 +990,-120.86061,19.2808,19.033413,-16.304611,-4.189333 +991,-113.530075,-10.421414,17.935637,4.278058,-6.5787687 +992,192.60555,-27.401243,62.647705,-12.01094,-5.5269957 +993,82.72921,36.912354,-27.403187,-14.825361,-3.2337413 +994,-87.98154,51.909805,3.5863466,-27.638544,0.32825947 +995,192.531,-2.7637687,48.360767,-19.99384,-8.832425 +996,165.35283,-48.31086,38.328274,-3.2081265,-23.81461 +997,2.2624037,5.5327535,-26.872492,-15.172605,19.020819 +998,-1.7815185,20.079012,-28.4706,-18.841942,21.232216 +999,-136.24225,21.334356,25.024084,-14.356951,-11.309762 +1000,-25.07228,-45.32023,-13.976359,15.456443,16.768654 +1001,-139.45174,-10.037964,30.099846,6.1685863,-14.868904 +1002,98.50674,79.42516,-33.646835,13.483313,-2.6447215 +1003,63.426285,-30.514273,-23.12172,-5.0524635,0.1731273 +1004,-127.35091,24.828384,21.123222,-17.810223,-6.466299 +1005,-150.55807,-28.43203,38.91048,18.744633,-21.007494 +1006,130.49435,-19.585688,-2.7126634,-13.033539,-18.770504 +1007,-94.375435,51.707348,6.6905365,-28.671682,1.4558511 +1008,-13.855269,-8.6352415,-22.622192,-7.073127,18.625784 +1009,-135.86897,8.166023,25.496992,-6.6362796,-10.276325 +1010,147.12242,32.998108,-2.4637854,-14.232103,-18.374538 +1011,-132.52568,58.064037,21.792414,-30.366035,-11.588376 +1012,36.923008,-35.367596,-23.827883,2.6522977,4.961984 +1013,42.0594,17.593292,-25.758722,-18.141743,1.2383527 +1014,58.4495,-24.887873,-23.282171,-8.53925,1.6559744 +1015,122.69038,-24.778027,-5.359862,-13.622763,-16.258202 +1016,124.790535,43.43121,-14.248689,-15.105053,-14.870175 +1017,2.771261,-49.439022,-16.961275,15.030225,6.958343 +1018,70.149704,-21.639849,-22.021622,-8.515284,-4.181344 +1019,-63.71221,-16.407898,-4.4074354,3.423331,9.379706 +1020,219.37088,10.227684,84.27505,-16.86119,32.23385 +1021,-86.66152,34.478966,2.8723924,-22.009766,1.7771071 +1022,135.69414,-28.362095,9.994212,-11.709089,-24.236412 +1023,-71.7607,44.34247,-2.74268,-26.74694,9.429321 +1024,43.2857,-8.274279,-29.040941,-11.272115,8.180232 +1025,-75.03205,27.481829,-1.4743836,-20.74857,8.548763 +1026,93.76958,156.2949,-35.37639,89.88513,-2.4097083 +1027,-83.901665,-2.1756053,3.8720508,-6.712383,7.434656 +1028,-63.190037,43.63437,-6.348466,-25.95439,11.049983 +1029,29.596027,68.52869,-34.214813,-10.105762,15.05519 +1030,-28.932558,34.789024,-20.17114,-22.245687,15.7697735 +1031,1.8884426,5.3824778,-28.034376,-14.529776,21.861595 +1032,-147.94302,-2.2014945,32.711605,2.0768833,-17.15192 +1033,9.819977,4.013362,-29.758148,-14.386698,22.277618 +1034,-129.39056,-19.106321,27.049809,9.051766,-9.926881 +1035,-39.352337,-3.4692092,-13.9895315,-9.43949,18.316296 +1036,-74.772766,57.447777,-3.083912,-28.957104,4.7566905 +1037,-139.84554,-13.064283,30.848825,6.788249,-13.720726 +1038,-106.5625,-21.201946,16.474167,7.9073644,-1.0769129 +1039,96.94351,54.52247,-26.404484,-10.837704,-6.3720665 +1040,-74.00915,24.809366,-2.3928087,-18.849195,7.2978086 +1041,13.80367,123.35751,-32.045517,34.411655,2.6104863 +1042,-4.918483,-43.7558,-19.075247,11.367015,15.018916 +1043,-47.031483,-32.880074,-8.091581,10.5965395,12.718205 +1044,-2.8572073,30.698051,-27.12431,-18.954493,16.482134 +1045,-4.5264406,-52.37939,-17.677362,16.80288,14.257305 +1046,147.02974,79.30538,-10.779117,18.699604,-18.390495 +1047,27.099195,13.407525,-32.167995,-17.644419,16.076761 +1048,-87.22336,25.209541,4.2295227,-20.359604,5.791559 +1049,82.05987,-27.603594,-15.314236,-7.1438046,-10.924391 +1050,108.85064,39.814697,-17.644245,-16.809381,-12.753025 +1051,-27.927816,166.16064,-16.692642,52.608932,-8.423241 +1052,124.448845,6.2375956,-9.346502,-18.303755,-17.461706 +1053,-33.79508,61.20491,-17.426237,-25.121653,10.194704 +1054,155.42252,-17.220116,17.82026,-20.87584,-20.09293 +1055,20.326204,49.154995,-32.6815,-19.17766,17.516657 +1056,18.520521,7.3749614,-31.044304,-16.087875,17.688862 +1057,-96.21655,35.922947,7.09447,-23.12294,0.16772108 +1058,-37.580845,18.852419,-16.14563,-17.126366,14.420918 +1059,-127.25653,-21.388502,26.378185,10.298688,-9.44546 +1060,-91.59811,57.868713,4.6463666,-29.049023,-1.2302938 +1061,-69.34355,-52.983547,5.079231,27.331305,2.460952 +1062,16.018799,-29.612537,-22.058645,1.6966791,7.3397183 +1063,69.195,35.975796,-28.887636,-20.374271,0.17305844 +1064,-24.750319,25.13669,-21.605835,-19.832382,17.929667 +1065,107.188614,13.784123,-13.408238,-18.340425,-16.095842 +1066,114.14747,-45.301792,-1.0846345,-0.42135492,-22.009434 +1067,123.05721,17.843794,-12.274399,-15.659563,-16.008583 +1068,0.52330947,169.82317,-26.74497,74.48542,-5.495492 +1069,-155.51837,48.470657,32.142063,-26.781328,-16.58701 +1070,-120.77458,36.346546,18.436258,-23.639128,-5.457659 +1071,44.340275,-3.421573,-30.990887,-16.173948,13.732636 +1072,-20.46898,33.021214,-23.288366,-21.46211,17.944323 +1073,18.576048,-12.771481,-27.512417,-8.293081,13.978498 +1074,-132.71823,70.44581,21.30121,-33.185978,-14.454096 +1075,-6.662337,59.001945,-26.08647,-21.68677,13.259825 +1076,-7.9748297,57.07794,-26.051014,-21.41442,13.291178 +1077,-74.301155,0.30729294,-0.19402616,-8.418488,9.361892 +1078,180.92162,-26.634535,46.339794,-11.373362,-17.86923 +1079,-138.36903,77.641365,23.554893,-35.403706,-12.057637 +1080,128.62991,40.894367,-11.466453,-14.607474,-16.209883 +1081,18.49046,4.002437,-30.174742,-15.6531315,18.729122 +1082,-87.86062,6.102557,4.6575665,-8.297096,2.4174306 +1083,28.520132,-21.13887,-27.457981,-5.591666,12.349287 +1084,229.5915,-6.7063127,122.78098,-12.588023,58.247406 +1085,-96.74121,-17.554113,11.458616,5.0584145,1.286545 +1086,151.72586,11.259757,6.1808047,-20.541168,-21.177973 +1087,111.91104,22.223272,-15.25258,-17.715195,-14.453598 +1088,-88.853516,-9.4926195,6.6115866,1.1953682,1.3849474 +1089,-11.430906,-1.91226,-24.440361,-10.261976,20.221853 +1090,106.34003,8.48525,-15.840256,-17.22529,-14.046478 +1091,-17.880808,-46.00635,-15.799684,14.385599,18.2603 +1092,-92.844025,-25.363565,10.62296,10.601208,0.8991445 +1093,-81.97268,187.63344,3.0157115,52.001144,-26.187992 +1094,137.89143,44.361675,-12.113254,-13.077734,-15.803141 +1095,47.620487,11.737284,-32.487514,-20.092833,12.433499 +1096,132.82785,-15.128237,-6.235373,-17.664974,-13.011 +1097,172.29314,-20.661562,36.619106,-14.200037,-21.62875 +1098,67.07803,-3.016149,-23.661276,-15.116798,-3.5690084 +1099,191.01569,-4.3509936,48.72787,-17.97153,-10.683647 +1100,121.44116,-19.466293,-8.422562,-12.382827,-16.191544 +1101,236.53217,-1.7353712,126.82081,-11.187742,75.714745 +1102,-95.13445,71.041794,5.1641974,-31.4307,-2.7306437 +1103,-63.32212,0.5990671,-5.1938195,-8.805229,11.510723 +1104,181.63817,-15.652165,40.086685,-14.660402,-16.47014 +1105,132.2005,0.0031645359,-5.535632,-16.03363,-18.7938 +1106,-66.79625,77.15438,-4.240736,-27.808264,-0.07994259 +1107,42.671566,34.949768,-30.189716,-17.783115,5.56107 +1108,169.34784,7.6492586,23.538315,-20.6121,-22.30165 +1109,-124.378914,47.600372,18.428944,-26.605713,-9.286715 +1110,40.986298,43.70529,-31.529629,-17.608593,7.2860947 +1111,158.63463,-21.99267,19.65406,-14.379705,-21.670712 +1112,34.939316,-55.67085,-18.431952,13.988169,1.8718935 +1113,105.37193,-27.415367,-9.701938,-8.893911,-16.467009 +1114,94.45471,-27.509235,-13.502156,-7.8125606,-13.062869 +1115,-116.42337,39.836872,15.96862,-25.054075,-4.4158196 +1116,-146.63127,-17.892973,34.936886,10.344487,-15.974094 +1117,-51.457623,-47.756435,-3.7665374,20.620045,10.982539 +1118,42.98659,-5.1995416,-30.34891,-13.813024,11.846703 +1119,-138.06807,13.708341,26.035124,-11.255253,-8.460379 +1120,83.97784,26.692322,-25.147642,-18.31538,-5.5810127 +1121,173.54805,38.857365,19.051058,-13.691236,-21.15005 +1122,-37.808693,-52.981125,-8.095355,23.213678,11.302368 +1123,10.867202,-10.917984,-24.972408,-8.451305,11.639404 +1124,87.36295,-47.598225,-11.40406,1.0981761,-12.126589 +1125,-29.87536,-46.429592,-12.678925,17.168146,16.310947 +1126,-43.211147,44.158466,-15.1149,-24.877975,13.670144 +1127,-95.53648,-14.864931,10.546446,5.5292697,-2.0056288 +1128,52.001034,32.512,-32.724792,-17.972115,7.6628966 +1129,149.18683,134.92625,-12.468308,67.81797,-15.24825 +1130,-112.761604,40.64032,13.672749,-23.745731,-6.089723 +1131,-133.82425,-19.941034,29.25054,10.089142,-11.489655 +1132,-69.29175,-11.777634,-1.8030283,1.4212902,6.2047453 +1133,-63.68908,64.03605,-6.392045,-28.223152,5.5463276 +1134,-104.00507,-24.149372,15.77054,13.23709,-5.9768167 +1135,-80.4252,50.633648,0.75288075,-28.369757,5.583478 +1136,128.91939,8.942819,-8.597207,-16.504217,-18.225527 +1137,-23.766256,134.10481,-20.041878,29.146627,-4.869849 +1138,67.394615,-7.1891274,-26.005896,-15.256671,0.6998616 +1139,116.293076,57.73614,-17.93913,-7.322402,-12.994783 +1140,180.46788,41.84094,25.420938,-11.941088,-19.595522 +1141,-126.363075,56.959454,18.837265,-29.67244,-10.758992 +1142,-139.99464,5.439582,27.895943,-4.5025783,-12.650589 +1143,153.44518,12.43709,7.8536997,-16.941065,-21.691917 +1144,-116.854,22.8221,16.690435,-17.14712,-4.310735 +1145,-56.166523,26.81025,-10.04751,-20.467249,12.235699 +1146,8.840901,10.134413,-29.214018,-15.499411,17.603767 +1147,-31.546589,-9.291581,-17.01604,-4.154032,15.854872 +1148,-25.538668,7.707966,-19.923857,-13.320342,16.55654 +1149,-38.10777,-6.486807,-14.142454,-7.1918035,17.3519 +1150,113.73359,-11.209371,-11.3102865,-17.043709,-14.328051 +1151,82.08023,27.45906,-25.156286,-19.167717,-5.365999 +1152,55.53718,-6.6924443,-26.249268,-12.595908,1.5102916 +1153,4.929855,-10.593101,-26.343271,-9.797769,22.437853 +1154,62.617832,-52.974804,-18.858917,7.980469,-2.9523 +1155,-59.56966,-49.531254,0.092486896,23.34825,6.8351073 +1156,28.335766,2.252884,-27.396584,-13.87095,7.9131484 +1157,66.21139,-71.52332,-14.965335,21.161036,-7.7749953 +1158,21.478786,34.781452,-32.68307,-20.47525,19.173077 +1159,55.635612,33.942505,-33.123497,-17.30791,7.6930857 +1160,-78.69053,-34.260628,5.582295,14.459513,5.5292616 +1161,111.61593,-38.405052,-5.5750074,-4.1581182,-18.97661 +1162,-140.43033,-3.5219939,29.384,2.1715143,-14.576401 +1163,-164.31502,-1.6797799,40.532486,1.471907,-20.05398 +1164,-117.48667,34.64185,16.948479,-22.774574,-4.3246202 +1165,106.525826,1.3351219,-17.485289,-18.031075,-10.719935 +1166,-32.41809,13.302869,-18.057535,-15.966791,17.096743 +1167,46.97699,-16.092882,-30.544197,-9.057213,11.558969 +1168,85.52453,29.679976,-28.506018,-20.61362,-1.7914561 +1169,-28.054901,19.208908,-19.767115,-17.711248,17.402576 +1170,70.025406,146.3294,-33.3511,62.55636,0.10550626 +1171,70.87946,30.96909,-27.915316,-18.558338,-1.1841104 +1172,-27.441944,50.526398,-20.131002,-24.85279,15.755479 +1173,-109.62896,-17.122406,17.296202,6.187609,-3.1047292 +1174,-25.22069,-38.57822,-15.214765,11.359952,16.643272 +1175,-58.36235,0.77005666,-6.932553,-9.941386,14.161715 +1176,19.713146,47.635624,-31.846708,-18.766447,15.897551 +1177,-44.521084,46.335575,-15.040741,-25.764868,14.165913 +1178,-20.705887,63.906715,-21.727442,-22.544682,11.845607 +1179,77.18272,28.001923,-28.74902,-20.197117,-0.33827966 +1180,23.871197,125.8794,-34.252758,38.545372,4.520382 +1181,-4.061196,16.615475,-26.93268,-18.84383,21.85836 +1182,-110.89609,141.98999,14.180769,0.4630819,-24.971302 +1183,3.9331486,169.01859,-27.579817,75.16742,-4.79345 +1184,194.05008,44.890083,38.053722,-8.199064,-13.625779 +1185,-2.5736938,13.24997,-27.936653,-16.31198,21.132198 +1186,158.53722,-7.9402742,13.46507,-17.95458,-19.529257 +1187,-76.461105,32.740185,-0.5681207,-22.603098,7.2694807 +1188,202.59518,11.539262,56.211254,-15.174271,-3.430824 +1189,233.63979,22.913721,111.367294,-10.367076,52.56934 +1190,175.60103,0.20044461,29.106655,-21.051167,-17.290241 +1191,102.472946,-2.6599069,-15.714215,-18.473116,-12.130613 +1192,211.83829,93.55855,47.054043,37.852936,-10.221341 +1193,196.59822,17.307207,45.240753,-22.572115,-6.682356 +1194,-105.696266,31.126778,12.05448,-21.951553,-0.28249395 +1195,-94.200554,59.7661,5.6707525,-30.933743,2.1143844 +1196,-78.11646,71.02954,-0.5829674,-29.747503,-0.51822704 +1197,113.26835,19.458982,-12.671197,-19.186018,-16.453045 +1198,176.07632,53.461216,18.84166,-4.5705857,-19.547678 +1199,133.45593,121.8764,-21.105099,50.591175,-11.437525 diff --git a/tests/interpolation/test_gps.py b/tests/interpolation/test_gps.py new file mode 100644 index 0000000..c60cd90 --- /dev/null +++ b/tests/interpolation/test_gps.py @@ -0,0 +1,240 @@ +"""Test suite for ExactGPInterpolation using real data.""" + +import os +import unittest + +import numpy as np +import pandas as pd + +from bluemath_tk.interpolation.gps import ExactGPInterpolation + + +def get_test_data_path(filename): + """Get path to test data files.""" + test_dir = os.path.dirname(os.path.abspath(__file__)) + return os.path.join(test_dir, "..", "data", "interpolation", filename) + + +class TestExactGPInterpolation(unittest.TestCase): + """Test suite for ExactGPInterpolation using real data.""" + + def setUp(self): + """Set up test fixtures with real data.""" + predictor_path = get_test_data_path("predictor.csv") + target_path = get_test_data_path("target.csv") + + self.subset_data = pd.read_csv(predictor_path, index_col=0).iloc[::10] + self.target_data = pd.read_csv(target_path, index_col=0).iloc[::10] + + def test_fit(self): + """Test fit with real data.""" + gp = ExactGPInterpolation(kernel="rbf+matern", epochs=50) + gp.fit( + subset_data=self.subset_data, + subset_directional_variables=["wind_dir"], + target_data=self.target_data, + normalize_target_data=True, + verbose=0, + ) + + self.assertTrue(gp.is_fitted) + self.assertTrue(gp.is_target_normalized) + self.assertIn("wind_dir_u", gp.normalized_subset_data.columns) + self.assertIn("wind_dir_v", gp.normalized_subset_data.columns) + self.assertIsNotNone(gp.hyperparameters) + self.assertGreater(len(gp.hyperparameters), 0) + + def test_predict(self): + """Test predict with real data.""" + gp = ExactGPInterpolation(kernel="rbf+matern", epochs=50) + gp.fit( + subset_data=self.subset_data, + subset_directional_variables=["wind_dir"], + target_data=self.target_data, + normalize_target_data=True, + verbose=0, + ) + + # Predict on full dataset + predictions = gp.predict(dataset=self.subset_data, verbose=0) + self.assertIsInstance(predictions, pd.DataFrame) + self.assertEqual(len(predictions), len(self.subset_data)) + # Check that all target columns are present + for col in self.target_data.columns: + self.assertIn(col, predictions.columns) + + def test_predict_with_uncertainty(self): + """Test predict with uncertainty quantification.""" + gp = ExactGPInterpolation(kernel="rbf+matern", epochs=50) + gp.fit( + subset_data=self.subset_data, + subset_directional_variables=["wind_dir"], + target_data=self.target_data, + normalize_target_data=True, + verbose=0, + ) + + # Predict on full dataset + predictions = gp.predict(dataset=self.subset_data, return_std=True, verbose=0) + self.assertIsInstance(predictions, pd.DataFrame) + # Check that uncertainty columns are present + for col in self.target_data.columns: + self.assertIn(f"{col}_lower_ci", predictions.columns) + self.assertIn(f"{col}_upper_ci", predictions.columns) + # Check that lower CI < upper CI + self.assertTrue( + (predictions[f"{col}_lower_ci"] <= predictions[f"{col}_upper_ci"]).all() + ) + + def test_fit_predict(self): + """Test fit_predict with real data.""" + gp = ExactGPInterpolation(kernel="rbf+matern", epochs=50) + predictions = gp.fit_predict( + subset_data=self.subset_data, + subset_directional_variables=["wind_dir"], + target_data=self.target_data, + normalize_target_data=True, + dataset=self.subset_data, + verbose=0, + ) + + self.assertIsInstance(predictions, pd.DataFrame) + self.assertEqual(len(predictions), len(self.subset_data)) + # Check that all target columns are present + for col in self.target_data.columns: + self.assertIn(col, predictions.columns) + + def test_training_poins_have_zero_error(self): + """Test that training points have zero error.""" + gp = ExactGPInterpolation(kernel="rbf+matern", epochs=50) + training_predictions = gp.fit_predict( + subset_data=self.subset_data, + subset_directional_variables=["wind_dir"], + target_data=self.target_data, + dataset=self.subset_data, + ) + for col in self.target_data.columns: + self.assertLessEqual( + np.abs( + self.target_data[col].values - training_predictions[col].values + ).max(), + 10, + ) + + def test_without_normalization(self): + """Test real data without target normalization.""" + gp = ExactGPInterpolation(kernel="rbf+matern", epochs=50) + gp.fit( + subset_data=self.subset_data, + subset_directional_variables=["wind_dir"], + target_data=self.target_data, + normalize_target_data=False, + verbose=0, + ) + + self.assertTrue(gp.is_fitted) + self.assertFalse(gp.is_target_normalized) + + def test_different_kernels(self): + """Test real data with different kernel types.""" + # Test with rbf kernel + gp_rbf = ExactGPInterpolation(kernel="rbf", epochs=50) + gp_rbf.fit( + subset_data=self.subset_data, + subset_directional_variables=["wind_dir"], + target_data=self.target_data, + normalize_target_data=True, + verbose=0, + ) + self.assertTrue(gp_rbf.is_fitted) + + # Test with matern kernel + gp_matern = ExactGPInterpolation(kernel="matern", epochs=50) + gp_matern.fit( + subset_data=self.subset_data, + subset_directional_variables=["wind_dir"], + target_data=self.target_data, + normalize_target_data=True, + verbose=0, + ) + self.assertTrue(gp_matern.is_fitted) + + # Test with rbf+matern kernel (default) + gp_combined = ExactGPInterpolation(kernel="rbf+matern", epochs=50) + gp_combined.fit( + subset_data=self.subset_data, + subset_directional_variables=["wind_dir"], + target_data=self.target_data, + normalize_target_data=True, + verbose=0, + ) + self.assertTrue(gp_combined.is_fitted) + + def test_hyperparameters_extraction(self): + """Test that hyperparameters are properly extracted.""" + gp = ExactGPInterpolation(kernel="rbf+matern", epochs=50) + gp.fit( + subset_data=self.subset_data, + subset_directional_variables=["wind_dir"], + target_data=self.target_data, + normalize_target_data=True, + verbose=0, + ) + + # Check hyperparameters structure + hyperparams = gp.hyperparameters + self.assertIsInstance(hyperparams, dict) + self.assertGreater(len(hyperparams), 0) + + # Check that each target variable has hyperparameters + for target_var in self.target_data.columns: + self.assertIn(target_var, hyperparams) + target_hyperparams = hyperparams[target_var] + self.assertIsInstance(target_hyperparams, dict) + # Check for expected keys + self.assertIn("noise", target_hyperparams) + self.assertIn("outputscale", target_hyperparams) + + def test_predictions_shape_and_type(self): + """Test that predictions have correct shape and data types.""" + gp = ExactGPInterpolation(kernel="rbf+matern", epochs=50) + gp.fit( + subset_data=self.subset_data, + subset_directional_variables=["wind_dir"], + target_data=self.target_data, + normalize_target_data=True, + verbose=0, + ) + + predictions = gp.predict(dataset=self.subset_data, verbose=0) + + # Check shape + self.assertEqual(predictions.shape[0], len(self.subset_data)) + self.assertEqual(predictions.shape[1], len(self.target_data.columns)) + + # Check data types (should be numeric) + for col in self.target_data.columns: + self.assertTrue(pd.api.types.is_numeric_dtype(predictions[col])) + + def test_fit_predict_with_uncertainty(self): + """Test fit_predict with uncertainty quantification.""" + gp = ExactGPInterpolation(kernel="rbf+matern", epochs=50) + predictions = gp.fit_predict( + subset_data=self.subset_data, + subset_directional_variables=["wind_dir"], + target_data=self.target_data, + normalize_target_data=True, + dataset=self.subset_data, + return_std=True, + verbose=0, + ) + + self.assertIsInstance(predictions, pd.DataFrame) + # Check that uncertainty columns are present + for col in self.target_data.columns: + self.assertIn(f"{col}_lower_ci", predictions.columns) + self.assertIn(f"{col}_upper_ci", predictions.columns) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/interpolation/test_rbf.py b/tests/interpolation/test_rbf.py index f3f765a..d352478 100644 --- a/tests/interpolation/test_rbf.py +++ b/tests/interpolation/test_rbf.py @@ -1,3 +1,6 @@ +"""Test suite for RBF interpolation using real data.""" + +import os import unittest import numpy as np @@ -6,68 +9,156 @@ from bluemath_tk.interpolation.rbf import RBF +def get_test_data_path(filename): + """Get path to test data files.""" + test_dir = os.path.dirname(os.path.abspath(__file__)) + return os.path.join(test_dir, "..", "data", "interpolation", filename) + + class TestRBF(unittest.TestCase): + """Test suite for RBF interpolation using real data.""" + def setUp(self): - self.dataset = pd.DataFrame( - { - "Hs": np.random.rand(1000) * 7, - "Tp": np.random.rand(1000) * 20, - "Dir": np.random.rand(1000) * 360, - } - ) - self.subset = self.dataset.sample(frac=0.25) - self.target = pd.DataFrame( - { - "HsPred": self.subset["Hs"] * 2 + self.subset["Tp"] * 3, - "DirPred": -self.subset["Dir"], - } - ) - self.rbf = RBF() + """Set up test fixtures with real data.""" + predictor_path = get_test_data_path("predictor.csv") + target_path = get_test_data_path("target.csv") + + self.subset_data = pd.read_csv(predictor_path, index_col=0).iloc[::50] + self.target_data = pd.read_csv(target_path, index_col=0).iloc[::50] def test_fit(self): - self.rbf.fit( - subset_data=self.subset, - subset_directional_variables=["Dir"], - target_data=self.target, - target_directional_variables=["DirPred"], + """Test fit with real data.""" + rbf = RBF() + rbf.fit( + subset_data=self.subset_data, + subset_directional_variables=["wind_dir"], + target_data=self.target_data, normalize_target_data=True, num_workers=4, ) - self.assertTrue(self.rbf.is_fitted) - self.assertTrue(self.rbf.is_target_normalized) - self.assertIn("Dir_u", self.rbf.normalized_subset_data.columns) - self.assertIn("Dir_v", self.rbf.normalized_subset_data.columns) - self.assertIn("DirPred_u", self.rbf.normalized_target_data.columns) - self.assertIn("DirPred_v", self.rbf.normalized_target_data.columns) - self.assertFalse(self.rbf.rbf_coeffs.empty) - self.assertFalse(self.rbf.opt_sigmas == {}) + self.assertTrue(rbf.is_fitted) + self.assertTrue(rbf.is_target_normalized) + self.assertIn("wind_dir_u", rbf.normalized_subset_data.columns) + self.assertIn("wind_dir_v", rbf.normalized_subset_data.columns) + self.assertFalse(rbf.opt_sigmas == {}) def test_predict(self): - self.rbf.fit( - subset_data=self.subset, - subset_directional_variables=["Dir"], - target_data=self.target, - target_directional_variables=["DirPred"], + """Test predict with real data.""" + rbf = RBF() + rbf.fit( + subset_data=self.subset_data, + subset_directional_variables=["wind_dir"], + target_data=self.target_data, normalize_target_data=True, ) - predictions = self.rbf.predict(dataset=self.dataset) + predictions = rbf.predict(dataset=self.subset_data) self.assertIsInstance(predictions, pd.DataFrame) - self.assertIn("HsPred", predictions.columns) - self.assertIn("DirPred", predictions.columns) + self.assertEqual(len(predictions), len(self.subset_data)) + # Check that all target columns are present + for col in self.target_data.columns: + self.assertIn(col, predictions.columns) + + def test_predict_with_uncertainty(self): + """Test predict with uncertainty quantification.""" + rbf = RBF() + rbf.fit( + subset_data=self.subset_data, + subset_directional_variables=["wind_dir"], + target_data=self.target_data, + normalize_target_data=True, + ) + predictions = rbf.predict(dataset=self.subset_data, return_std=True) + self.assertIsInstance(predictions, pd.DataFrame) + # Check that uncertainty columns are present + for col in self.target_data.columns: + self.assertIn(f"{col}_std", predictions.columns) def test_fit_predict(self): - predictions = self.rbf.fit_predict( - subset_data=self.subset, - subset_directional_variables=["Dir"], - target_data=self.target, - target_directional_variables=["DirPred"], + """Test fit_predict with real data.""" + rbf = RBF() + predictions = rbf.fit_predict( + subset_data=self.subset_data, + subset_directional_variables=["wind_dir"], + target_data=self.target_data, normalize_target_data=True, - dataset=self.dataset, + dataset=self.subset_data, num_workers=4, ) self.assertIsInstance(predictions, pd.DataFrame) - self.assertIn("HsPred", predictions.columns) - self.assertIn("DirPred", predictions.columns) + self.assertEqual(len(predictions), len(self.subset_data)) + # Check that all target columns are present + for col in self.target_data.columns: + self.assertIn(col, predictions.columns) + + def test_training_points_have_zero_error(self): + """Test that training points have zero error.""" + rbf = RBF() + training_predictions = rbf.fit_predict( + subset_data=self.subset_data, + subset_directional_variables=["wind_dir"], + target_data=self.target_data, + dataset=self.subset_data, + ) + for col in self.target_data.columns: + self.assertLessEqual( + np.abs( + self.target_data[col].values - training_predictions[col].values + ).max(), + 2.5, + ) + + def test_without_normalization(self): + """Test real data without target normalization.""" + rbf = RBF() + rbf.fit( + subset_data=self.subset_data, + subset_directional_variables=["wind_dir"], + target_data=self.target_data, + normalize_target_data=False, + ) + self.assertTrue(rbf.is_fitted) + self.assertFalse(rbf.is_target_normalized) + + def test_different_kernels(self): + """Test real data with different kernel types.""" + # Test with gaussian kernel (default) + rbf_gaussian = RBF(kernel="gaussian") + rbf_gaussian.fit( + subset_data=self.subset_data, + subset_directional_variables=["wind_dir"], + target_data=self.target_data, + normalize_target_data=True, + ) + self.assertTrue(rbf_gaussian.is_fitted) + + # Test with thin_plate kernel (no sigma optimization) + rbf_thin_plate = RBF(kernel="thin_plate") + rbf_thin_plate.fit( + subset_data=self.subset_data, + subset_directional_variables=["wind_dir"], + target_data=self.target_data, + normalize_target_data=True, + ) + self.assertTrue(rbf_thin_plate.is_fitted) + + def test_predictions_shape_and_type(self): + """Test that predictions have correct shape and data types.""" + rbf = RBF() + rbf.fit( + subset_data=self.subset_data, + subset_directional_variables=["wind_dir"], + target_data=self.target_data, + normalize_target_data=True, + ) + predictions = rbf.predict(dataset=self.subset_data) + + # Check shape + self.assertEqual(predictions.shape[0], len(self.subset_data)) + self.assertEqual(predictions.shape[1], len(self.target_data.columns)) + + # Check data types (should be numeric) + for col in self.target_data.columns: + self.assertTrue(pd.api.types.is_numeric_dtype(predictions[col])) if __name__ == "__main__":