10#include "observation_weights.h"
11#include <Eigen/SparseCore>
23 explicit WeightRangeSums(
const Eigen::VectorXd& weights)
28 double sum(Eigen::Index begin, Eigen::Index end);
31 const Eigen::VectorXd& weights;
35template<
typename T,
typename F>
37forEachWeightedColumnValue(
const Eigen::MatrixBase<T>& x,
38 const Eigen::VectorXd& weights,
44 for (Eigen::Index i = 0; i < x.rows(); ++i) {
45 if (weights(i) > 0.0) {
46 visit(x(i, column), weights(i));
51template<
typename T,
typename F>
53forEachWeightedColumnValue(
const Eigen::SparseMatrixBase<T>& x,
54 const Eigen::VectorXd& weights,
56 const Eigen::Index support,
57 WeightRangeSums* range_sums,
60 Eigen::Index stored_rows = 0;
61 for (
typename T::InnerIterator it(x.derived(), column); it; ++it) {
62 if (weights(it.row()) > 0.0) {
63 visit(it.value(), weights(it.row()));
69 if (stored_rows < support) {
70 double implicit_weight = 0.0;
72 Eigen::Index next_row = 0;
73 for (
typename T::InnerIterator it(x.derived(), column); it; ++it) {
74 implicit_weight += range_sums->sum(next_row, it.row());
75 next_row = it.row() + 1;
77 implicit_weight += range_sums->sum(next_row, weights.size());
79 visit(0.0, implicit_weight);
85weightedFeatureCenters(
const T& x,
86 const std::string& type,
87 const Eigen::VectorXd& weights)
89 Eigen::VectorXd centers(x.cols());
90 const double total = weights.sum();
91 const Eigen::Index support = positiveWeightCount(weights);
92 for (Eigen::Index j = 0; j < x.cols(); ++j) {
94 type ==
"min" ? std::numeric_limits<double>::infinity() : 0.0;
95 forEachWeightedColumnValue(
96 x, weights, j, support,
nullptr, [&](
double entry,
double weight) {
98 value = std::min(value, entry);
100 value += (weight / total) * entry;
110weightedFeatureScales(
const T& x,
111 const std::string& type,
112 const Eigen::VectorXd& weights)
114 Eigen::VectorXd scales(x.cols());
115 Eigen::VectorXd
means;
117 means = weightedFeatureCenters(x,
"mean", weights);
119 const double total = weights.sum();
120 const Eigen::Index support = positiveWeightCount(weights);
121 WeightRangeSums range_sums(weights);
122 for (Eigen::Index j = 0; j < x.cols(); ++j) {
124 double minimum = std::numeric_limits<double>::infinity();
125 double maximum = -std::numeric_limits<double>::infinity();
126 forEachWeightedColumnValue(
131 type ==
"sd" ? &range_sums :
nullptr,
132 [&](
double entry,
double weight) {
133 if (type ==
"range") {
134 minimum = std::min(minimum, entry);
135 maximum = std::max(maximum, entry);
136 }
else if (type ==
"max_abs") {
137 value = std::max(value, std::abs(entry));
138 }
else if (type ==
"l1") {
139 value += (weight / total) * std::abs(entry);
141 double centered = entry;
143 minimum = std::min(minimum, entry);
144 maximum = std::max(maximum, entry);
145 centered -=
means(j);
147 value = std::hypot(value, std::sqrt(weight / total) * centered);
150 if (type ==
"range") {
151 value = maximum - minimum;
152 }
else if (type ==
"sd" && minimum == maximum) {
155 }
else if (type ==
"l1") {
157 }
else if (type ==
"l2") {
158 value *= std::sqrt(support);
188 const std::string& type,
189 const Eigen::VectorXd& observation_weights = Eigen::VectorXd())
192 Eigen::VectorXd weights;
193 if (observation_weights.size() > 0) {
195 detail::normalizeObservationWeights(observation_weights, x.rows());
196 if (detail::uniformObservationWeights(weights)) {
201 if (type ==
"manual") {
202 if (x_centers.size() != p) {
203 throw std::invalid_argument(
"Invalid dimensions in centers");
206 if (!x_centers.allFinite()) {
207 throw std::invalid_argument(
"Centers must be finite");
210 }
else if (weights.size() > 0 && (type ==
"mean" || type ==
"min")) {
211 x_centers = detail::weightedFeatureCenters(x, type, weights);
212 }
else if (type ==
"mean") {
213 x_centers =
means(x);
214 }
else if (type ==
"min") {
216 }
else if (type !=
"none") {
217 throw std::invalid_argument(
"Invalid centering type");
244 const std::string& type,
245 const Eigen::VectorXd& observation_weights = Eigen::VectorXd())
248 Eigen::VectorXd weights;
249 if (observation_weights.size() > 0) {
251 detail::normalizeObservationWeights(observation_weights, x.rows());
252 if (detail::uniformObservationWeights(weights)) {
257 if (type ==
"manual") {
258 if (x_scales.size() != p) {
259 throw std::invalid_argument(
"Invalid dimensions in scales");
261 if (!x_scales.allFinite()) {
262 throw std::invalid_argument(
"Scales must be finite");
264 }
else if (weights.size() > 0 &&
265 (type ==
"sd" || type ==
"l1" || type ==
"l2" ||
266 type ==
"max_abs" || type ==
"range")) {
267 x_scales = detail::weightedFeatureScales(x, type, weights);
268 }
else if (type ==
"sd") {
270 }
else if (type ==
"l1") {
272 }
else if (type ==
"l2") {
274 }
else if (type ==
"max_abs") {
276 }
else if (type ==
"range") {
278 }
else if (type !=
"none") {
279 throw std::invalid_argument(
"Invalid scaling type");
308 Eigen::VectorXd& x_centers,
309 Eigen::VectorXd& x_scales,
310 const std::string& centering_type,
311 const std::string& scaling_type,
313 const Eigen::VectorXd& observation_weights = Eigen::VectorXd())
315 const int p = x.cols();
317 computeCenters(x_centers, x, centering_type, observation_weights);
318 computeScales(x_scales, x, scaling_type, observation_weights);
322 if (scaling_type !=
"none" && scaling_type !=
"manual") {
323 for (
int j = 0; j < p; ++j) {
324 if (std::abs(x_scales(j)) == 0.0) {
330 bool center = centering_type !=
"none";
331 bool scale = scaling_type !=
"none";
332 bool center_jit = center && !modify_x;
333 bool scale_jit = scale && !modify_x;
337 if (center_jit && scale_jit) {
339 }
else if (center_jit) {
341 }
else if (scale_jit) {
347 if (modify_x && (center || scale)) {
348 const bool ignored_rows = observation_weights.size() > 0 &&
349 (observation_weights.array() == 0.0).any();
351 for (
int j = 0; j < p; ++j) {
352 for (Eigen::Index i = 0; i < x.rows(); ++i) {
354 if (observation_weights(i) == 0.0) {
359 x(i, j) -= x_centers(j);
362 x(i, j) /= x_scales(j);
367 for (
int j = 0; j < p; ++j) {
369 x.col(j).array() -= x_centers(j);
372 x.col(j).array() /= x_scales(j);
378 return jit_normalization;
406 Eigen::VectorXd& x_centers,
407 Eigen::VectorXd& x_scales,
408 const std::string& centering_type,
409 const std::string& scaling_type,
411 const Eigen::VectorXd& observation_weights = Eigen::VectorXd())
413 computeCenters(x_centers, x, centering_type, observation_weights);
414 computeScales(x_scales, x, scaling_type, observation_weights);
418 const int p = x.cols();
419 if (scaling_type !=
"none" && scaling_type !=
"manual") {
420 for (
int j = 0; j < p; ++j) {
421 if (std::abs(x_scales(j)) == 0.0) {
427 bool center = centering_type !=
"none";
428 bool scale = scaling_type !=
"none";
429 bool center_jit = center;
430 bool scale_jit = scale;
434 if (center_jit && scale_jit) {
436 }
else if (center_jit) {
438 }
else if (scale_jit) {
453 return jit_normalization;
476std::tuple<Eigen::VectorXd, Eigen::MatrixXd>
478 const Eigen::SparseMatrix<double>& beta,
479 const Eigen::VectorXd& x_centers,
480 const Eigen::VectorXd& x_scales,
481 const bool intercept);
Enums to control predictor standardization behavior.
Mathematical support functions for the slope package.
Namespace containing SLOPE regression implementation.
Eigen::VectorXd means(const Eigen::SparseMatrixBase< T > &x)
Computes the arithmetic mean for each column of a sparse matrix.
Eigen::VectorXd l1Norms(const T &x)
Computes the L1 (Manhattan) norms for each column of a matrix.
JitNormalization
Enums to control predictor standardization behavior.
@ None
No JIT normalization.
void computeCenters(Eigen::VectorXd &x_centers, const T &x, const std::string &type, const Eigen::VectorXd &observation_weights=Eigen::VectorXd())
Eigen::VectorXd ranges(const Eigen::SparseMatrixBase< T > &x)
Computes the range (max - min) for each column of a matrix.
std::tuple< Eigen::VectorXd, Eigen::MatrixXd > rescaleCoefficients(const Eigen::VectorXd &beta0, const Eigen::SparseMatrix< double > &beta, const Eigen::VectorXd &x_centers, const Eigen::VectorXd &x_scales, const bool intercept)
Rescales the coefficients using the given parameters.
void computeScales(Eigen::VectorXd &x_scales, const T &x, const std::string &type, const Eigen::VectorXd &observation_weights=Eigen::VectorXd())
Eigen::VectorXd mins(const Eigen::SparseMatrixBase< T > &x)
Computes the minimum value for each column of a sparse matrix.
JitNormalization normalize(Eigen::MatrixBase< T > &x, Eigen::VectorXd &x_centers, Eigen::VectorXd &x_scales, const std::string ¢ering_type, const std::string &scaling_type, const bool modify_x, const Eigen::VectorXd &observation_weights=Eigen::VectorXd())
Eigen::VectorXd stdDevs(const Eigen::SparseMatrixBase< T > &x)
Computes the standard deviation for each column of a matrix.
Eigen::VectorXd l2Norms(const Eigen::SparseMatrixBase< T > &x)
Computes the L2 (Euclidean) norms for each column of a sparse matrix.
Eigen::VectorXd maxAbs(const Eigen::SparseMatrixBase< T > &x)
Computes the maximum absolute value for each column of a matrix.