Skip to content

Commit

Permalink
New functions and updated README.md 🚀
Browse files Browse the repository at this point in the history
* R-squared (rsq) with the possibility of adjusting for parameters
	- Unit tests have been made.

* Huber loss (huberloss)
	- Unit tests have been made.

* README.md have been rewritten and the layout have been updated.
	- It needs a logo too.

NOTE: All the functions where inputs are not altered could
benefit from adding a const declaration. This will happen
at a later point.
  • Loading branch information
serkor1 committed Aug 26, 2024
1 parent bb9ac1d commit 25dfbfa
Show file tree
Hide file tree
Showing 10 changed files with 277 additions and 15 deletions.
27 changes: 27 additions & 0 deletions R/RcppExports.R
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
# Generated by using Rcpp::compileAttributes() -> do not edit by hand
# Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393

#' Huber Loss
#'
#' Calculate the huber loss of two <[numeric]> vectors.
#'
#' @param actual A <[numeric]>-vector of length N.
#' @param predicted A <[numeric]>-vector of length N.
#' @param delta A <[numeric]>-vector of length 1. 1 by default.
#'
#' @returns A <[numeric]>-value of length 1.
huberloss <- function(actual, predicted, delta = 1) {
.Call(`_SLmetrics_huberloss`, actual, predicted, delta)
}

#' Mean Absolute Error (MAE)
#'
#' Calculate the MAE of two <[numeric]>-vectors
Expand Down Expand Up @@ -57,3 +70,17 @@ rmsle <- function(actual, predicted) {
.Call(`_SLmetrics_rmsle`, actual, predicted)
}

#' R squared
#'
#' Calculate the R squared of two <[numeric]> vectors.
#'
#' @param actual A <[numeric]>-vector of length N.
#' @param predicted A <[numeric]>-vector of length N.
#' @param k A <[numeric]>-vector of length 1. 0 by default. If k>0
#' the function returns the adjusted R squared.
#'
#' @returns A <[numeric]>-value of length 1.
rsq <- function(actual, predicted, k = 0) {
.Call(`_SLmetrics_rsq`, actual, predicted, k)
}

13 changes: 5 additions & 8 deletions README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ knitr::opts_chunk$set(
[![Codecov test coverage](https://codecov.io/gh/serkor1/MLmetrics/graph/badge.svg)](https://app.codecov.io/gh/serkor1/MLmetrics)
<!-- badges: end -->

{SLmetrics} is a collection of performance evaluation metrics for regression and classification models written in c++ and [{Rcpp}](https://github.com/RcppCore/Rcpp)

## Example: Linear Regression
{SLmetrics} is a collection of (lightning fast) performance evaluation metrics for regression and classification models written in c++ and [{Rcpp}](https://github.com/RcppCore/Rcpp). It's like using a supercharged yardstick to measure model performance, without the risk of soft to super-hard deprecations.

## :information_source: Basic usage
```{r}
# 0) load {SLmetrics}
library(SLmetrics)
Expand All @@ -36,13 +35,11 @@ model <- lm(
# 2) evaluate RMSE
rmse(
actual = fitted(model),
predicted = predict(model)
actual = mtcars$mpg,
predicted = fitted(model)
)
```



</details>

## :information_source: Installation

Expand Down
18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@
coverage](https://codecov.io/gh/serkor1/MLmetrics/graph/badge.svg)](https://app.codecov.io/gh/serkor1/MLmetrics)
<!-- badges: end -->

{SLmetrics} is a collection of performance evaluation metrics for
regression and classification models written in c++ and
[{Rcpp}](https://github.com/RcppCore/Rcpp)
{SLmetrics} is a collection of (lightning fast) performance evaluation
metrics for regression and classification models written in c++ and
[{Rcpp}](https://github.com/RcppCore/Rcpp). It’s like using a
supercharged yardstick to measure model performance, without the risk of
soft to super-hard deprecations.

## Example: Linear Regression
## :information_source: Basic usage

``` r
# 0) load {SLmetrics}
Expand All @@ -28,12 +30,14 @@ model <- lm(

# 2) evaluate RMSE
rmse(
actual = fitted(model),
predicted = predict(model)
actual = mtcars$mpg,
predicted = fitted(model)
)
#> [1] 1.385601e-14
#> [1] 2.146905
```

</details>

## :information_source: Installation

### :shield: Stable version
Expand Down
21 changes: 21 additions & 0 deletions man/huberloss.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions man/rsq.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions src/RcppExports.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,19 @@ Rcpp::Rostream<true>& Rcpp::Rcout = Rcpp::Rcpp_cout_get();
Rcpp::Rostream<false>& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get();
#endif

// huberloss
double huberloss(const NumericVector& actual, const NumericVector& predicted, const double delta);
RcppExport SEXP _SLmetrics_huberloss(SEXP actualSEXP, SEXP predictedSEXP, SEXP deltaSEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< const NumericVector& >::type actual(actualSEXP);
Rcpp::traits::input_parameter< const NumericVector& >::type predicted(predictedSEXP);
Rcpp::traits::input_parameter< const double >::type delta(deltaSEXP);
rcpp_result_gen = Rcpp::wrap(huberloss(actual, predicted, delta));
return rcpp_result_gen;
END_RCPP
}
// mae
double mae(const Rcpp::NumericVector& actual, const Rcpp::NumericVector& predicted);
RcppExport SEXP _SLmetrics_mae(SEXP actualSEXP, SEXP predictedSEXP) {
Expand Down Expand Up @@ -58,12 +71,27 @@ BEGIN_RCPP
return rcpp_result_gen;
END_RCPP
}
// rsq
double rsq(const NumericVector& actual, const NumericVector& predicted, const double k);
RcppExport SEXP _SLmetrics_rsq(SEXP actualSEXP, SEXP predictedSEXP, SEXP kSEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< const NumericVector& >::type actual(actualSEXP);
Rcpp::traits::input_parameter< const NumericVector& >::type predicted(predictedSEXP);
Rcpp::traits::input_parameter< const double >::type k(kSEXP);
rcpp_result_gen = Rcpp::wrap(rsq(actual, predicted, k));
return rcpp_result_gen;
END_RCPP
}

static const R_CallMethodDef CallEntries[] = {
{"_SLmetrics_huberloss", (DL_FUNC) &_SLmetrics_huberloss, 3},
{"_SLmetrics_mae", (DL_FUNC) &_SLmetrics_mae, 2},
{"_SLmetrics_mse", (DL_FUNC) &_SLmetrics_mse, 2},
{"_SLmetrics_rmse", (DL_FUNC) &_SLmetrics_rmse, 2},
{"_SLmetrics_rmsle", (DL_FUNC) &_SLmetrics_rmsle, 2},
{"_SLmetrics_rsq", (DL_FUNC) &_SLmetrics_rsq, 3},
{NULL, NULL, 0}
};

Expand Down
39 changes: 39 additions & 0 deletions src/regression_HUBER.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include <Rcpp.h>
using namespace Rcpp;

//' Huber Loss
//'
//' Calculate the huber loss of two <[numeric]> vectors.
//'
//' @param actual A <[numeric]>-vector of length N.
//' @param predicted A <[numeric]>-vector of length N.
//' @param delta A <[numeric]>-vector of length 1. 1 by default.
//'
//' @returns A <[numeric]>-value of length 1.
// [[Rcpp::export]]
double huberloss(
const NumericVector& actual,
const NumericVector& predicted,
const double delta = 1) {

// Get the size of the vectors
const std::size_t n = actual.size();

// Initialize the output variable
double output = 0.0;

// Iterate over the vectors and compute the Huber loss
for (std::size_t i = 0; i < n; ++i) {
double diff = actual[i] - predicted[i];
double abs_diff = std::abs(diff);

if (abs_diff <= delta) {
output += 0.5 * diff * diff;
} else {
output += delta * (abs_diff - 0.5 * delta);
}
}

// Return the mean Huber loss
return output / n;
}
40 changes: 40 additions & 0 deletions src/regression_RSQ.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include <Rcpp.h>
using namespace Rcpp;

//' R squared
//'
//' Calculate the R squared of two <[numeric]> vectors.
//'
//' @param actual A <[numeric]>-vector of length N.
//' @param predicted A <[numeric]>-vector of length N.
//' @param k A <[numeric]>-vector of length 1. 0 by default. If k>0
//' the function returns the adjusted R squared.
//'
//' @returns A <[numeric]>-value of length 1.
// [[Rcpp::export]]
double rsq(
const NumericVector& actual,
const NumericVector& predicted,
const double k = 0) {

// Get the size of the vectors
const std::size_t n = actual.size();

// Calculate the mean of actual values
double mean_actual = std::accumulate(actual.begin(), actual.end(), 0.0) / n;

// Calculate SSE and SSR
double SSE = 0.0;
double SST = 0.0;

for (std::size_t i = 0; i < n; ++i) {
const double actual_val = actual[i];
const double predicted_val = predicted[i];

SSE += (actual_val - predicted_val) * (actual_val - predicted_val);
SST += (actual_val - mean_actual) * (actual_val - mean_actual);
}

// Calculate R-squared
return 1.0 - (SSE / SST) * ((n - 1))/(n - (k + 1));
}
43 changes: 43 additions & 0 deletions tests/testthat/test-huber.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# script: Huber Loss test
# author: Serkan Korkmaz, [email protected]
# date: 2024-08-26
# objective: Test that the huber loss function
# returns a non-zero value
# script start;


testthat::test_that(
desc = "`huberloss`-function returns non-zero postive values",
code = {

# 0) generate values
# from a normal distribution
actual <- rnorm(
n = 1e2
)

predicted <- actual + rnorm(
n = 1e2
)


# 1) calculate the
# rsq using rsq()-function
output <- testthat::expect_no_condition(
huberloss(
predicted,
actual,
delta = 5
)
)

# 2) test that the value
# is greater than 0
testthat::expect_true(
output > 0
)

}
)

# script end;
41 changes: 41 additions & 0 deletions tests/testthat/test-rsq.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# script: RSQ Tests
# author: Serkan Korkmaz, [email protected]
# date: 2024-08-26
# objective: Test that rsq returns a non-zero
# positive value for all values passed into it
# script start;

testthat::test_that(
desc = "`rsq`-function returns non-zero postive values",
code = {

# 0) generate values
# from a normal distribution
actual <- rnorm(
n = 1e2
)

predicted <- actual + rnorm(
n = 1e2
)


# 1) calculate the
# rsq using rsq()-function
output <- testthat::expect_no_condition(
rsq(
predicted,
actual
)
)

# 2) test that the value
# is greater than 0
testthat::expect_true(
output > 0
)

}
)

# script end;

0 comments on commit 25dfbfa

Please sign in to comment.