diff --git a/.Rbuildignore b/.Rbuildignore index 8be7dfa..01ddd28 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -15,3 +15,6 @@ ^vignettes/articles/\.quarto$ ^vignettes/articles/*_files$ ^vignettes/articles$ +^codemeta\.json$ +^CODE_OF_CONDUCT\.md$ +^src/.*\.o$ diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..f803f88 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,47 @@ +# Contributing to tidyhydro + +This outlines how to propose a change to tidyhydro. +For a detailed discussion on contributing to this and other tidyverse packages, please see the [development contributing guide](https://rstd.io/tidy-contrib) and our [code review principles](https://code-review.tidyverse.org/). + +## Fixing typos + +You can fix typos, spelling mistakes, or grammatical errors in the documentation directly using the GitHub web interface, as long as the changes are made in the _source_ file. +This generally means you'll need to edit [roxygen2 comments](https://roxygen2.r-lib.org/articles/roxygen2.html) in an `.R`, not a `.Rd` file. +You can find the `.R` file that generates the `.Rd` by reading the comment in the first line. + +## Bigger changes + +If you want to make a bigger change, it's a good idea to first file an issue and make sure someone from the team agrees that it’s needed. +If you’ve found a bug, please file an issue that illustrates the bug with a minimal +[reprex](https://www.tidyverse.org/help/#reprex) (this will also help you write a unit test, if needed). +See our guide on [how to create a great issue](https://code-review.tidyverse.org/issues/) for more advice. + +### Pull request process + +* Fork the package and clone onto your computer. If you haven't done this before, we recommend using `usethis::create_from_github("atsyplenkov/tidyhydro", fork = TRUE)`. + +* Install all development dependencies with `devtools::install_dev_deps()`, and then make sure the package passes R CMD check by running `devtools::check()`. + If R CMD check doesn't pass cleanly, it's a good idea to ask for help before continuing. +* Create a Git branch for your pull request (PR). We recommend using `usethis::pr_init("brief-description-of-change")`. + +* Make your changes, commit to git, and then create a PR by running `usethis::pr_push()`, and following the prompts in your browser. + The title of your PR should briefly describe the change. + The body of your PR should contain `Fixes #issue-number`. + +* For user-facing changes, add a bullet to the top of `NEWS.md` (i.e. just below the first header). Follow the style described in . + +### Code style + +* New code should follow the tidyverse [style guide](https://style.tidyverse.org). + You can use the [styler](https://CRAN.R-project.org/package=styler) package to apply these styles, but please don't restyle code that has nothing to do with your PR. + +* We use [roxygen2](https://cran.r-project.org/package=roxygen2), with [Markdown syntax](https://cran.r-project.org/web/packages/roxygen2/vignettes/rd-formatting.html), for documentation. + +* We use [testthat](https://cran.r-project.org/package=testthat) for unit tests. + Contributions with test cases included are easier to accept. + +## Code of Conduct + +Please note that the tidyhydro project is released with a +[Contributor Code of Conduct](CODE_OF_CONDUCT.md). By contributing to this +project you agree to abide by its terms. diff --git a/.github/workflows/check-no-suggests.yaml b/.github/workflows/check-no-suggests.yaml index 3775153..bc93129 100644 --- a/.github/workflows/check-no-suggests.yaml +++ b/.github/workflows/check-no-suggests.yaml @@ -1,59 +1,59 @@ -# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples -# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help -# -# NOTE: This workflow only directly installs "hard" dependencies, i.e. Depends, -# Imports, and LinkingTo dependencies. Notably, Suggests dependencies are never -# installed, with the exception of testthat, knitr, and rmarkdown. The cache is -# never used to avoid accidentally restoring a cache containing a suggested -# dependency. -on: - push: - branches: master - pull_request: - -name: check-no-suggests.yaml - -permissions: read-all - -jobs: - check-no-suggests: - runs-on: ${{ matrix.config.os }} - - name: ${{ matrix.config.os }} (${{ matrix.config.r }}) - - strategy: - fail-fast: false - matrix: - config: - - {os: ubuntu-latest, r: 'release'} - - env: - GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - R_KEEP_PKG_SOURCE: yes - - steps: - - uses: actions/checkout@v4 - - - uses: r-lib/actions/setup-pandoc@v2 - - - uses: r-lib/actions/setup-r@v2 - with: - r-version: ${{ matrix.config.r }} - http-user-agent: ${{ matrix.config.http-user-agent }} - use-public-rspm: true - - - uses: r-lib/actions/setup-r-dependencies@v2 - with: - dependencies: '"hard"' - cache: false - extra-packages: | - any::rcmdcheck - any::testthat - any::knitr - any::rmarkdown - needs: check - - - uses: r-lib/actions/check-r-package@v2 - with: - upload-snapshots: true +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help +# +# NOTE: This workflow only directly installs "hard" dependencies, i.e. Depends, +# Imports, and LinkingTo dependencies. Notably, Suggests dependencies are never +# installed, with the exception of testthat, knitr, and rmarkdown. The cache is +# never used to avoid accidentally restoring a cache containing a suggested +# dependency. +on: + push: + branches: master + pull_request: + +name: check-no-suggests.yaml + +permissions: read-all + +jobs: + check-no-suggests: + runs-on: ${{ matrix.config.os }} + + name: ${{ matrix.config.os }} (${{ matrix.config.r }}) + + strategy: + fail-fast: false + matrix: + config: + - {os: ubuntu-latest, r: 'release'} + + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + R_KEEP_PKG_SOURCE: yes + + steps: + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-pandoc@v2 + + - uses: r-lib/actions/setup-r@v2 + with: + r-version: ${{ matrix.config.r }} + http-user-agent: ${{ matrix.config.http-user-agent }} + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + dependencies: '"hard"' + cache: false + extra-packages: | + any::rcmdcheck + any::testthat + any::knitr + any::rmarkdown + needs: check + + - uses: r-lib/actions/check-r-package@v2 + with: + upload-snapshots: true build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' \ No newline at end of file diff --git a/.github/workflows/check-r-pkg.yaml b/.github/workflows/check-r-pkg.yaml index 28c6b92..4fffb78 100644 --- a/.github/workflows/check-r-pkg.yaml +++ b/.github/workflows/check-r-pkg.yaml @@ -1,50 +1,50 @@ -# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples -# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help -on: - push: - branches: master - pull_request: - branches: master - -name: R-CMD-check - -jobs: - R-CMD-check: - runs-on: ${{ matrix.config.os }} - - name: ${{ matrix.config.os }} (${{ matrix.config.r }}) - - strategy: - fail-fast: false - matrix: - config: - - {os: macos-latest, r: 'release'} - - {os: windows-latest, r: 'release'} - - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} - - {os: ubuntu-latest, r: 'release'} - - {os: ubuntu-latest, r: 'oldrel-1'} - - env: - GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - R_KEEP_PKG_SOURCE: yes - - steps: - - uses: actions/checkout@v4 - - - uses: r-lib/actions/setup-pandoc@v2 - - - uses: r-lib/actions/setup-r@v2 - with: - r-version: ${{ matrix.config.r }} - http-user-agent: ${{ matrix.config.http-user-agent }} - use-public-rspm: true - - - uses: r-lib/actions/setup-r-dependencies@v2 - with: - extra-packages: any::rcmdcheck - needs: check - - - uses: r-lib/actions/check-r-package@v2 - with: - upload-snapshots: true - build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help +on: + push: + branches: master] + pull_request: + branches: master + +name: R-CMD-check + +jobs: + R-CMD-check: + runs-on: ${{ matrix.config.os }} + + name: ${{ matrix.config.os }} (${{ matrix.config.r }}) + + strategy: + fail-fast: false + matrix: + config: + - {os: macos-latest, r: 'release'} + - {os: windows-latest, r: 'release'} + - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} + - {os: ubuntu-latest, r: 'release'} + - {os: ubuntu-latest, r: 'oldrel-1'} + + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + R_KEEP_PKG_SOURCE: yes + + steps: + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-pandoc@v2 + + - uses: r-lib/actions/setup-r@v2 + with: + r-version: ${{ matrix.config.r }} + http-user-agent: ${{ matrix.config.http-user-agent }} + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::rcmdcheck + needs: check + + - uses: r-lib/actions/check-r-package@v2 + with: + upload-snapshots: true + build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index 8bd57fa..722375c 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -1,49 +1,49 @@ -# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples -# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help -on: - push: - branches: master - pull_request: - release: - types: [published] - workflow_dispatch: - -name: pkgdown.yaml - -permissions: read-all - -jobs: - pkgdown: - runs-on: ubuntu-latest - # Only restrict concurrency for non-PR jobs - concurrency: - group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} - env: - GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - permissions: - contents: write - steps: - - uses: actions/checkout@v4 - - - uses: r-lib/actions/setup-pandoc@v2 - - - uses: r-lib/actions/setup-r@v2 - with: - use-public-rspm: true - - - uses: r-lib/actions/setup-r-dependencies@v2 - with: - extra-packages: any::pkgdown, local::. - needs: website - - - name: Build site - run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) - shell: Rscript {0} - - - name: Deploy to GitHub pages 🚀 - if: github.event_name != 'pull_request' - uses: JamesIves/github-pages-deploy-action@v4.5.0 - with: - clean: false - branch: gh-pages - folder: docs +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help +on: + push: + branches: master + pull_request: + release: + types: [published] + workflow_dispatch: + +name: pkgdown.yaml + +permissions: read-all + +jobs: + pkgdown: + runs-on: ubuntu-latest + # Only restrict concurrency for non-PR jobs + concurrency: + group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-pandoc@v2 + + - uses: r-lib/actions/setup-r@v2 + with: + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::pkgdown, local::. + needs: website + + - name: Build site + run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) + shell: Rscript {0} + + - name: Deploy to GitHub pages 🚀 + if: github.event_name != 'pull_request' + uses: JamesIves/github-pages-deploy-action@v4.5.0 + with: + clean: false + branch: gh-pages + folder: docs diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml index b69edb7..3b95185 100644 --- a/.github/workflows/test-coverage.yaml +++ b/.github/workflows/test-coverage.yaml @@ -1,61 +1,61 @@ -# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples -# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help -on: - push: - branches: master - pull_request: - branches: master - -name: test-coverage.yaml - -permissions: read-all - -jobs: - test-coverage: - runs-on: ubuntu-latest - env: - GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - - steps: - - uses: actions/checkout@v4 - - - uses: r-lib/actions/setup-r@v2 - with: - use-public-rspm: true - - - uses: r-lib/actions/setup-r-dependencies@v2 - with: - extra-packages: any::covr, any::xml2 - needs: coverage - - - name: Test coverage - run: | - cov <- covr::package_coverage( - quiet = FALSE, - clean = FALSE, - install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") - ) - covr::to_cobertura(cov) - shell: Rscript {0} - - - uses: codecov/codecov-action@v4 - with: - fail_ci_if_error: ${{ github.event_name != 'pull_request' && true || false }} - file: ./cobertura.xml - plugin: noop - disable_search: true - token: ${{ secrets.CODECOV_TOKEN }} - - - name: Show testthat output - if: always() - run: | - ## -------------------------------------------------------------------- - find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true - shell: bash - - - name: Upload test results - if: failure() - uses: actions/upload-artifact@v4 - with: - name: coverage-test-failures +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help +on: + push: + branches: master + pull_request: + branches: master + +name: test-coverage.yaml + +permissions: read-all + +jobs: + test-coverage: + runs-on: ubuntu-latest + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + + steps: + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-r@v2 + with: + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::covr, any::xml2 + needs: coverage + + - name: Test coverage + run: | + cov <- covr::package_coverage( + quiet = FALSE, + clean = FALSE, + install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") + ) + covr::to_cobertura(cov) + shell: Rscript {0} + + - uses: codecov/codecov-action@v4 + with: + fail_ci_if_error: ${{ github.event_name != 'pull_request' && true || false }} + file: ./cobertura.xml + plugin: noop + disable_search: true + token: ${{ secrets.CODECOV_TOKEN }} + + - name: Show testthat output + if: always() + run: | + ## -------------------------------------------------------------------- + find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true + shell: bash + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v4 + with: + name: coverage-test-failures path: ${{ runner.temp }}/package \ No newline at end of file diff --git a/.gitignore b/.gitignore index acb77db..e265460 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ cran-comments.md CRAN-SUBMISSION docs **/.quarto/ +*.o +*.so \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..80aa572 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,126 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at atsyplenkov@fastmail.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][https://github.com/mozilla/inclusion]. + +For answers to common questions about this code of conduct, see the FAQ at +. Translations are available at . + +[homepage]: https://www.contributor-covenant.org diff --git a/NEWS.md b/NEWS.md index cce08ef..6015990 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,44 +1,44 @@ -# tidyhydro 0.1.1 - -## New features - -- Added support for modified Kling-Gupta Efficiency (`kge2012`), aka $KGE'$ ([#8](https://github.com/atsyplenkov/tidyhydro/issues/8)) -- Added vignettes and website ([#14](https://github.com/atsyplenkov/tidyhydro/issues/14)) - -## Bug fixes - -- Improved documenation by switching from `\url` to `\doi` -- Removed unicode characters α, β - -## Miscellaneous -- Created website with vignettes (https://atsyplenkov.github.io/tidyhydro) - -# tidyhydro 0.1.0 - -## New features - -- Added Kling-Gupta Efficiency (`kge`). -- Added Mean Squared Error (`mse`). -- Added example dataset (`avacha`) with observed and modelled daily water discharge measurements in cubic meters per second ([#6](https://github.com/atsyplenkov/tidyhydro/issues/6)). - -## Bug fixes - -- `nse` with `na_rm = TRUE` flag and missing values present in both simulated and observed time series now returns the same results as `hydroGOF::NSE()`. Previously, it did not skip missing values in the observed time series. - -## Miscellaneous - -- Introduced parameter testing via `quickcheck` ([#3](https://github.com/atsyplenkov/tidyhydro/issues/3)). Estimated metrics are now validated against their implementations in the `hydroGOF` package. -- Removed unnecessary dependencies ([#2](https://github.com/atsyplenkov/tidyhydro/issues/2)). -- Updated documentation with equations and references. - -# tidyhydro 0.0.4 - -## New features - -- Added Standard Factorial Error (`sfe`). - -# tidyhydro 0.0.3 - -## New features - +# tidyhydro 0.1.1 + +## New features + +- Added support for modified Kling-Gupta Efficiency (`kge2012`), aka $KGE'$ ([#8](https://github.com/atsyplenkov/tidyhydro/issues/8)) +- Added vignettes and website ([#14](https://github.com/atsyplenkov/tidyhydro/issues/14)) + +## Bug fixes + +- Improved documenation by switching from `\url` to `\doi` +- Removed unicode characters α, β + +## Miscellaneous +- Created website with vignettes (https://atsyplenkov.github.io/tidyhydro) + +# tidyhydro 0.1.0 + +## New features + +- Added Kling-Gupta Efficiency (`kge`). +- Added Mean Squared Error (`mse`). +- Added example dataset (`avacha`) with observed and modelled daily water discharge measurements in cubic meters per second ([#6](https://github.com/atsyplenkov/tidyhydro/issues/6)). + +## Bug fixes + +- `nse` with `na_rm = TRUE` flag and missing values present in both simulated and observed time series now returns the same results as `hydroGOF::NSE()`. Previously, it did not skip missing values in the observed time series. + +## Miscellaneous + +- Introduced parameter testing via `quickcheck` ([#3](https://github.com/atsyplenkov/tidyhydro/issues/3)). Estimated metrics are now validated against their implementations in the `hydroGOF` package. +- Removed unnecessary dependencies ([#2](https://github.com/atsyplenkov/tidyhydro/issues/2)). +- Updated documentation with equations and references. + +# tidyhydro 0.0.4 + +## New features + +- Added Standard Factorial Error (`sfe`). + +# tidyhydro 0.0.3 + +## New features + - Added PRediction Error Sum of Squares (`press`). \ No newline at end of file diff --git a/R/RcppExports.R b/R/RcppExports.R index ec7d1ac..56c2f72 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -1,27 +1,27 @@ -# Generated by using Rcpp::compileAttributes() -> do not edit by hand -# Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 - -kge_cpp <- function(obs, sim, na_rm = TRUE, version = "2012") { - .Call(`_tidyhydro_kge_cpp`, obs, sim, na_rm, version) -} - -mse_cpp <- function(truth, estimate, na_rm = TRUE) { - .Call(`_tidyhydro_mse_cpp`, truth, estimate, na_rm) -} - -nse_cpp <- function(truth, estimate, performance = FALSE, na_rm = TRUE) { - .Call(`_tidyhydro_nse_cpp`, truth, estimate, performance, na_rm) -} - -pbias_cpp <- function(truth, estimate, performance = FALSE, na_rm = TRUE) { - .Call(`_tidyhydro_pbias_cpp`, truth, estimate, performance, na_rm) -} - -press_cpp <- function(truth, estimate, na_rm = TRUE) { - .Call(`_tidyhydro_press_cpp`, truth, estimate, na_rm) -} - -sfe_cpp <- function(truth, estimate, na_rm = TRUE) { - .Call(`_tidyhydro_sfe_cpp`, truth, estimate, na_rm) -} - +# Generated by using Rcpp::compileAttributes() -> do not edit by hand +# Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 + +kge_cpp <- function(obs, sim, na_rm = TRUE, version = "2012") { + .Call(`_tidyhydro_kge_cpp`, obs, sim, na_rm, version) +} + +mse_cpp <- function(truth, estimate, na_rm = TRUE) { + .Call(`_tidyhydro_mse_cpp`, truth, estimate, na_rm) +} + +nse_cpp <- function(truth, estimate, performance = FALSE, na_rm = TRUE) { + .Call(`_tidyhydro_nse_cpp`, truth, estimate, performance, na_rm) +} + +pbias_cpp <- function(truth, estimate, performance = FALSE, na_rm = TRUE) { + .Call(`_tidyhydro_pbias_cpp`, truth, estimate, performance, na_rm) +} + +press_cpp <- function(truth, estimate, na_rm = TRUE) { + .Call(`_tidyhydro_press_cpp`, truth, estimate, na_rm) +} + +sfe_cpp <- function(truth, estimate, na_rm = TRUE) { + .Call(`_tidyhydro_sfe_cpp`, truth, estimate, na_rm) +} + diff --git a/R/data.R b/R/data.R index d246d03..87c7ca7 100644 --- a/R/data.R +++ b/R/data.R @@ -1,26 +1,26 @@ -#' Mean Daily Water Discharge At Avacha River (Elizovo City) -#' -#' @details These data contain the measured (`obs`) mean daily water discharge -#' values (in \eqn{m^3/s}) at the Avacha River -- Elizovo City state gauging -#' station for the 2022 calendar year. They are accompanied by the GloFAS v4.0 -#' reanalysis water discharge values for the last 24 hours (`sim`), derived -#' from -#' \url{https://ewds.climate.copernicus.eu/datasets/cems-glofas-historical}. -#' -#' Read more about GloFAS Water Discharge reanalysis -- -#' \url{https://confluence.ecmwf.int/display/CEMS/GloFAS+v4.0} -#' -#' @name avacha -#' @aliases avacha -#' @docType data -#' @return \item{avacha}{a data frame} -#' -#' @source -#' * \url{https://gmvo.skniivh.ru/} -#' * \url{https://ewds.climate.copernicus.eu/datasets/cems-glofas-historical} -#' -#' @keywords datasets -#' @examples -#' data(avacha) -#' str(avacha) -NULL +#' Mean Daily Water Discharge At Avacha River (Elizovo City) +#' +#' @details These data contain the measured (`obs`) mean daily water discharge +#' values (in \eqn{m^3/s}) at the Avacha River -- Elizovo City state gauging +#' station for the 2022 calendar year. They are accompanied by the GloFAS v4.0 +#' reanalysis water discharge values for the last 24 hours (`sim`), derived +#' from +#' \url{https://ewds.climate.copernicus.eu/datasets/cems-glofas-historical}. +#' +#' Read more about GloFAS Water Discharge reanalysis -- +#' \url{https://confluence.ecmwf.int/display/CEMS/GloFAS+v4.0} +#' +#' @name avacha +#' @aliases avacha +#' @docType data +#' @return \item{avacha}{a data frame} +#' +#' @source +#' * \url{https://gmvo.skniivh.ru/} +#' * \url{https://ewds.climate.copernicus.eu/datasets/cems-glofas-historical} +#' +#' @keywords datasets +#' @examples +#' data(avacha) +#' str(avacha) +NULL diff --git a/R/kge.R b/R/kge.R index 5fdc8fb..b4f327d 100644 --- a/R/kge.R +++ b/R/kge.R @@ -1,249 +1,249 @@ -#' Kling-Gupta Efficiency (KGE) -#' -#' @description -#' Calculate the Kling-Gupta Efficiency (*Gupta et al., 2009*). -#' Dimensionless (from \eqn{-\infty} to 1). `kge()` assesses the accuracy of -#' simulated data by considering correlation, bias, and variability relative -#' to observed data. -#' -#' @details -#' The Kling-Gupta Efficiency is a composite metric that decomposes model -#' performance into three components: correlation (\eqn{r}), -#' variability ratio (\eqn{\alpha}), and bias ratio (\eqn{\beta}). -#' It improves upon the Nash-Sutcliffe Efficiency (see [nse]) -#' by explicitly accounting for each source of error (*Gupta et al., 2009*). -#' -#' The Kling-Gupta Efficiency is estimated as follows: -#' \deqn{ -#' KGE = 1 - \sqrt{(r - 1)^2 + (\alpha - 1)^2 + (\beta - 1)^2} -#' } -#' where: -#' \itemize{ -#' \item \eqn{r} is the linear Pearson correlation coefficient between -#' observed and simulated values -#' \item \eqn{\alpha = \sigma_{sim} / \sigma_{obs}} is the ratio of the -#' standard deviations (variability ratio) -#' \item \eqn{\beta = \mu_{sim} / \mu_{obs}} is the ratio of the -#' means (bias ratio) -#' } -#' -#' @note -#' Unlike the Nash–Sutcliffe Efficiency ([nse]), the KGE does not have an -#' inherent benchmark such as "mean flow", and \eqn{KGE = 0} does not -#' correspond to a baseline performance. -#' Therefore, KGE values should not be interpreted as "good" or "bad" based -#' solely on their sign or magnitude. -#' Instead, users are encouraged to examine the individual components -#' (\eqn{r}, \eqn{\alpha}, \eqn{\beta}) -#' to understand the nature of model performance and consider defining -#' explicit benchmarks based on the study context. -#' -#' For further discussion, see Knoben et al. (2019), who caution against -#' directly translating NSE-based interpretation thresholds to KGE. -#' -#' @family numeric metrics -#' @family accuracy metrics -#' @templateVar fn kge -#' @template return -#' -#' @param data A `data.frame` containing the columns specified by the `truth` -#' and `estimate` arguments. -#' -#' @param truth The column identifier for the true results -#' (that is `numeric`). This should be an unquoted column name although -#' this argument is passed by expression and supports -#' [quasiquotation][rlang::quasiquotation] (you can unquote column -#' names). For `_vec()` functions, a `numeric` vector. -#' -#' @param estimate The column identifier for the predicted -#' results (that is also `numeric`). As with `truth` this can be -#' specified different ways but the primary method is to use an -#' unquoted variable name. For `_vec()` functions, a `numeric` vector. -#' -#' @param na_rm A `logical` value indicating whether `NA` -#' values should be stripped before the computation proceeds. -#' -#' @param ... Not currently used. -#' -#' @references -#' Gupta, H.V.; Kling, H.; Yilmaz, K.K.; Martinez, G.F. (2009). -#' Decomposition of the mean squared error and kge performance criteria: -#' Implications for improving hydrological modelling. Journal of Hydrology, -#' 377(1-2), 80-91. \doi{10.1016/j.jhydrol.2009.08.003} -#' -#' Knoben, W. J. M., Freer, J. E., & Woods, R. A. (2019). -#' Technical note: Inherent benchmark or not? Comparing Nash–Sutcliffe and -#' Kling–Gupta efficiency scores. Hydrology and Earth System Sciences, 23, -#' 4323–4331. \doi{10.5194/hess-23-4323-2019} -#' -#' @template examples-numeric -#' -#' @export -#' -kge <- function(data, ...) { - UseMethod("kge") -} - -kge <- yardstick::new_numeric_metric( - kge, - direction = "maximize" -) - -#' @rdname kge -#' @export -kge.data.frame <- function( - data, - truth, - estimate, - na_rm = TRUE, - ... -) { - yardstick::numeric_metric_summarizer( - name = "kge", - fn = kge_vec, - data = data, - truth = !!rlang::enquo(truth), - estimate = !!rlang::enquo(estimate), - na_rm = na_rm - ) -} - -#' @rdname kge -#' @export -kge_vec <- function( - truth, - estimate, - na_rm = TRUE, - ... -) { - yardstick::check_numeric_metric(truth, estimate, case_weights = NULL) - - kge_cpp(truth, estimate, na_rm = na_rm, version = "2009") -} - -#' Modified Kling-Gupta Efficiency (KGE') -#' -#' @description -#' Calculate the modified Kling-Gupta Efficiency (*Kling et al., 2012*), -#' aka \eqn{KGE'}. Dimensionless (from \eqn{-\infty} to 1). -#' `kge2012()` assesses the accuracy of -#' simulated data by considering correlation, bias, and variability relative -#' to observed data. -#' -#' @details -#' The Modified Kling-Gupta Efficiency is a composite metric that decomposes -#' model performance into three components: correlation (\eqn{r}), -#' bias ratio (\eqn{\beta}), and variability ratio (\eqn{\gamma}). -#' It improves upon the Kling-Gupta Efficiency (see [kge]) by replacing -#' standard deviation with Coefficient of Variation. This ensures that the -#' bias and variability ratios are not cross-correlated, -#' which otherwise may occur when e.g. the precipitation inputs are biased. -#' -#' The Modified Kling-Gupta Efficiency (\eqn{KGE'}) is estimated as follows: -#' \deqn{ -#' KGE' = 1 - \sqrt{(r - 1)^2 + (\beta - 1)^2 + (\gamma - 1)^2} -#' } -#' where: -#' \itemize{ -#' \item \eqn{r} is the linear Pearson correlation coefficient between -#' observed and simulated values -#' \item \eqn{\beta = \mu_{sim} / \mu_{obs}} is the ratio of the -#' means (bias ratio) -#' \item \eqn{ -#' \gamma = \frac{\sigma_{sim} / \mu_{sim}}{\sigma_{sim} / \mu_{sim}} -#' } is the ratio of the Coefficients of Variation (variability ratio) -#' } -#' -#' @note -#' Unlike the Nash–Sutcliffe Efficiency ([nse]), the KGE does not have an -#' inherent benchmark such as "mean flow", and \eqn{KGE' = 0} does not -#' correspond to a baseline performance. -#' Therefore, \eqn{KGE'} values should not be interpreted as "good" or "bad" -#' based solely on their sign or magnitude. -#' Instead, users are encouraged to examine the individual components -#' (\eqn{r}, \eqn{\beta}, \eqn{\gamma}) -#' to understand the nature of model performance and consider defining -#' explicit benchmarks based on the study context. -#' -#' For further discussion, see Knoben et al. (2019), who caution against -#' directly translating NSE-based interpretation thresholds to KGE. -#' -#' @family numeric metrics -#' @family accuracy metrics -#' @templateVar fn kge2012 -#' @template return -#' -#' @param data A `data.frame` containing the columns specified by the `truth` -#' and `estimate` arguments. -#' -#' @param truth The column identifier for the true results -#' (that is `numeric`). This should be an unquoted column name although -#' this argument is passed by expression and supports -#' [quasiquotation][rlang::quasiquotation] (you can unquote column -#' names). For `_vec()` functions, a `numeric` vector. -#' -#' @param estimate The column identifier for the predicted -#' results (that is also `numeric`). As with `truth` this can be -#' specified different ways but the primary method is to use an -#' unquoted variable name. For `_vec()` functions, a `numeric` vector. -#' -#' @param na_rm A `logical` value indicating whether `NA` -#' values should be stripped before the computation proceeds. -#' -#' @param ... Not currently used. -#' -#' @references -#' Kling, H., Fuchs, M., & Paulin, M. (2012). Runoff conditions in the upper -#' Danube basin under an ensemble of climate change scenarios. -#' Journal of Hydrology, 424–425, 264–277. -#' \doi{10.1016/j.jhydrol.2012.01.011} -#' -#' Knoben, W. J. M., Freer, J. E., & Woods, R. A. (2019). -#' Technical note: Inherent benchmark or not? Comparing Nash–Sutcliffe and -#' Kling–Gupta efficiency scores. Hydrology and Earth System Sciences, 23, -#' 4323–4331. \doi{10.5194/hess-23-4323-2019} -#' -#' @template examples-numeric -#' -#' @export -#' -kge2012 <- function(data, ...) { - UseMethod("kge2012") -} - -kge2012 <- yardstick::new_numeric_metric( - kge2012, - direction = "maximize" -) - -#' @rdname kge2012 -#' @export -kge2012.data.frame <- function( - data, - truth, - estimate, - na_rm = TRUE, - ... -) { - yardstick::numeric_metric_summarizer( - name = "kge2012", - fn = kge2012_vec, - data = data, - truth = !!rlang::enquo(truth), - estimate = !!rlang::enquo(estimate), - na_rm = na_rm - ) -} - -#' @rdname kge2012 -#' @export -kge2012_vec <- function( - truth, - estimate, - na_rm = TRUE, - ... -) { - yardstick::check_numeric_metric(truth, estimate, case_weights = NULL) - - kge_cpp(truth, estimate, na_rm = na_rm, version = "2012") -} +#' Kling-Gupta Efficiency (KGE) +#' +#' @description +#' Calculate the Kling-Gupta Efficiency (*Gupta et al., 2009*). +#' Dimensionless (from \eqn{-\infty} to 1). `kge()` assesses the accuracy of +#' simulated data by considering correlation, bias, and variability relative +#' to observed data. +#' +#' @details +#' The Kling-Gupta Efficiency is a composite metric that decomposes model +#' performance into three components: correlation (\eqn{r}), +#' variability ratio (\eqn{\alpha}), and bias ratio (\eqn{\beta}). +#' It improves upon the Nash-Sutcliffe Efficiency (see [nse]) +#' by explicitly accounting for each source of error (*Gupta et al., 2009*). +#' +#' The Kling-Gupta Efficiency is estimated as follows: +#' \deqn{ +#' KGE = 1 - \sqrt{(r - 1)^2 + (\alpha - 1)^2 + (\beta - 1)^2} +#' } +#' where: +#' \itemize{ +#' \item \eqn{r} is the linear Pearson correlation coefficient between +#' observed and simulated values +#' \item \eqn{\alpha = \sigma_{sim} / \sigma_{obs}} is the ratio of the +#' standard deviations (variability ratio) +#' \item \eqn{\beta = \mu_{sim} / \mu_{obs}} is the ratio of the +#' means (bias ratio) +#' } +#' +#' @note +#' Unlike the Nash–Sutcliffe Efficiency ([nse]), the KGE does not have an +#' inherent benchmark such as "mean flow", and \eqn{KGE = 0} does not +#' correspond to a baseline performance. +#' Therefore, KGE values should not be interpreted as "good" or "bad" based +#' solely on their sign or magnitude. +#' Instead, users are encouraged to examine the individual components +#' (\eqn{r}, \eqn{\alpha}, \eqn{\beta}) +#' to understand the nature of model performance and consider defining +#' explicit benchmarks based on the study context. +#' +#' For further discussion, see Knoben et al. (2019), who caution against +#' directly translating NSE-based interpretation thresholds to KGE. +#' +#' @family numeric metrics +#' @family accuracy metrics +#' @templateVar fn kge +#' @template return +#' +#' @param data A `data.frame` containing the columns specified by the `truth` +#' and `estimate` arguments. +#' +#' @param truth The column identifier for the true results +#' (that is `numeric`). This should be an unquoted column name although +#' this argument is passed by expression and supports +#' [quasiquotation][rlang::quasiquotation] (you can unquote column +#' names). For `_vec()` functions, a `numeric` vector. +#' +#' @param estimate The column identifier for the predicted +#' results (that is also `numeric`). As with `truth` this can be +#' specified different ways but the primary method is to use an +#' unquoted variable name. For `_vec()` functions, a `numeric` vector. +#' +#' @param na_rm A `logical` value indicating whether `NA` +#' values should be stripped before the computation proceeds. +#' +#' @param ... Not currently used. +#' +#' @references +#' Gupta, H.V.; Kling, H.; Yilmaz, K.K.; Martinez, G.F. (2009). +#' Decomposition of the mean squared error and kge performance criteria: +#' Implications for improving hydrological modelling. Journal of Hydrology, +#' 377(1-2), 80-91. \doi{10.1016/j.jhydrol.2009.08.003} +#' +#' Knoben, W. J. M., Freer, J. E., & Woods, R. A. (2019). +#' Technical note: Inherent benchmark or not? Comparing Nash–Sutcliffe and +#' Kling–Gupta efficiency scores. Hydrology and Earth System Sciences, 23, +#' 4323–4331. \doi{10.5194/hess-23-4323-2019} +#' +#' @template examples-numeric +#' +#' @export +#' +kge <- function(data, ...) { + UseMethod("kge") +} + +kge <- yardstick::new_numeric_metric( + kge, + direction = "maximize" +) + +#' @rdname kge +#' @export +kge.data.frame <- function( + data, + truth, + estimate, + na_rm = TRUE, + ... +) { + yardstick::numeric_metric_summarizer( + name = "kge", + fn = kge_vec, + data = data, + truth = !!rlang::enquo(truth), + estimate = !!rlang::enquo(estimate), + na_rm = na_rm + ) +} + +#' @rdname kge +#' @export +kge_vec <- function( + truth, + estimate, + na_rm = TRUE, + ... +) { + yardstick::check_numeric_metric(truth, estimate, case_weights = NULL) + + kge_cpp(truth, estimate, na_rm = na_rm, version = "2009") +} + +#' Modified Kling-Gupta Efficiency (KGE') +#' +#' @description +#' Calculate the modified Kling-Gupta Efficiency (*Kling et al., 2012*), +#' aka \eqn{KGE'}. Dimensionless (from \eqn{-\infty} to 1). +#' `kge2012()` assesses the accuracy of +#' simulated data by considering correlation, bias, and variability relative +#' to observed data. +#' +#' @details +#' The Modified Kling-Gupta Efficiency is a composite metric that decomposes +#' model performance into three components: correlation (\eqn{r}), +#' bias ratio (\eqn{\beta}), and variability ratio (\eqn{\gamma}). +#' It improves upon the Kling-Gupta Efficiency (see [kge]) by replacing +#' standard deviation with Coefficient of Variation. This ensures that the +#' bias and variability ratios are not cross-correlated, +#' which otherwise may occur when e.g. the precipitation inputs are biased. +#' +#' The Modified Kling-Gupta Efficiency (\eqn{KGE'}) is estimated as follows: +#' \deqn{ +#' KGE' = 1 - \sqrt{(r - 1)^2 + (\beta - 1)^2 + (\gamma - 1)^2} +#' } +#' where: +#' \itemize{ +#' \item \eqn{r} is the linear Pearson correlation coefficient between +#' observed and simulated values +#' \item \eqn{\beta = \mu_{sim} / \mu_{obs}} is the ratio of the +#' means (bias ratio) +#' \item \eqn{ +#' \gamma = \frac{\sigma_{sim} / \mu_{sim}}{\sigma_{sim} / \mu_{sim}} +#' } is the ratio of the Coefficients of Variation (variability ratio) +#' } +#' +#' @note +#' Unlike the Nash–Sutcliffe Efficiency ([nse]), the KGE does not have an +#' inherent benchmark such as "mean flow", and \eqn{KGE' = 0} does not +#' correspond to a baseline performance. +#' Therefore, \eqn{KGE'} values should not be interpreted as "good" or "bad" +#' based solely on their sign or magnitude. +#' Instead, users are encouraged to examine the individual components +#' (\eqn{r}, \eqn{\beta}, \eqn{\gamma}) +#' to understand the nature of model performance and consider defining +#' explicit benchmarks based on the study context. +#' +#' For further discussion, see Knoben et al. (2019), who caution against +#' directly translating NSE-based interpretation thresholds to KGE. +#' +#' @family numeric metrics +#' @family accuracy metrics +#' @templateVar fn kge2012 +#' @template return +#' +#' @param data A `data.frame` containing the columns specified by the `truth` +#' and `estimate` arguments. +#' +#' @param truth The column identifier for the true results +#' (that is `numeric`). This should be an unquoted column name although +#' this argument is passed by expression and supports +#' [quasiquotation][rlang::quasiquotation] (you can unquote column +#' names). For `_vec()` functions, a `numeric` vector. +#' +#' @param estimate The column identifier for the predicted +#' results (that is also `numeric`). As with `truth` this can be +#' specified different ways but the primary method is to use an +#' unquoted variable name. For `_vec()` functions, a `numeric` vector. +#' +#' @param na_rm A `logical` value indicating whether `NA` +#' values should be stripped before the computation proceeds. +#' +#' @param ... Not currently used. +#' +#' @references +#' Kling, H., Fuchs, M., & Paulin, M. (2012). Runoff conditions in the upper +#' Danube basin under an ensemble of climate change scenarios. +#' Journal of Hydrology, 424–425, 264–277. +#' \doi{10.1016/j.jhydrol.2012.01.011} +#' +#' Knoben, W. J. M., Freer, J. E., & Woods, R. A. (2019). +#' Technical note: Inherent benchmark or not? Comparing Nash–Sutcliffe and +#' Kling–Gupta efficiency scores. Hydrology and Earth System Sciences, 23, +#' 4323–4331. \doi{10.5194/hess-23-4323-2019} +#' +#' @template examples-numeric +#' +#' @export +#' +kge2012 <- function(data, ...) { + UseMethod("kge2012") +} + +kge2012 <- yardstick::new_numeric_metric( + kge2012, + direction = "maximize" +) + +#' @rdname kge2012 +#' @export +kge2012.data.frame <- function( + data, + truth, + estimate, + na_rm = TRUE, + ... +) { + yardstick::numeric_metric_summarizer( + name = "kge2012", + fn = kge2012_vec, + data = data, + truth = !!rlang::enquo(truth), + estimate = !!rlang::enquo(estimate), + na_rm = na_rm + ) +} + +#' @rdname kge2012 +#' @export +kge2012_vec <- function( + truth, + estimate, + na_rm = TRUE, + ... +) { + yardstick::check_numeric_metric(truth, estimate, case_weights = NULL) + + kge_cpp(truth, estimate, na_rm = na_rm, version = "2012") +} diff --git a/R/mse.R b/R/mse.R index a6ddddc..c30819d 100644 --- a/R/mse.R +++ b/R/mse.R @@ -1,99 +1,99 @@ -#' Mean Squared Error (MSE) -#' -#' @description -#' The MSE is a metric that evaluates the goodness of fit between model -#' simulations and observations (*Fisher, 1920*). Measured in the squared -#' units of `truth` and `estimate` and can vary from \eqn{-\infty} to -#' \eqn{+\infty}. -#' -#' @details -#' The MSE is estimated as follows (Clark et al., 2021): -#' \deqn{ -#' MSE = \frac{1}{n} \sum_{i=1}^{n}{(sim_i - obs_i)^2} -#' } -#' where: -#' \itemize{ -#' \item \eqn{sim} defines model simulations at time step \eqn{i} -#' \item \eqn{obs} defines model observations at time step \eqn{i} -#' } -#' -#' @family numeric metrics -#' @family accuracy metrics -#' @templateVar fn mse -#' @template return -#' -#' @param data A `data.frame` containing the columns specified by the `truth` -#' and `estimate` arguments. -#' -#' @param truth The column identifier for the true results -#' (that is `numeric`). This should be an unquoted column name although -#' this argument is passed by expression and supports -#' [quasiquotation][rlang::quasiquotation] (you can unquote column -#' names). For `_vec()` functions, a `numeric` vector. -#' -#' @param estimate The column identifier for the predicted -#' results (that is also `numeric`). As with `truth` this can be -#' specified different ways but the primary method is to use an -#' unquoted variable name. For `_vec()` functions, a `numeric` vector. -#' -#' @param na_rm A `logical` value indicating whether `NA` -#' values should be stripped before the computation proceeds. -#' -#' @param ... Not currently used. -#' -#' @references -#' Fisher, R. A. (1920). Accuracy of observation, a mathematical -#' examination of the methods of determining, by the mean error and -#' by the mean square error. Monthly Notices of the Royal Astronomical -#' Society, 80, 758–770. \doi{10.1093/mnras/80.8.758} -#' -#' Clark, M. P., Vogel, R. M., Lamontagne, J. R., Mizukami, N., -#' Knoben, W. J. M., Tang, G., Gharari, S., Freer, J. E., Whitfield, -#' P. H., Shook, K. R., & Papalexiou, S. M. (2021). The Abuse of Popular -#' Performance Metrics in Hydrologic Modeling. Water Resources Research, 57(9), -#' e2020WR029001. \doi{10.1029/2020WR029001} -#' -#' @template examples-numeric -#' -#' @export -#' -mse <- function(data, ...) { - UseMethod("mse") -} - -mse <- yardstick::new_numeric_metric( - mse, - direction = "minimize" -) - -#' @rdname mse -#' @export -mse.data.frame <- function( - data, - truth, - estimate, - na_rm = TRUE, - ... -) { - yardstick::numeric_metric_summarizer( - name = "mse", - fn = mse_vec, - data = data, - truth = !!rlang::enquo(truth), - estimate = !!rlang::enquo(estimate), - na_rm = na_rm - ) -} - -#' @rdname mse -#' @export -mse_vec <- function( - truth, - estimate, - na_rm = TRUE, - ... -) { - yardstick::check_numeric_metric(truth, estimate, case_weights = NULL) - - mse_cpp(truth, estimate, na_rm = na_rm) -} +#' Mean Squared Error (MSE) +#' +#' @description +#' The MSE is a metric that evaluates the goodness of fit between model +#' simulations and observations (*Fisher, 1920*). Measured in the squared +#' units of `truth` and `estimate` and can vary from \eqn{-\infty} to +#' \eqn{+\infty}. +#' +#' @details +#' The MSE is estimated as follows (Clark et al., 2021): +#' \deqn{ +#' MSE = \frac{1}{n} \sum_{i=1}^{n}{(sim_i - obs_i)^2} +#' } +#' where: +#' \itemize{ +#' \item \eqn{sim} defines model simulations at time step \eqn{i} +#' \item \eqn{obs} defines model observations at time step \eqn{i} +#' } +#' +#' @family numeric metrics +#' @family accuracy metrics +#' @templateVar fn mse +#' @template return +#' +#' @param data A `data.frame` containing the columns specified by the `truth` +#' and `estimate` arguments. +#' +#' @param truth The column identifier for the true results +#' (that is `numeric`). This should be an unquoted column name although +#' this argument is passed by expression and supports +#' [quasiquotation][rlang::quasiquotation] (you can unquote column +#' names). For `_vec()` functions, a `numeric` vector. +#' +#' @param estimate The column identifier for the predicted +#' results (that is also `numeric`). As with `truth` this can be +#' specified different ways but the primary method is to use an +#' unquoted variable name. For `_vec()` functions, a `numeric` vector. +#' +#' @param na_rm A `logical` value indicating whether `NA` +#' values should be stripped before the computation proceeds. +#' +#' @param ... Not currently used. +#' +#' @references +#' Fisher, R. A. (1920). Accuracy of observation, a mathematical +#' examination of the methods of determining, by the mean error and +#' by the mean square error. Monthly Notices of the Royal Astronomical +#' Society, 80, 758–770. \doi{10.1093/mnras/80.8.758} +#' +#' Clark, M. P., Vogel, R. M., Lamontagne, J. R., Mizukami, N., +#' Knoben, W. J. M., Tang, G., Gharari, S., Freer, J. E., Whitfield, +#' P. H., Shook, K. R., & Papalexiou, S. M. (2021). The Abuse of Popular +#' Performance Metrics in Hydrologic Modeling. Water Resources Research, 57(9), +#' e2020WR029001. \doi{10.1029/2020WR029001} +#' +#' @template examples-numeric +#' +#' @export +#' +mse <- function(data, ...) { + UseMethod("mse") +} + +mse <- yardstick::new_numeric_metric( + mse, + direction = "minimize" +) + +#' @rdname mse +#' @export +mse.data.frame <- function( + data, + truth, + estimate, + na_rm = TRUE, + ... +) { + yardstick::numeric_metric_summarizer( + name = "mse", + fn = mse_vec, + data = data, + truth = !!rlang::enquo(truth), + estimate = !!rlang::enquo(estimate), + na_rm = na_rm + ) +} + +#' @rdname mse +#' @export +mse_vec <- function( + truth, + estimate, + na_rm = TRUE, + ... +) { + yardstick::check_numeric_metric(truth, estimate, case_weights = NULL) + + mse_cpp(truth, estimate, na_rm = na_rm) +} diff --git a/R/sfe.R b/R/sfe.R index 14fec8f..772f27f 100644 --- a/R/sfe.R +++ b/R/sfe.R @@ -1,100 +1,100 @@ -#' Standard Factorial Error (SFE) -#' -#' @description -#' Prediction standard factorial error estimated -#' using standard regression methods (see *Herschy, 1978*). -#' -#' @details -#' The metric is widely used for assessing Sediment Rating Curves -#' (e.g., Hicks et al. 2020). The model is usually considered 'unacceptable' -#' if the \eqn{SFE > 2}, see Hicks et al. (2011). -#' -#' It is estimated as follows: -#' \deqn{SFE = \exp\left(\sqrt{\frac{1}{n} \sum_{i=1}^{n} -#' \left( \log\left(\frac{obs_i}{sim_i} \right) \right)^2 }\right)} -#' where: -#' \itemize{ -#' \item \eqn{sim} defines model simulations at time step \eqn{i} -#' \item \eqn{obs} defines model observations at time step \eqn{i} -#' } -#' -#' @family numeric metrics -#' @family accuracy metrics -#' @templateVar fn sfe -#' @template return -#' -#' @param data A `data.frame` containing the columns specified by the `truth` -#' and `estimate` arguments. -#' @param truth The column identifier for the true results -#' (that is `numeric`). This should be an unquoted column name although -#' this argument is passed by expression and supports -#' [quasiquotation][rlang::quasiquotation] (you can unquote column -#' names). For `_vec()` functions, a `numeric` vector. -#' @param estimate The column identifier for the predicted -#' results (that is also `numeric`). As with `truth` this can be -#' specified different ways but the primary method is to use an -#' unquoted variable name. For `_vec()` functions, a `numeric` vector. -#' @param na_rm A `logical` value indicating whether `NA` -#' values should be stripped before the computation proceeds. -#' @param ... Not currently used. -#' -#' @references -#' Herschy, R.W. 1978: Accuracy. Chapter 10 In: Herschy, R.W. (ed.) -#' Hydrometry - principles and practices. John Wiley and Sons, Chichester, -#' 511 p. -#' -#' Hicks, D. M., Shankar, U., McKerchar, A. I., Basher, L., Lynn, I., -#' Page, M., & Jessen, M. (2011). Suspended Sediment Yields from New Zealand -#' Rivers. Journal of Hydrology (New Zealand), 50(1), 81–142. -#' \doi{10.3316/informit.315190637227597} -#' -#' Hicks, M., Doyle, M., Watson, J., Holwerda, N., Lynch, B., Wyatt, J., -#' Jones, H., & Hill, R. (2020). Measurement of Fluvial Suspended Sediment -#' Load and its Composition (No. 1.0.0; National Environmental Monitoring -#' Standards, p. 138). -#' \url{https://www.nems.org.nz/documents/suspended-sediment} -#' -#' @template examples-numeric -#' -#' @export -#' -sfe <- function(data, ...) { - UseMethod("sfe") -} - -sfe <- yardstick::new_numeric_metric( - sfe, - direction = "minimize" -) - -#' @rdname sfe -#' @export -sfe.data.frame <- function( - data, - truth, - estimate, - na_rm = TRUE, - ... -) { - yardstick::numeric_metric_summarizer( - name = "sfe", - fn = sfe_vec, - data = data, - truth = !!rlang::enquo(truth), - estimate = !!rlang::enquo(estimate), - na_rm = na_rm - ) -} - -#' @rdname sfe -#' @export -sfe_vec <- function( - truth, - estimate, - na_rm = TRUE, - ... -) { - yardstick::check_numeric_metric(truth, estimate, case_weights = NULL) - - sfe_cpp(truth, estimate, na_rm = na_rm) -} +#' Standard Factorial Error (SFE) +#' +#' @description +#' Prediction standard factorial error estimated +#' using standard regression methods (see *Herschy, 1978*). +#' +#' @details +#' The metric is widely used for assessing Sediment Rating Curves +#' (e.g., Hicks et al. 2020). The model is usually considered 'unacceptable' +#' if the \eqn{SFE > 2}, see Hicks et al. (2011). +#' +#' It is estimated as follows: +#' \deqn{SFE = \exp\left(\sqrt{\frac{1}{n} \sum_{i=1}^{n} +#' \left( \log\left(\frac{obs_i}{sim_i} \right) \right)^2 }\right)} +#' where: +#' \itemize{ +#' \item \eqn{sim} defines model simulations at time step \eqn{i} +#' \item \eqn{obs} defines model observations at time step \eqn{i} +#' } +#' +#' @family numeric metrics +#' @family accuracy metrics +#' @templateVar fn sfe +#' @template return +#' +#' @param data A `data.frame` containing the columns specified by the `truth` +#' and `estimate` arguments. +#' @param truth The column identifier for the true results +#' (that is `numeric`). This should be an unquoted column name although +#' this argument is passed by expression and supports +#' [quasiquotation][rlang::quasiquotation] (you can unquote column +#' names). For `_vec()` functions, a `numeric` vector. +#' @param estimate The column identifier for the predicted +#' results (that is also `numeric`). As with `truth` this can be +#' specified different ways but the primary method is to use an +#' unquoted variable name. For `_vec()` functions, a `numeric` vector. +#' @param na_rm A `logical` value indicating whether `NA` +#' values should be stripped before the computation proceeds. +#' @param ... Not currently used. +#' +#' @references +#' Herschy, R.W. 1978: Accuracy. Chapter 10 In: Herschy, R.W. (ed.) +#' Hydrometry - principles and practices. John Wiley and Sons, Chichester, +#' 511 p. +#' +#' Hicks, D. M., Shankar, U., McKerchar, A. I., Basher, L., Lynn, I., +#' Page, M., & Jessen, M. (2011). Suspended Sediment Yields from New Zealand +#' Rivers. Journal of Hydrology (New Zealand), 50(1), 81–142. +#' \doi{10.3316/informit.315190637227597} +#' +#' Hicks, M., Doyle, M., Watson, J., Holwerda, N., Lynch, B., Wyatt, J., +#' Jones, H., & Hill, R. (2020). Measurement of Fluvial Suspended Sediment +#' Load and its Composition (No. 1.0.0; National Environmental Monitoring +#' Standards, p. 138). +#' \url{https://www.nems.org.nz/documents/suspended-sediment} +#' +#' @template examples-numeric +#' +#' @export +#' +sfe <- function(data, ...) { + UseMethod("sfe") +} + +sfe <- yardstick::new_numeric_metric( + sfe, + direction = "minimize" +) + +#' @rdname sfe +#' @export +sfe.data.frame <- function( + data, + truth, + estimate, + na_rm = TRUE, + ... +) { + yardstick::numeric_metric_summarizer( + name = "sfe", + fn = sfe_vec, + data = data, + truth = !!rlang::enquo(truth), + estimate = !!rlang::enquo(estimate), + na_rm = na_rm + ) +} + +#' @rdname sfe +#' @export +sfe_vec <- function( + truth, + estimate, + na_rm = TRUE, + ... +) { + yardstick::check_numeric_metric(truth, estimate, case_weights = NULL) + + sfe_cpp(truth, estimate, na_rm = na_rm) +} diff --git a/R/tidyhydro-package.R b/R/tidyhydro-package.R index 0cc9deb..b8144fe 100644 --- a/R/tidyhydro-package.R +++ b/R/tidyhydro-package.R @@ -1,2 +1,2 @@ -#' @keywords internal -"_PACKAGE" +#' @keywords internal +"_PACKAGE" diff --git a/README.Rmd b/README.Rmd index 1260ce0..d230f88 100644 --- a/README.Rmd +++ b/README.Rmd @@ -96,6 +96,10 @@ bench::mark( ) ``` +## Code of Conduct + +Please note that the tidyhydro project is released with a [Contributor Code of Conduct](https://atsyplenkov.github.io/tidyhydro/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. + ## See also * [`hydroGOF`](https://github.com/hzambran/hydroGOF) - Goodness-of-fit functions for comparison of simulated and observed hydrological time series. -* [`yardstick`](https://github.com/tidymodels/yardstick/tree/main) - tidy methods for models performance assessment. \ No newline at end of file +* [`yardstick`](https://github.com/tidymodels/yardstick/tree/main) - tidy methods for models performance assessment. diff --git a/README.md b/README.md index 4be6f9b..860f30b 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,7 @@ # tidyhydro -

- The `tidyhydro` package provides a set of commonly used metrics in @@ -143,15 +140,22 @@ bench::mark( #> # A tibble: 3 × 6 #> expression min median `itr/sec` mem_alloc `gc/sec` #> -#> 1 tidyhydro 1 1 39.1 NaN NaN -#> 2 hydroGOF 30.8 33.7 1 Inf Inf -#> 3 baseR 20.5 21.6 1.92 Inf Inf +#> 1 tidyhydro 1 1 52.8 NaN NaN +#> 2 hydroGOF 30.5 41.1 1 Inf Inf +#> 3 baseR 17.3 20.6 2.31 Inf Inf ``` +## Code of Conduct + +Please note that the tidyhydro project is released with a [Contributor +Code of +Conduct](https://atsyplenkov.github.io/tidyhydro/CODE_OF_CONDUCT.html). +By contributing to this project, you agree to abide by its terms. + ## See also -- [`hydroGOF`](https://github.com/hzambran/hydroGOF) - Goodness-of-fit - functions for comparison of simulated and observed hydrological time - series. -- [`yardstick`](https://github.com/tidymodels/yardstick/tree/main) - - tidy methods for models performance assessment. +- [`hydroGOF`](https://github.com/hzambran/hydroGOF) - Goodness-of-fit + functions for comparison of simulated and observed hydrological time + series. +- [`yardstick`](https://github.com/tidymodels/yardstick/tree/main) - + tidy methods for models performance assessment. diff --git a/_pkgdown.yml b/_pkgdown.yml index 038e8ff..70beb52 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -1,23 +1,23 @@ -url: https://atsyplenkov.github.io/tidyhydro/ - -repo: - url: - home: https://github.com/atsyplenkov/tidyhydro - source: https://github.com/atsyplenkov/tidyhydro/tree/master - issues: https://github.com/atsyplenkov/tidyhydro/issues - -template: - bootstrap: 5 - math-rendering: mathjax - bslib: - base_font: {google: "Roboto"} - heading_font: {google: "Inter Tight"} - code_font: {google: "Fira Code"} - -footer: - structure: - left: [developed_by] - right: [legal] - components: - legal: "[MIT](https://opensource.org/license/mit) License | Copyright (c) 2025 tidyhydro authors" - developed_by: Developed by [Anatolii Tsyplenkov](https://github.com/atsyplenkov) +url: https://atsyplenkov.github.io/tidyhydro/ + +repo: + url: + home: https://github.com/atsyplenkov/tidyhydro + source: https://github.com/atsyplenkov/tidyhydro/tree/master + issues: https://github.com/atsyplenkov/tidyhydro/issues + +template: + bootstrap: 5 + math-rendering: mathjax + bslib: + base_font: {google: "Roboto"} + heading_font: {google: "Inter Tight"} + code_font: {google: "Fira Code"} + +footer: + structure: + left: [developed_by] + right: [legal] + components: + legal: "[MIT](https://opensource.org/license/mit) License | Copyright (c) 2025 tidyhydro authors" + developed_by: Developed by [Anatolii Tsyplenkov](https://github.com/atsyplenkov) diff --git a/codemeta.json b/codemeta.json new file mode 100644 index 0000000..b75c4d5 --- /dev/null +++ b/codemeta.json @@ -0,0 +1,149 @@ +{ + "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@type": "SoftwareSourceCode", + "identifier": "tidyhydro", + "description": "Provides tidy tools for comparing simulated and observed hydrological time series. Includes compatibility with the 'yardstick' package for model performance evaluation using commonly used metrics such as the Nash–Sutcliffe Efficiency (NSE), Kling–Gupta Efficiency (KGE), percent bias (pBIAS) and etc.", + "name": "tidyhydro: Tidy Metrics for Assessing Hydrological Models Performance", + "relatedLink": "https://atsyplenkov.github.io/tidyhydro/", + "codeRepository": "https://github.com/atsyplenkov/tidyhydro", + "issueTracker": "https://github.com/atsyplenkov/tidyhydro/issues", + "license": "https://spdx.org/licenses/MIT", + "version": "0.1.1", + "programmingLanguage": { + "@type": "ComputerLanguage", + "name": "R", + "url": "https://r-project.org" + }, + "runtimePlatform": "R version 4.5.1 Patched (2025-06-14 r88315)", + "author": [ + { + "@type": "Person", + "givenName": "Anatoly", + "familyName": "Tsyplenkov", + "email": "atsyplenkov@fastmail.com", + "@id": "https://orcid.org/0000-0003-4144-8402" + } + ], + "copyrightHolder": [ + { + "@type": "Person", + "givenName": "Anatoly", + "familyName": "Tsyplenkov", + "email": "atsyplenkov@fastmail.com", + "@id": "https://orcid.org/0000-0003-4144-8402" + } + ], + "maintainer": [ + { + "@type": "Person", + "givenName": "Anatoly", + "familyName": "Tsyplenkov", + "email": "atsyplenkov@fastmail.com", + "@id": "https://orcid.org/0000-0003-4144-8402" + } + ], + "softwareSuggestions": [ + { + "@type": "SoftwareApplication", + "identifier": "hydroGOF", + "name": "hydroGOF", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=hydroGOF" + }, + { + "@type": "SoftwareApplication", + "identifier": "testthat", + "name": "testthat", + "version": ">= 3.0.0", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=testthat" + }, + { + "@type": "SoftwareApplication", + "identifier": "quickcheck", + "name": "quickcheck", + "version": ">= 0.1.3", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=quickcheck" + }, + { + "@type": "SoftwareApplication", + "identifier": "quarto", + "name": "quarto", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=quarto" + } + ], + "softwareRequirements": { + "1": { + "@type": "SoftwareApplication", + "identifier": "R", + "name": "R", + "version": ">= 4.1.0" + }, + "2": { + "@type": "SoftwareApplication", + "identifier": "Rcpp", + "name": "Rcpp", + "version": ">= 1.0.12", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=Rcpp" + }, + "3": { + "@type": "SoftwareApplication", + "identifier": "rlang", + "name": "rlang", + "version": ">= 1.1.0", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=rlang" + }, + "4": { + "@type": "SoftwareApplication", + "identifier": "yardstick", + "name": "yardstick", + "version": ">= 1.3.1", + "provider": { + "@id": "https://cran.r-project.org", + "@type": "Organization", + "name": "Comprehensive R Archive Network (CRAN)", + "url": "https://cran.r-project.org" + }, + "sameAs": "https://CRAN.R-project.org/package=yardstick" + }, + "SystemRequirements": null + }, + "fileSize": "102.604KB", + "releaseNotes": "https://github.com/atsyplenkov/tidyhydro/blob/master/NEWS.md", + "readme": "https://github.com/atsyplenkov/tidyhydro/blob/master/README.md", + "keywords": ["r", "r-package", "rstats"] +} diff --git a/man/avacha.Rd b/man/avacha.Rd index d2590d8..aec875b 100644 --- a/man/avacha.Rd +++ b/man/avacha.Rd @@ -1,34 +1,34 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/data.R -\docType{data} -\name{avacha} -\alias{avacha} -\title{Mean Daily Water Discharge At Avacha River (Elizovo City)} -\source{ -\itemize{ -\item \url{https://gmvo.skniivh.ru/} -\item \url{https://ewds.climate.copernicus.eu/datasets/cems-glofas-historical} -} -} -\value{ -\item{avacha}{a data frame} -} -\description{ -Mean Daily Water Discharge At Avacha River (Elizovo City) -} -\details{ -These data contain the measured (\code{obs}) mean daily water discharge -values (in \eqn{m^3/s}) at the Avacha River -- Elizovo City state gauging -station for the 2022 calendar year. They are accompanied by the GloFAS v4.0 -reanalysis water discharge values for the last 24 hours (\code{sim}), derived -from -\url{https://ewds.climate.copernicus.eu/datasets/cems-glofas-historical}. - -Read more about GloFAS Water Discharge reanalysis -- -\url{https://confluence.ecmwf.int/display/CEMS/GloFAS+v4.0} -} -\examples{ -data(avacha) -str(avacha) -} -\keyword{datasets} +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data.R +\docType{data} +\name{avacha} +\alias{avacha} +\title{Mean Daily Water Discharge At Avacha River (Elizovo City)} +\source{ +\itemize{ +\item \url{https://gmvo.skniivh.ru/} +\item \url{https://ewds.climate.copernicus.eu/datasets/cems-glofas-historical} +} +} +\value{ +\item{avacha}{a data frame} +} +\description{ +Mean Daily Water Discharge At Avacha River (Elizovo City) +} +\details{ +These data contain the measured (\code{obs}) mean daily water discharge +values (in \eqn{m^3/s}) at the Avacha River -- Elizovo City state gauging +station for the 2022 calendar year. They are accompanied by the GloFAS v4.0 +reanalysis water discharge values for the last 24 hours (\code{sim}), derived +from +\url{https://ewds.climate.copernicus.eu/datasets/cems-glofas-historical}. + +Read more about GloFAS Water Discharge reanalysis -- +\url{https://confluence.ecmwf.int/display/CEMS/GloFAS+v4.0} +} +\examples{ +data(avacha) +str(avacha) +} +\keyword{datasets} diff --git a/man/kge.Rd b/man/kge.Rd index 7354f4f..41dbdcf 100644 --- a/man/kge.Rd +++ b/man/kge.Rd @@ -1,124 +1,124 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/kge.R -\name{kge} -\alias{kge} -\alias{kge.data.frame} -\alias{kge_vec} -\title{Kling-Gupta Efficiency (KGE)} -\usage{ -kge(data, ...) - -\method{kge}{data.frame}(data, truth, estimate, na_rm = TRUE, ...) - -kge_vec(truth, estimate, na_rm = TRUE, ...) -} -\arguments{ -\item{data}{A \code{data.frame} containing the columns specified by the \code{truth} -and \code{estimate} arguments.} - -\item{...}{Not currently used.} - -\item{truth}{The column identifier for the true results -(that is \code{numeric}). This should be an unquoted column name although -this argument is passed by expression and supports -\link[rlang:topic-inject]{quasiquotation} (you can unquote column -names). For \verb{_vec()} functions, a \code{numeric} vector.} - -\item{estimate}{The column identifier for the predicted -results (that is also \code{numeric}). As with \code{truth} this can be -specified different ways but the primary method is to use an -unquoted variable name. For \verb{_vec()} functions, a \code{numeric} vector.} - -\item{na_rm}{A \code{logical} value indicating whether \code{NA} -values should be stripped before the computation proceeds.} -} -\value{ -A \code{tibble} with columns \code{.metric}, \code{.estimator}, -and \code{.estimate} and 1 row of values. - -For grouped data frames, the number of rows returned will be the same as -the number of groups. - -For \code{kge_vec()}, a single \code{numeric} value (or \code{NA}). -} -\description{ -Calculate the Kling-Gupta Efficiency (\emph{Gupta et al., 2009}). -Dimensionless (from \eqn{-\infty} to 1). \code{kge()} assesses the accuracy of -simulated data by considering correlation, bias, and variability relative -to observed data. -} -\details{ -The Kling-Gupta Efficiency is a composite metric that decomposes model -performance into three components: correlation (\eqn{r}), -variability ratio (\eqn{\alpha}), and bias ratio (\eqn{\beta}). -It improves upon the Nash-Sutcliffe Efficiency (see \link{nse}) -by explicitly accounting for each source of error (\emph{Gupta et al., 2009}). - -The Kling-Gupta Efficiency is estimated as follows: -\deqn{ -KGE = 1 - \sqrt{(r - 1)^2 + (\alpha - 1)^2 + (\beta - 1)^2} -} -where: -\itemize{ -\item \eqn{r} is the linear Pearson correlation coefficient between -observed and simulated values -\item \eqn{\alpha = \sigma_{sim} / \sigma_{obs}} is the ratio of the -standard deviations (variability ratio) -\item \eqn{\beta = \mu_{sim} / \mu_{obs}} is the ratio of the -means (bias ratio) -} -} -\note{ -Unlike the Nash–Sutcliffe Efficiency (\link{nse}), the KGE does not have an -inherent benchmark such as "mean flow", and \eqn{KGE = 0} does not -correspond to a baseline performance. -Therefore, KGE values should not be interpreted as "good" or "bad" based -solely on their sign or magnitude. -Instead, users are encouraged to examine the individual components -(\eqn{r}, \eqn{\alpha}, \eqn{\beta}) -to understand the nature of model performance and consider defining -explicit benchmarks based on the study context. - -For further discussion, see Knoben et al. (2019), who caution against -directly translating NSE-based interpretation thresholds to KGE. -} -\examples{ -library(tidyhydro) -data(avacha) - -# Supply truth and predictions as bare column names -kge(avacha, obs, sim) - -# Or as numeric vectors -kge_vec(avacha$obs, avacha$sim) -} -\references{ -Gupta, H.V.; Kling, H.; Yilmaz, K.K.; Martinez, G.F. (2009). -Decomposition of the mean squared error and kge performance criteria: -Implications for improving hydrological modelling. Journal of Hydrology, -377(1-2), 80-91. \doi{10.1016/j.jhydrol.2009.08.003} - -Knoben, W. J. M., Freer, J. E., & Woods, R. A. (2019). -Technical note: Inherent benchmark or not? Comparing Nash–Sutcliffe and -Kling–Gupta efficiency scores. Hydrology and Earth System Sciences, 23, -4323–4331. \doi{10.5194/hess-23-4323-2019} -} -\seealso{ -Other numeric metrics: -\code{\link{kge2012}()}, -\code{\link{mse}()}, -\code{\link{nse}()}, -\code{\link{pbias}()}, -\code{\link{press}()}, -\code{\link{sfe}()} - -Other accuracy metrics: -\code{\link{kge2012}()}, -\code{\link{mse}()}, -\code{\link{nse}()}, -\code{\link{pbias}()}, -\code{\link{press}()}, -\code{\link{sfe}()} -} -\concept{accuracy metrics} -\concept{numeric metrics} +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/kge.R +\name{kge} +\alias{kge} +\alias{kge.data.frame} +\alias{kge_vec} +\title{Kling-Gupta Efficiency (KGE)} +\usage{ +kge(data, ...) + +\method{kge}{data.frame}(data, truth, estimate, na_rm = TRUE, ...) + +kge_vec(truth, estimate, na_rm = TRUE, ...) +} +\arguments{ +\item{data}{A \code{data.frame} containing the columns specified by the \code{truth} +and \code{estimate} arguments.} + +\item{...}{Not currently used.} + +\item{truth}{The column identifier for the true results +(that is \code{numeric}). This should be an unquoted column name although +this argument is passed by expression and supports +\link[rlang:topic-inject]{quasiquotation} (you can unquote column +names). For \verb{_vec()} functions, a \code{numeric} vector.} + +\item{estimate}{The column identifier for the predicted +results (that is also \code{numeric}). As with \code{truth} this can be +specified different ways but the primary method is to use an +unquoted variable name. For \verb{_vec()} functions, a \code{numeric} vector.} + +\item{na_rm}{A \code{logical} value indicating whether \code{NA} +values should be stripped before the computation proceeds.} +} +\value{ +A \code{tibble} with columns \code{.metric}, \code{.estimator}, +and \code{.estimate} and 1 row of values. + +For grouped data frames, the number of rows returned will be the same as +the number of groups. + +For \code{kge_vec()}, a single \code{numeric} value (or \code{NA}). +} +\description{ +Calculate the Kling-Gupta Efficiency (\emph{Gupta et al., 2009}). +Dimensionless (from \eqn{-\infty} to 1). \code{kge()} assesses the accuracy of +simulated data by considering correlation, bias, and variability relative +to observed data. +} +\details{ +The Kling-Gupta Efficiency is a composite metric that decomposes model +performance into three components: correlation (\eqn{r}), +variability ratio (\eqn{\alpha}), and bias ratio (\eqn{\beta}). +It improves upon the Nash-Sutcliffe Efficiency (see \link{nse}) +by explicitly accounting for each source of error (\emph{Gupta et al., 2009}). + +The Kling-Gupta Efficiency is estimated as follows: +\deqn{ +KGE = 1 - \sqrt{(r - 1)^2 + (\alpha - 1)^2 + (\beta - 1)^2} +} +where: +\itemize{ +\item \eqn{r} is the linear Pearson correlation coefficient between +observed and simulated values +\item \eqn{\alpha = \sigma_{sim} / \sigma_{obs}} is the ratio of the +standard deviations (variability ratio) +\item \eqn{\beta = \mu_{sim} / \mu_{obs}} is the ratio of the +means (bias ratio) +} +} +\note{ +Unlike the Nash–Sutcliffe Efficiency (\link{nse}), the KGE does not have an +inherent benchmark such as "mean flow", and \eqn{KGE = 0} does not +correspond to a baseline performance. +Therefore, KGE values should not be interpreted as "good" or "bad" based +solely on their sign or magnitude. +Instead, users are encouraged to examine the individual components +(\eqn{r}, \eqn{\alpha}, \eqn{\beta}) +to understand the nature of model performance and consider defining +explicit benchmarks based on the study context. + +For further discussion, see Knoben et al. (2019), who caution against +directly translating NSE-based interpretation thresholds to KGE. +} +\examples{ +library(tidyhydro) +data(avacha) + +# Supply truth and predictions as bare column names +kge(avacha, obs, sim) + +# Or as numeric vectors +kge_vec(avacha$obs, avacha$sim) +} +\references{ +Gupta, H.V.; Kling, H.; Yilmaz, K.K.; Martinez, G.F. (2009). +Decomposition of the mean squared error and kge performance criteria: +Implications for improving hydrological modelling. Journal of Hydrology, +377(1-2), 80-91. \doi{10.1016/j.jhydrol.2009.08.003} + +Knoben, W. J. M., Freer, J. E., & Woods, R. A. (2019). +Technical note: Inherent benchmark or not? Comparing Nash–Sutcliffe and +Kling–Gupta efficiency scores. Hydrology and Earth System Sciences, 23, +4323–4331. \doi{10.5194/hess-23-4323-2019} +} +\seealso{ +Other numeric metrics: +\code{\link{kge2012}()}, +\code{\link{mse}()}, +\code{\link{nse}()}, +\code{\link{pbias}()}, +\code{\link{press}()}, +\code{\link{sfe}()} + +Other accuracy metrics: +\code{\link{kge2012}()}, +\code{\link{mse}()}, +\code{\link{nse}()}, +\code{\link{pbias}()}, +\code{\link{press}()}, +\code{\link{sfe}()} +} +\concept{accuracy metrics} +\concept{numeric metrics} diff --git a/man/kge2012.Rd b/man/kge2012.Rd index 5d41f0d..46e2037 100644 --- a/man/kge2012.Rd +++ b/man/kge2012.Rd @@ -1,128 +1,128 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/kge.R -\name{kge2012} -\alias{kge2012} -\alias{kge2012.data.frame} -\alias{kge2012_vec} -\title{Modified Kling-Gupta Efficiency (KGE')} -\usage{ -kge2012(data, ...) - -\method{kge2012}{data.frame}(data, truth, estimate, na_rm = TRUE, ...) - -kge2012_vec(truth, estimate, na_rm = TRUE, ...) -} -\arguments{ -\item{data}{A \code{data.frame} containing the columns specified by the \code{truth} -and \code{estimate} arguments.} - -\item{...}{Not currently used.} - -\item{truth}{The column identifier for the true results -(that is \code{numeric}). This should be an unquoted column name although -this argument is passed by expression and supports -\link[rlang:topic-inject]{quasiquotation} (you can unquote column -names). For \verb{_vec()} functions, a \code{numeric} vector.} - -\item{estimate}{The column identifier for the predicted -results (that is also \code{numeric}). As with \code{truth} this can be -specified different ways but the primary method is to use an -unquoted variable name. For \verb{_vec()} functions, a \code{numeric} vector.} - -\item{na_rm}{A \code{logical} value indicating whether \code{NA} -values should be stripped before the computation proceeds.} -} -\value{ -A \code{tibble} with columns \code{.metric}, \code{.estimator}, -and \code{.estimate} and 1 row of values. - -For grouped data frames, the number of rows returned will be the same as -the number of groups. - -For \code{kge2012_vec()}, a single \code{numeric} value (or \code{NA}). -} -\description{ -Calculate the modified Kling-Gupta Efficiency (\emph{Kling et al., 2012}), -aka \eqn{KGE'}. Dimensionless (from \eqn{-\infty} to 1). -\code{kge2012()} assesses the accuracy of -simulated data by considering correlation, bias, and variability relative -to observed data. -} -\details{ -The Modified Kling-Gupta Efficiency is a composite metric that decomposes -model performance into three components: correlation (\eqn{r}), -bias ratio (\eqn{\beta}), and variability ratio (\eqn{\gamma}). -It improves upon the Kling-Gupta Efficiency (see \link{kge}) by replacing -standard deviation with Coefficient of Variation. This ensures that the -bias and variability ratios are not cross-correlated, -which otherwise may occur when e.g. the precipitation inputs are biased. - -The Modified Kling-Gupta Efficiency (\eqn{KGE'}) is estimated as follows: -\deqn{ -KGE' = 1 - \sqrt{(r - 1)^2 + (\beta - 1)^2 + (\gamma - 1)^2} -} -where: -\itemize{ -\item \eqn{r} is the linear Pearson correlation coefficient between -observed and simulated values -\item \eqn{\beta = \mu_{sim} / \mu_{obs}} is the ratio of the -means (bias ratio) -\item \eqn{ - \gamma = \frac{\sigma_{sim} / \mu_{sim}}{\sigma_{sim} / \mu_{sim}} - } is the ratio of the Coefficients of Variation (variability ratio) -} -} -\note{ -Unlike the Nash–Sutcliffe Efficiency (\link{nse}), the KGE does not have an -inherent benchmark such as "mean flow", and \eqn{KGE' = 0} does not -correspond to a baseline performance. -Therefore, \eqn{KGE'} values should not be interpreted as "good" or "bad" -based solely on their sign or magnitude. -Instead, users are encouraged to examine the individual components -(\eqn{r}, \eqn{\beta}, \eqn{\gamma}) -to understand the nature of model performance and consider defining -explicit benchmarks based on the study context. - -For further discussion, see Knoben et al. (2019), who caution against -directly translating NSE-based interpretation thresholds to KGE. -} -\examples{ -library(tidyhydro) -data(avacha) - -# Supply truth and predictions as bare column names -kge2012(avacha, obs, sim) - -# Or as numeric vectors -kge2012_vec(avacha$obs, avacha$sim) -} -\references{ -Kling, H., Fuchs, M., & Paulin, M. (2012). Runoff conditions in the upper -Danube basin under an ensemble of climate change scenarios. -Journal of Hydrology, 424–425, 264–277. -\doi{10.1016/j.jhydrol.2012.01.011} - -Knoben, W. J. M., Freer, J. E., & Woods, R. A. (2019). -Technical note: Inherent benchmark or not? Comparing Nash–Sutcliffe and -Kling–Gupta efficiency scores. Hydrology and Earth System Sciences, 23, -4323–4331. \doi{10.5194/hess-23-4323-2019} -} -\seealso{ -Other numeric metrics: -\code{\link{kge}()}, -\code{\link{mse}()}, -\code{\link{nse}()}, -\code{\link{pbias}()}, -\code{\link{press}()}, -\code{\link{sfe}()} - -Other accuracy metrics: -\code{\link{kge}()}, -\code{\link{mse}()}, -\code{\link{nse}()}, -\code{\link{pbias}()}, -\code{\link{press}()}, -\code{\link{sfe}()} -} -\concept{accuracy metrics} -\concept{numeric metrics} +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/kge.R +\name{kge2012} +\alias{kge2012} +\alias{kge2012.data.frame} +\alias{kge2012_vec} +\title{Modified Kling-Gupta Efficiency (KGE')} +\usage{ +kge2012(data, ...) + +\method{kge2012}{data.frame}(data, truth, estimate, na_rm = TRUE, ...) + +kge2012_vec(truth, estimate, na_rm = TRUE, ...) +} +\arguments{ +\item{data}{A \code{data.frame} containing the columns specified by the \code{truth} +and \code{estimate} arguments.} + +\item{...}{Not currently used.} + +\item{truth}{The column identifier for the true results +(that is \code{numeric}). This should be an unquoted column name although +this argument is passed by expression and supports +\link[rlang:topic-inject]{quasiquotation} (you can unquote column +names). For \verb{_vec()} functions, a \code{numeric} vector.} + +\item{estimate}{The column identifier for the predicted +results (that is also \code{numeric}). As with \code{truth} this can be +specified different ways but the primary method is to use an +unquoted variable name. For \verb{_vec()} functions, a \code{numeric} vector.} + +\item{na_rm}{A \code{logical} value indicating whether \code{NA} +values should be stripped before the computation proceeds.} +} +\value{ +A \code{tibble} with columns \code{.metric}, \code{.estimator}, +and \code{.estimate} and 1 row of values. + +For grouped data frames, the number of rows returned will be the same as +the number of groups. + +For \code{kge2012_vec()}, a single \code{numeric} value (or \code{NA}). +} +\description{ +Calculate the modified Kling-Gupta Efficiency (\emph{Kling et al., 2012}), +aka \eqn{KGE'}. Dimensionless (from \eqn{-\infty} to 1). +\code{kge2012()} assesses the accuracy of +simulated data by considering correlation, bias, and variability relative +to observed data. +} +\details{ +The Modified Kling-Gupta Efficiency is a composite metric that decomposes +model performance into three components: correlation (\eqn{r}), +bias ratio (\eqn{\beta}), and variability ratio (\eqn{\gamma}). +It improves upon the Kling-Gupta Efficiency (see \link{kge}) by replacing +standard deviation with Coefficient of Variation. This ensures that the +bias and variability ratios are not cross-correlated, +which otherwise may occur when e.g. the precipitation inputs are biased. + +The Modified Kling-Gupta Efficiency (\eqn{KGE'}) is estimated as follows: +\deqn{ +KGE' = 1 - \sqrt{(r - 1)^2 + (\beta - 1)^2 + (\gamma - 1)^2} +} +where: +\itemize{ +\item \eqn{r} is the linear Pearson correlation coefficient between +observed and simulated values +\item \eqn{\beta = \mu_{sim} / \mu_{obs}} is the ratio of the +means (bias ratio) +\item \eqn{ + \gamma = \frac{\sigma_{sim} / \mu_{sim}}{\sigma_{sim} / \mu_{sim}} + } is the ratio of the Coefficients of Variation (variability ratio) +} +} +\note{ +Unlike the Nash–Sutcliffe Efficiency (\link{nse}), the KGE does not have an +inherent benchmark such as "mean flow", and \eqn{KGE' = 0} does not +correspond to a baseline performance. +Therefore, \eqn{KGE'} values should not be interpreted as "good" or "bad" +based solely on their sign or magnitude. +Instead, users are encouraged to examine the individual components +(\eqn{r}, \eqn{\beta}, \eqn{\gamma}) +to understand the nature of model performance and consider defining +explicit benchmarks based on the study context. + +For further discussion, see Knoben et al. (2019), who caution against +directly translating NSE-based interpretation thresholds to KGE. +} +\examples{ +library(tidyhydro) +data(avacha) + +# Supply truth and predictions as bare column names +kge2012(avacha, obs, sim) + +# Or as numeric vectors +kge2012_vec(avacha$obs, avacha$sim) +} +\references{ +Kling, H., Fuchs, M., & Paulin, M. (2012). Runoff conditions in the upper +Danube basin under an ensemble of climate change scenarios. +Journal of Hydrology, 424–425, 264–277. +\doi{10.1016/j.jhydrol.2012.01.011} + +Knoben, W. J. M., Freer, J. E., & Woods, R. A. (2019). +Technical note: Inherent benchmark or not? Comparing Nash–Sutcliffe and +Kling–Gupta efficiency scores. Hydrology and Earth System Sciences, 23, +4323–4331. \doi{10.5194/hess-23-4323-2019} +} +\seealso{ +Other numeric metrics: +\code{\link{kge}()}, +\code{\link{mse}()}, +\code{\link{nse}()}, +\code{\link{pbias}()}, +\code{\link{press}()}, +\code{\link{sfe}()} + +Other accuracy metrics: +\code{\link{kge}()}, +\code{\link{mse}()}, +\code{\link{nse}()}, +\code{\link{pbias}()}, +\code{\link{press}()}, +\code{\link{sfe}()} +} +\concept{accuracy metrics} +\concept{numeric metrics} diff --git a/man/mse.Rd b/man/mse.Rd index 531d79d..b47d84f 100644 --- a/man/mse.Rd +++ b/man/mse.Rd @@ -1,101 +1,101 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/mse.R -\name{mse} -\alias{mse} -\alias{mse.data.frame} -\alias{mse_vec} -\title{Mean Squared Error (MSE)} -\usage{ -mse(data, ...) - -\method{mse}{data.frame}(data, truth, estimate, na_rm = TRUE, ...) - -mse_vec(truth, estimate, na_rm = TRUE, ...) -} -\arguments{ -\item{data}{A \code{data.frame} containing the columns specified by the \code{truth} -and \code{estimate} arguments.} - -\item{...}{Not currently used.} - -\item{truth}{The column identifier for the true results -(that is \code{numeric}). This should be an unquoted column name although -this argument is passed by expression and supports -\link[rlang:topic-inject]{quasiquotation} (you can unquote column -names). For \verb{_vec()} functions, a \code{numeric} vector.} - -\item{estimate}{The column identifier for the predicted -results (that is also \code{numeric}). As with \code{truth} this can be -specified different ways but the primary method is to use an -unquoted variable name. For \verb{_vec()} functions, a \code{numeric} vector.} - -\item{na_rm}{A \code{logical} value indicating whether \code{NA} -values should be stripped before the computation proceeds.} -} -\value{ -A \code{tibble} with columns \code{.metric}, \code{.estimator}, -and \code{.estimate} and 1 row of values. - -For grouped data frames, the number of rows returned will be the same as -the number of groups. - -For \code{mse_vec()}, a single \code{numeric} value (or \code{NA}). -} -\description{ -The MSE is a metric that evaluates the goodness of fit between model -simulations and observations (\emph{Fisher, 1920}). Measured in the squared -units of \code{truth} and \code{estimate} and can vary from \eqn{-\infty} to -\eqn{+\infty}. -} -\details{ -The MSE is estimated as follows (Clark et al., 2021): -\deqn{ -MSE = \frac{1}{n} \sum_{i=1}^{n}{(sim_i - obs_i)^2} -} -where: -\itemize{ -\item \eqn{sim} defines model simulations at time step \eqn{i} -\item \eqn{obs} defines model observations at time step \eqn{i} -} -} -\examples{ -library(tidyhydro) -data(avacha) - -# Supply truth and predictions as bare column names -mse(avacha, obs, sim) - -# Or as numeric vectors -mse_vec(avacha$obs, avacha$sim) -} -\references{ -Fisher, R. A. (1920). Accuracy of observation, a mathematical -examination of the methods of determining, by the mean error and -by the mean square error. Monthly Notices of the Royal Astronomical -Society, 80, 758–770. \doi{10.1093/mnras/80.8.758} - -Clark, M. P., Vogel, R. M., Lamontagne, J. R., Mizukami, N., -Knoben, W. J. M., Tang, G., Gharari, S., Freer, J. E., Whitfield, -P. H., Shook, K. R., & Papalexiou, S. M. (2021). The Abuse of Popular -Performance Metrics in Hydrologic Modeling. Water Resources Research, 57(9), -e2020WR029001. \doi{10.1029/2020WR029001} -} -\seealso{ -Other numeric metrics: -\code{\link{kge}()}, -\code{\link{kge2012}()}, -\code{\link{nse}()}, -\code{\link{pbias}()}, -\code{\link{press}()}, -\code{\link{sfe}()} - -Other accuracy metrics: -\code{\link{kge}()}, -\code{\link{kge2012}()}, -\code{\link{nse}()}, -\code{\link{pbias}()}, -\code{\link{press}()}, -\code{\link{sfe}()} -} -\concept{accuracy metrics} -\concept{numeric metrics} +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/mse.R +\name{mse} +\alias{mse} +\alias{mse.data.frame} +\alias{mse_vec} +\title{Mean Squared Error (MSE)} +\usage{ +mse(data, ...) + +\method{mse}{data.frame}(data, truth, estimate, na_rm = TRUE, ...) + +mse_vec(truth, estimate, na_rm = TRUE, ...) +} +\arguments{ +\item{data}{A \code{data.frame} containing the columns specified by the \code{truth} +and \code{estimate} arguments.} + +\item{...}{Not currently used.} + +\item{truth}{The column identifier for the true results +(that is \code{numeric}). This should be an unquoted column name although +this argument is passed by expression and supports +\link[rlang:topic-inject]{quasiquotation} (you can unquote column +names). For \verb{_vec()} functions, a \code{numeric} vector.} + +\item{estimate}{The column identifier for the predicted +results (that is also \code{numeric}). As with \code{truth} this can be +specified different ways but the primary method is to use an +unquoted variable name. For \verb{_vec()} functions, a \code{numeric} vector.} + +\item{na_rm}{A \code{logical} value indicating whether \code{NA} +values should be stripped before the computation proceeds.} +} +\value{ +A \code{tibble} with columns \code{.metric}, \code{.estimator}, +and \code{.estimate} and 1 row of values. + +For grouped data frames, the number of rows returned will be the same as +the number of groups. + +For \code{mse_vec()}, a single \code{numeric} value (or \code{NA}). +} +\description{ +The MSE is a metric that evaluates the goodness of fit between model +simulations and observations (\emph{Fisher, 1920}). Measured in the squared +units of \code{truth} and \code{estimate} and can vary from \eqn{-\infty} to +\eqn{+\infty}. +} +\details{ +The MSE is estimated as follows (Clark et al., 2021): +\deqn{ +MSE = \frac{1}{n} \sum_{i=1}^{n}{(sim_i - obs_i)^2} +} +where: +\itemize{ +\item \eqn{sim} defines model simulations at time step \eqn{i} +\item \eqn{obs} defines model observations at time step \eqn{i} +} +} +\examples{ +library(tidyhydro) +data(avacha) + +# Supply truth and predictions as bare column names +mse(avacha, obs, sim) + +# Or as numeric vectors +mse_vec(avacha$obs, avacha$sim) +} +\references{ +Fisher, R. A. (1920). Accuracy of observation, a mathematical +examination of the methods of determining, by the mean error and +by the mean square error. Monthly Notices of the Royal Astronomical +Society, 80, 758–770. \doi{10.1093/mnras/80.8.758} + +Clark, M. P., Vogel, R. M., Lamontagne, J. R., Mizukami, N., +Knoben, W. J. M., Tang, G., Gharari, S., Freer, J. E., Whitfield, +P. H., Shook, K. R., & Papalexiou, S. M. (2021). The Abuse of Popular +Performance Metrics in Hydrologic Modeling. Water Resources Research, 57(9), +e2020WR029001. \doi{10.1029/2020WR029001} +} +\seealso{ +Other numeric metrics: +\code{\link{kge}()}, +\code{\link{kge2012}()}, +\code{\link{nse}()}, +\code{\link{pbias}()}, +\code{\link{press}()}, +\code{\link{sfe}()} + +Other accuracy metrics: +\code{\link{kge}()}, +\code{\link{kge2012}()}, +\code{\link{nse}()}, +\code{\link{pbias}()}, +\code{\link{press}()}, +\code{\link{sfe}()} +} +\concept{accuracy metrics} +\concept{numeric metrics} diff --git a/man/nse.Rd b/man/nse.Rd index 462a31d..27a862c 100644 --- a/man/nse.Rd +++ b/man/nse.Rd @@ -1,120 +1,120 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/nse.R -\name{nse} -\alias{nse} -\alias{nse.data.frame} -\alias{nse_vec} -\title{Nash-Sutcliffe Efficiency (NSE)} -\usage{ -nse(data, ...) - -\method{nse}{data.frame}(data, truth, estimate, na_rm = TRUE, performance = FALSE, ...) - -nse_vec(truth, estimate, na_rm = TRUE, performance = FALSE, ...) -} -\arguments{ -\item{data}{A \code{data.frame} containing the columns specified by the \code{truth} -and \code{estimate} arguments.} - -\item{...}{Not currently used.} - -\item{truth}{The column identifier for the true results -(that is \code{numeric}). This should be an unquoted column name although -this argument is passed by expression and supports -\link[rlang:topic-inject]{quasiquotation} (you can unquote column -names). For \verb{_vec()} functions, a \code{numeric} vector.} - -\item{estimate}{The column identifier for the predicted -results (that is also \code{numeric}). As with \code{truth} this can be -specified different ways but the primary method is to use an -unquoted variable name. For \verb{_vec()} functions, a \code{numeric} vector.} - -\item{na_rm}{A \code{logical} value indicating whether \code{NA} -values should be stripped before the computation proceeds.} - -\item{performance}{The optional column, indicating should the \code{nse()} return -metric interpretation. See details.} -} -\value{ -A \code{tibble} with columns \code{.metric}, \code{.estimator}, -and \code{.estimate} and 1 row of values. - -For grouped data frames, the number of rows returned will be the same as -the number of groups. - -For \code{nse_vec()}, a single \code{numeric} value (or \code{NA}). -} -\description{ -Calculate the Nash-Sutcliffe efficiency (\emph{Nash & Sutcliffe, 1970}). -Dimensionless (from \eqn{-\infty} to 1). \code{nse()} indicates how well the plot -of observed versus simulated data fits the 1:1 line. -} -\details{ -The Nash-Sutcliffe efficiency is a normalized statistic that determines -the relative magnitude of the residual variance ("noise") compared to the -measured data variance ("information"; \emph{Nash and Sutcliffe, 1970}). - -The formula for NSE is: - -\deqn{ - NSE = 1 - \frac{ - \sum_{i=1}^{n}{(sim_i - obs_i)^2} - }{ - \sum_{i=1}^{n}{(obs_i - \mu_{obs})^2} - } -} -where: -\itemize{ -\item \eqn{sim} defines model simulations at time step \eqn{i} -\item \eqn{obs} defines model observations at time step \eqn{i} -\item \eqn{\mu_{obs}} defines mean of model observations -} - -According to Moriasi et al. (2015) the metric interpretation can be -as follows: -\itemize{ -\item \strong{Excellent}/\strong{Very Good} -- \code{nse()} > 0.8 -\item \strong{Good} -- 0.6 <= \code{nse()} <= 0.8 -\item \strong{Satisfactory} -- 0.5 < \code{nse()} < 0.6 -\item \strong{Poor} -- \code{nse()} <= 0.5 -} -} -\examples{ -library(tidyhydro) -data(avacha) - -# Supply truth and predictions as bare column names -nse(avacha, obs, sim) - -# Or as numeric vectors -nse_vec(avacha$obs, avacha$sim) -} -\references{ -Nash, J. E., & Sutcliffe, J. V. (1970). River flow forecasting through -conceptual models part I — A discussion of principles. Journal of Hydrology, -10(3), 282–290. \doi{10.1016/0022-1694(70)90255-6} - -Moriasi, D. N., Gitau, M. W., Pai, N., & Daggupati, P. (2015). Hydrologic -and Water Quality Models: Performance Measures and Evaluation Criteria. -Transactions of the ASABE, 58(6), 1763–1785. -\doi{10.13031/trans.58.10715} -} -\seealso{ -Other numeric metrics: -\code{\link{kge}()}, -\code{\link{kge2012}()}, -\code{\link{mse}()}, -\code{\link{pbias}()}, -\code{\link{press}()}, -\code{\link{sfe}()} - -Other accuracy metrics: -\code{\link{kge}()}, -\code{\link{kge2012}()}, -\code{\link{mse}()}, -\code{\link{pbias}()}, -\code{\link{press}()}, -\code{\link{sfe}()} -} -\concept{accuracy metrics} -\concept{numeric metrics} +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/nse.R +\name{nse} +\alias{nse} +\alias{nse.data.frame} +\alias{nse_vec} +\title{Nash-Sutcliffe Efficiency (NSE)} +\usage{ +nse(data, ...) + +\method{nse}{data.frame}(data, truth, estimate, na_rm = TRUE, performance = FALSE, ...) + +nse_vec(truth, estimate, na_rm = TRUE, performance = FALSE, ...) +} +\arguments{ +\item{data}{A \code{data.frame} containing the columns specified by the \code{truth} +and \code{estimate} arguments.} + +\item{...}{Not currently used.} + +\item{truth}{The column identifier for the true results +(that is \code{numeric}). This should be an unquoted column name although +this argument is passed by expression and supports +\link[rlang:topic-inject]{quasiquotation} (you can unquote column +names). For \verb{_vec()} functions, a \code{numeric} vector.} + +\item{estimate}{The column identifier for the predicted +results (that is also \code{numeric}). As with \code{truth} this can be +specified different ways but the primary method is to use an +unquoted variable name. For \verb{_vec()} functions, a \code{numeric} vector.} + +\item{na_rm}{A \code{logical} value indicating whether \code{NA} +values should be stripped before the computation proceeds.} + +\item{performance}{The optional column, indicating should the \code{nse()} return +metric interpretation. See details.} +} +\value{ +A \code{tibble} with columns \code{.metric}, \code{.estimator}, +and \code{.estimate} and 1 row of values. + +For grouped data frames, the number of rows returned will be the same as +the number of groups. + +For \code{nse_vec()}, a single \code{numeric} value (or \code{NA}). +} +\description{ +Calculate the Nash-Sutcliffe efficiency (\emph{Nash & Sutcliffe, 1970}). +Dimensionless (from \eqn{-\infty} to 1). \code{nse()} indicates how well the plot +of observed versus simulated data fits the 1:1 line. +} +\details{ +The Nash-Sutcliffe efficiency is a normalized statistic that determines +the relative magnitude of the residual variance ("noise") compared to the +measured data variance ("information"; \emph{Nash and Sutcliffe, 1970}). + +The formula for NSE is: + +\deqn{ + NSE = 1 - \frac{ + \sum_{i=1}^{n}{(sim_i - obs_i)^2} + }{ + \sum_{i=1}^{n}{(obs_i - \mu_{obs})^2} + } +} +where: +\itemize{ +\item \eqn{sim} defines model simulations at time step \eqn{i} +\item \eqn{obs} defines model observations at time step \eqn{i} +\item \eqn{\mu_{obs}} defines mean of model observations +} + +According to Moriasi et al. (2015) the metric interpretation can be +as follows: +\itemize{ +\item \strong{Excellent}/\strong{Very Good} -- \code{nse()} > 0.8 +\item \strong{Good} -- 0.6 <= \code{nse()} <= 0.8 +\item \strong{Satisfactory} -- 0.5 < \code{nse()} < 0.6 +\item \strong{Poor} -- \code{nse()} <= 0.5 +} +} +\examples{ +library(tidyhydro) +data(avacha) + +# Supply truth and predictions as bare column names +nse(avacha, obs, sim) + +# Or as numeric vectors +nse_vec(avacha$obs, avacha$sim) +} +\references{ +Nash, J. E., & Sutcliffe, J. V. (1970). River flow forecasting through +conceptual models part I — A discussion of principles. Journal of Hydrology, +10(3), 282–290. \doi{10.1016/0022-1694(70)90255-6} + +Moriasi, D. N., Gitau, M. W., Pai, N., & Daggupati, P. (2015). Hydrologic +and Water Quality Models: Performance Measures and Evaluation Criteria. +Transactions of the ASABE, 58(6), 1763–1785. +\doi{10.13031/trans.58.10715} +} +\seealso{ +Other numeric metrics: +\code{\link{kge}()}, +\code{\link{kge2012}()}, +\code{\link{mse}()}, +\code{\link{pbias}()}, +\code{\link{press}()}, +\code{\link{sfe}()} + +Other accuracy metrics: +\code{\link{kge}()}, +\code{\link{kge2012}()}, +\code{\link{mse}()}, +\code{\link{pbias}()}, +\code{\link{press}()}, +\code{\link{sfe}()} +} +\concept{accuracy metrics} +\concept{numeric metrics} diff --git a/man/pbias.Rd b/man/pbias.Rd index ba791f7..e9a79f4 100644 --- a/man/pbias.Rd +++ b/man/pbias.Rd @@ -1,118 +1,118 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/pbias.R -\name{pbias} -\alias{pbias} -\alias{pbias.data.frame} -\alias{pbias_vec} -\title{Percent BIAS (pBIAS)} -\usage{ -pbias(data, ...) - -\method{pbias}{data.frame}(data, truth, estimate, na_rm = TRUE, performance = FALSE, ...) - -pbias_vec(truth, estimate, na_rm = TRUE, performance = FALSE, ...) -} -\arguments{ -\item{data}{A \code{data.frame} containing the columns specified by the \code{truth} -and \code{estimate} arguments.} - -\item{...}{Not currently used.} - -\item{truth}{The column identifier for the true results -(that is \code{numeric}). This should be an unquoted column name although -this argument is passed by expression and supports -\link[rlang:topic-inject]{quasiquotation} (you can unquote column -names). For \verb{_vec()} functions, a \code{numeric} vector.} - -\item{estimate}{The column identifier for the predicted -results (that is also \code{numeric}). As with \code{truth} this can be -specified different ways but the primary method is to use an -unquoted variable name. For \verb{_vec()} functions, a \code{numeric} vector.} - -\item{na_rm}{A \code{logical} value indicating whether \code{NA} -values should be stripped before the computation proceeds.} - -\item{performance}{The optional column, indicating should the \code{pbias()} -return metric interpretation. See details.} -} -\value{ -A \code{tibble} with columns \code{.metric}, \code{.estimator}, -and \code{.estimate} and 1 row of values. - -For grouped data frames, the number of rows returned will be the same as -the number of groups. - -For \code{pbias_vec()}, a single \code{numeric} value (or \code{NA}). -} -\description{ -\eqn{pBIAS} is the deviation of data being evaluated, expressed as a -percentage. It measures the average tendency of the simulated data to be -larger or smaller than their observed counterparts (\emph{Moriasi et al., 2015}). -The optimal value of \eqn{pBIAS} is 0.0, with low-magnitude values -indicating accurate mode simulation. Positive values indicate model -underestimation bias, and negative values indicate model overestimation -bias (\emph{Gupta et al., 1999}). -} -\details{ -The formula for \eqn{pBIAS} is: - -\deqn{ - pBIAS = 100 \times \frac{\sum_{i=1}^{n}{(sim_i - obs_i)}} - {\sum_{i=1}^{n}{obs_i}} -} - -where: -\itemize{ -\item \eqn{sim} defines model simulations at time step \eqn{i} -\item \eqn{obs} defines model observations at time step \eqn{i} -} - -According to Moriasi et al. (2015) the metric interpretation can be as -follows: -\itemize{ -\item \strong{Excellent}/\strong{Very Good} -- \code{pbias()} < ±5.0 -\item \strong{Good} -- ±5.0 <= \code{pbias()} < ±10.0 -\item \strong{Satisfactory} -- ±10.0 <= \code{pbias()} < ±15.0 -\item \strong{Poor} -- \code{pbias()} >= ±15.0 -} -} -\examples{ -library(tidyhydro) -data(avacha) - -# Supply truth and predictions as bare column names -pbias(avacha, obs, sim) - -# Or as numeric vectors -pbias_vec(avacha$obs, avacha$sim) -} -\references{ -Moriasi, D. N., Gitau, M. W., Pai, N., & Daggupati, P. (2015). Hydrologic -and Water Quality Models: Performance Measures and Evaluation Criteria. -Transactions of the ASABE, 58(6), 1763–1785. -\doi{10.13031/trans.58.10715} - -Gupta, H. V., S. Sorooshian, and P. O. Yapo. (1999). -Status of automatic calibration for hydrologic models: Comparison with -multilevel expert calibration. J. Hydrologic Eng. 4(2): 135-143 -\doi{10.1061/(ASCE)1084-0699(1999)4:2(135)} -} -\seealso{ -Other numeric metrics: -\code{\link{kge}()}, -\code{\link{kge2012}()}, -\code{\link{mse}()}, -\code{\link{nse}()}, -\code{\link{press}()}, -\code{\link{sfe}()} - -Other accuracy metrics: -\code{\link{kge}()}, -\code{\link{kge2012}()}, -\code{\link{mse}()}, -\code{\link{nse}()}, -\code{\link{press}()}, -\code{\link{sfe}()} -} -\concept{accuracy metrics} -\concept{numeric metrics} +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/pbias.R +\name{pbias} +\alias{pbias} +\alias{pbias.data.frame} +\alias{pbias_vec} +\title{Percent BIAS (pBIAS)} +\usage{ +pbias(data, ...) + +\method{pbias}{data.frame}(data, truth, estimate, na_rm = TRUE, performance = FALSE, ...) + +pbias_vec(truth, estimate, na_rm = TRUE, performance = FALSE, ...) +} +\arguments{ +\item{data}{A \code{data.frame} containing the columns specified by the \code{truth} +and \code{estimate} arguments.} + +\item{...}{Not currently used.} + +\item{truth}{The column identifier for the true results +(that is \code{numeric}). This should be an unquoted column name although +this argument is passed by expression and supports +\link[rlang:topic-inject]{quasiquotation} (you can unquote column +names). For \verb{_vec()} functions, a \code{numeric} vector.} + +\item{estimate}{The column identifier for the predicted +results (that is also \code{numeric}). As with \code{truth} this can be +specified different ways but the primary method is to use an +unquoted variable name. For \verb{_vec()} functions, a \code{numeric} vector.} + +\item{na_rm}{A \code{logical} value indicating whether \code{NA} +values should be stripped before the computation proceeds.} + +\item{performance}{The optional column, indicating should the \code{pbias()} +return metric interpretation. See details.} +} +\value{ +A \code{tibble} with columns \code{.metric}, \code{.estimator}, +and \code{.estimate} and 1 row of values. + +For grouped data frames, the number of rows returned will be the same as +the number of groups. + +For \code{pbias_vec()}, a single \code{numeric} value (or \code{NA}). +} +\description{ +\eqn{pBIAS} is the deviation of data being evaluated, expressed as a +percentage. It measures the average tendency of the simulated data to be +larger or smaller than their observed counterparts (\emph{Moriasi et al., 2015}). +The optimal value of \eqn{pBIAS} is 0.0, with low-magnitude values +indicating accurate mode simulation. Positive values indicate model +underestimation bias, and negative values indicate model overestimation +bias (\emph{Gupta et al., 1999}). +} +\details{ +The formula for \eqn{pBIAS} is: + +\deqn{ + pBIAS = 100 \times \frac{\sum_{i=1}^{n}{(sim_i - obs_i)}} + {\sum_{i=1}^{n}{obs_i}} +} + +where: +\itemize{ +\item \eqn{sim} defines model simulations at time step \eqn{i} +\item \eqn{obs} defines model observations at time step \eqn{i} +} + +According to Moriasi et al. (2015) the metric interpretation can be as +follows: +\itemize{ +\item \strong{Excellent}/\strong{Very Good} -- \code{pbias()} < ±5.0 +\item \strong{Good} -- ±5.0 <= \code{pbias()} < ±10.0 +\item \strong{Satisfactory} -- ±10.0 <= \code{pbias()} < ±15.0 +\item \strong{Poor} -- \code{pbias()} >= ±15.0 +} +} +\examples{ +library(tidyhydro) +data(avacha) + +# Supply truth and predictions as bare column names +pbias(avacha, obs, sim) + +# Or as numeric vectors +pbias_vec(avacha$obs, avacha$sim) +} +\references{ +Moriasi, D. N., Gitau, M. W., Pai, N., & Daggupati, P. (2015). Hydrologic +and Water Quality Models: Performance Measures and Evaluation Criteria. +Transactions of the ASABE, 58(6), 1763–1785. +\doi{10.13031/trans.58.10715} + +Gupta, H. V., S. Sorooshian, and P. O. Yapo. (1999). +Status of automatic calibration for hydrologic models: Comparison with +multilevel expert calibration. J. Hydrologic Eng. 4(2): 135-143 +\doi{10.1061/(ASCE)1084-0699(1999)4:2(135)} +} +\seealso{ +Other numeric metrics: +\code{\link{kge}()}, +\code{\link{kge2012}()}, +\code{\link{mse}()}, +\code{\link{nse}()}, +\code{\link{press}()}, +\code{\link{sfe}()} + +Other accuracy metrics: +\code{\link{kge}()}, +\code{\link{kge2012}()}, +\code{\link{mse}()}, +\code{\link{nse}()}, +\code{\link{press}()}, +\code{\link{sfe}()} +} +\concept{accuracy metrics} +\concept{numeric metrics} diff --git a/man/press.Rd b/man/press.Rd index 9ed2078..c452332 100644 --- a/man/press.Rd +++ b/man/press.Rd @@ -1,117 +1,117 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/press.R -\name{press} -\alias{press} -\alias{press.data.frame} -\alias{press_vec} -\title{PRediction Error Sum of Squares (PRESS)} -\usage{ -press(data, ...) - -\method{press}{data.frame}(data, truth, estimate, na_rm = TRUE, ...) - -press_vec(truth, estimate, na_rm = TRUE, ...) -} -\arguments{ -\item{data}{A \code{data.frame} containing the columns specified by the \code{truth} -and \code{estimate} arguments.} - -\item{...}{Not currently used.} - -\item{truth}{The column identifier for the true results -(that is \code{numeric}). This should be an unquoted column name although -this argument is passed by expression and supports -\link[rlang:topic-inject]{quasiquotation} (you can unquote column -names). For \verb{_vec()} functions, a \code{numeric} vector.} - -\item{estimate}{The column identifier for the predicted -results (that is also \code{numeric}). As with \code{truth} this can be -specified different ways but the primary method is to use an -unquoted variable name. For \verb{_vec()} functions, a \code{numeric} vector.} - -\item{na_rm}{A \code{logical} value indicating whether \code{NA} -values should be stripped before the computation proceeds.} -} -\value{ -A \code{tibble} with columns \code{.metric}, \code{.estimator}, -and \code{.estimate} and 1 row of values. - -For grouped data frames, the number of rows returned will be the same as -the number of groups. - -For \code{press_vec()}, a single \code{numeric} value (or \code{NA}). -} -\description{ -\eqn{PRESS} is a measure of the quality of a regression model using -residuals. \eqn{PRESS} is a validation-type estimator of error that uses -the deleted residuals to provide an estimate of the prediction error. -When comparing alternate regression models, selecting the model with the -lowest value of the \eqn{PRESS} statistic is a good approach because it -means that the equation produces the least error when making new predictions -(see \emph{Helsel et al., 2020}). - -It is particularly valuable in assessing multiple forms of multiple -linear regressions, but it is also useful for -simply comparing different options for a single explanatory variable in -single-variable regression models. -} -\details{ -The \eqn{PRESS} is only relevant for comparisons to other regression models -with the same response variable units (\emph{Rasmunsen et al., 2009}). - -It estimates as follows: -\deqn{ - PRESS = \sum_{i=1}^{n}{(sim_i - obs_i)^2} -} - -where: -\itemize{ -\item \eqn{sim} defines model simulations at time step \eqn{i} -\item \eqn{obs} defines model observations at time step \eqn{i} -} -} -\note{ -The $PRESS$ statistic is not appropriate for comparison of models having -different transformations of response variable, e.g. linear regression and -log-transformed linear regression (\emph{Helsel et al., 2020}). -} -\examples{ -library(tidyhydro) -data(avacha) - -# Supply truth and predictions as bare column names -press(avacha, obs, sim) - -# Or as numeric vectors -press_vec(avacha$obs, avacha$sim) -} -\references{ -Rasmussen, P. P., Gray, J. R., Glysson, G. D. & Ziegler, A. C. -Guidelines and procedures for computing time-series suspended-sediment -concentrations and loads from in-stream turbidity-sensor and streamflow -data. in U.S. Geological Survey Techniques and Methods book 3, chap. -C4 53 (2009) \url{https://pubs.usgs.gov/tm/tm3c4/}. - -Helsel, D. R., Hirsch, R. M., Ryberg, K. R., Archfield, S. A. & -Gilroy, E. J. Statistical Methods in Water Resources. 484 (2020) -\doi{10.3133/tm4A3}. -} -\seealso{ -Other numeric metrics: -\code{\link{kge}()}, -\code{\link{kge2012}()}, -\code{\link{mse}()}, -\code{\link{nse}()}, -\code{\link{pbias}()}, -\code{\link{sfe}()} - -Other accuracy metrics: -\code{\link{kge}()}, -\code{\link{kge2012}()}, -\code{\link{mse}()}, -\code{\link{nse}()}, -\code{\link{pbias}()}, -\code{\link{sfe}()} -} -\concept{accuracy metrics} -\concept{numeric metrics} +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/press.R +\name{press} +\alias{press} +\alias{press.data.frame} +\alias{press_vec} +\title{PRediction Error Sum of Squares (PRESS)} +\usage{ +press(data, ...) + +\method{press}{data.frame}(data, truth, estimate, na_rm = TRUE, ...) + +press_vec(truth, estimate, na_rm = TRUE, ...) +} +\arguments{ +\item{data}{A \code{data.frame} containing the columns specified by the \code{truth} +and \code{estimate} arguments.} + +\item{...}{Not currently used.} + +\item{truth}{The column identifier for the true results +(that is \code{numeric}). This should be an unquoted column name although +this argument is passed by expression and supports +\link[rlang:topic-inject]{quasiquotation} (you can unquote column +names). For \verb{_vec()} functions, a \code{numeric} vector.} + +\item{estimate}{The column identifier for the predicted +results (that is also \code{numeric}). As with \code{truth} this can be +specified different ways but the primary method is to use an +unquoted variable name. For \verb{_vec()} functions, a \code{numeric} vector.} + +\item{na_rm}{A \code{logical} value indicating whether \code{NA} +values should be stripped before the computation proceeds.} +} +\value{ +A \code{tibble} with columns \code{.metric}, \code{.estimator}, +and \code{.estimate} and 1 row of values. + +For grouped data frames, the number of rows returned will be the same as +the number of groups. + +For \code{press_vec()}, a single \code{numeric} value (or \code{NA}). +} +\description{ +\eqn{PRESS} is a measure of the quality of a regression model using +residuals. \eqn{PRESS} is a validation-type estimator of error that uses +the deleted residuals to provide an estimate of the prediction error. +When comparing alternate regression models, selecting the model with the +lowest value of the \eqn{PRESS} statistic is a good approach because it +means that the equation produces the least error when making new predictions +(see \emph{Helsel et al., 2020}). + +It is particularly valuable in assessing multiple forms of multiple +linear regressions, but it is also useful for +simply comparing different options for a single explanatory variable in +single-variable regression models. +} +\details{ +The \eqn{PRESS} is only relevant for comparisons to other regression models +with the same response variable units (\emph{Rasmunsen et al., 2009}). + +It estimates as follows: +\deqn{ + PRESS = \sum_{i=1}^{n}{(sim_i - obs_i)^2} +} + +where: +\itemize{ +\item \eqn{sim} defines model simulations at time step \eqn{i} +\item \eqn{obs} defines model observations at time step \eqn{i} +} +} +\note{ +The $PRESS$ statistic is not appropriate for comparison of models having +different transformations of response variable, e.g. linear regression and +log-transformed linear regression (\emph{Helsel et al., 2020}). +} +\examples{ +library(tidyhydro) +data(avacha) + +# Supply truth and predictions as bare column names +press(avacha, obs, sim) + +# Or as numeric vectors +press_vec(avacha$obs, avacha$sim) +} +\references{ +Rasmussen, P. P., Gray, J. R., Glysson, G. D. & Ziegler, A. C. +Guidelines and procedures for computing time-series suspended-sediment +concentrations and loads from in-stream turbidity-sensor and streamflow +data. in U.S. Geological Survey Techniques and Methods book 3, chap. +C4 53 (2009) \url{https://pubs.usgs.gov/tm/tm3c4/}. + +Helsel, D. R., Hirsch, R. M., Ryberg, K. R., Archfield, S. A. & +Gilroy, E. J. Statistical Methods in Water Resources. 484 (2020) +\doi{10.3133/tm4A3}. +} +\seealso{ +Other numeric metrics: +\code{\link{kge}()}, +\code{\link{kge2012}()}, +\code{\link{mse}()}, +\code{\link{nse}()}, +\code{\link{pbias}()}, +\code{\link{sfe}()} + +Other accuracy metrics: +\code{\link{kge}()}, +\code{\link{kge2012}()}, +\code{\link{mse}()}, +\code{\link{nse}()}, +\code{\link{pbias}()}, +\code{\link{sfe}()} +} +\concept{accuracy metrics} +\concept{numeric metrics} diff --git a/man/sfe.Rd b/man/sfe.Rd index 58b51b0..82cd842 100644 --- a/man/sfe.Rd +++ b/man/sfe.Rd @@ -1,106 +1,106 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/sfe.R -\name{sfe} -\alias{sfe} -\alias{sfe.data.frame} -\alias{sfe_vec} -\title{Standard Factorial Error (SFE)} -\usage{ -sfe(data, ...) - -\method{sfe}{data.frame}(data, truth, estimate, na_rm = TRUE, ...) - -sfe_vec(truth, estimate, na_rm = TRUE, ...) -} -\arguments{ -\item{data}{A \code{data.frame} containing the columns specified by the \code{truth} -and \code{estimate} arguments.} - -\item{...}{Not currently used.} - -\item{truth}{The column identifier for the true results -(that is \code{numeric}). This should be an unquoted column name although -this argument is passed by expression and supports -\link[rlang:topic-inject]{quasiquotation} (you can unquote column -names). For \verb{_vec()} functions, a \code{numeric} vector.} - -\item{estimate}{The column identifier for the predicted -results (that is also \code{numeric}). As with \code{truth} this can be -specified different ways but the primary method is to use an -unquoted variable name. For \verb{_vec()} functions, a \code{numeric} vector.} - -\item{na_rm}{A \code{logical} value indicating whether \code{NA} -values should be stripped before the computation proceeds.} -} -\value{ -A \code{tibble} with columns \code{.metric}, \code{.estimator}, -and \code{.estimate} and 1 row of values. - -For grouped data frames, the number of rows returned will be the same as -the number of groups. - -For \code{sfe_vec()}, a single \code{numeric} value (or \code{NA}). -} -\description{ -Prediction standard factorial error estimated -using standard regression methods (see \emph{Herschy, 1978}). -} -\details{ -The metric is widely used for assessing Sediment Rating Curves -(e.g., Hicks et al. 2020). The model is usually considered 'unacceptable' -if the \eqn{SFE > 2}, see Hicks et al. (2011). - -It is estimated as follows: -\deqn{SFE = \exp\left(\sqrt{\frac{1}{n} \sum_{i=1}^{n} -\left( \log\left(\frac{obs_i}{sim_i} \right) \right)^2 }\right)} -where: -\itemize{ -\item \eqn{sim} defines model simulations at time step \eqn{i} -\item \eqn{obs} defines model observations at time step \eqn{i} -} -} -\examples{ -library(tidyhydro) -data(avacha) - -# Supply truth and predictions as bare column names -sfe(avacha, obs, sim) - -# Or as numeric vectors -sfe_vec(avacha$obs, avacha$sim) -} -\references{ -Herschy, R.W. 1978: Accuracy. Chapter 10 In: Herschy, R.W. (ed.) -Hydrometry - principles and practices. John Wiley and Sons, Chichester, -511 p. - -Hicks, D. M., Shankar, U., McKerchar, A. I., Basher, L., Lynn, I., -Page, M., & Jessen, M. (2011). Suspended Sediment Yields from New Zealand -Rivers. Journal of Hydrology (New Zealand), 50(1), 81–142. -\doi{10.3316/informit.315190637227597} - -Hicks, M., Doyle, M., Watson, J., Holwerda, N., Lynch, B., Wyatt, J., -Jones, H., & Hill, R. (2020). Measurement of Fluvial Suspended Sediment -Load and its Composition (No. 1.0.0; National Environmental Monitoring -Standards, p. 138). -\url{https://www.nems.org.nz/documents/suspended-sediment} -} -\seealso{ -Other numeric metrics: -\code{\link{kge}()}, -\code{\link{kge2012}()}, -\code{\link{mse}()}, -\code{\link{nse}()}, -\code{\link{pbias}()}, -\code{\link{press}()} - -Other accuracy metrics: -\code{\link{kge}()}, -\code{\link{kge2012}()}, -\code{\link{mse}()}, -\code{\link{nse}()}, -\code{\link{pbias}()}, -\code{\link{press}()} -} -\concept{accuracy metrics} -\concept{numeric metrics} +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/sfe.R +\name{sfe} +\alias{sfe} +\alias{sfe.data.frame} +\alias{sfe_vec} +\title{Standard Factorial Error (SFE)} +\usage{ +sfe(data, ...) + +\method{sfe}{data.frame}(data, truth, estimate, na_rm = TRUE, ...) + +sfe_vec(truth, estimate, na_rm = TRUE, ...) +} +\arguments{ +\item{data}{A \code{data.frame} containing the columns specified by the \code{truth} +and \code{estimate} arguments.} + +\item{...}{Not currently used.} + +\item{truth}{The column identifier for the true results +(that is \code{numeric}). This should be an unquoted column name although +this argument is passed by expression and supports +\link[rlang:topic-inject]{quasiquotation} (you can unquote column +names). For \verb{_vec()} functions, a \code{numeric} vector.} + +\item{estimate}{The column identifier for the predicted +results (that is also \code{numeric}). As with \code{truth} this can be +specified different ways but the primary method is to use an +unquoted variable name. For \verb{_vec()} functions, a \code{numeric} vector.} + +\item{na_rm}{A \code{logical} value indicating whether \code{NA} +values should be stripped before the computation proceeds.} +} +\value{ +A \code{tibble} with columns \code{.metric}, \code{.estimator}, +and \code{.estimate} and 1 row of values. + +For grouped data frames, the number of rows returned will be the same as +the number of groups. + +For \code{sfe_vec()}, a single \code{numeric} value (or \code{NA}). +} +\description{ +Prediction standard factorial error estimated +using standard regression methods (see \emph{Herschy, 1978}). +} +\details{ +The metric is widely used for assessing Sediment Rating Curves +(e.g., Hicks et al. 2020). The model is usually considered 'unacceptable' +if the \eqn{SFE > 2}, see Hicks et al. (2011). + +It is estimated as follows: +\deqn{SFE = \exp\left(\sqrt{\frac{1}{n} \sum_{i=1}^{n} +\left( \log\left(\frac{obs_i}{sim_i} \right) \right)^2 }\right)} +where: +\itemize{ +\item \eqn{sim} defines model simulations at time step \eqn{i} +\item \eqn{obs} defines model observations at time step \eqn{i} +} +} +\examples{ +library(tidyhydro) +data(avacha) + +# Supply truth and predictions as bare column names +sfe(avacha, obs, sim) + +# Or as numeric vectors +sfe_vec(avacha$obs, avacha$sim) +} +\references{ +Herschy, R.W. 1978: Accuracy. Chapter 10 In: Herschy, R.W. (ed.) +Hydrometry - principles and practices. John Wiley and Sons, Chichester, +511 p. + +Hicks, D. M., Shankar, U., McKerchar, A. I., Basher, L., Lynn, I., +Page, M., & Jessen, M. (2011). Suspended Sediment Yields from New Zealand +Rivers. Journal of Hydrology (New Zealand), 50(1), 81–142. +\doi{10.3316/informit.315190637227597} + +Hicks, M., Doyle, M., Watson, J., Holwerda, N., Lynch, B., Wyatt, J., +Jones, H., & Hill, R. (2020). Measurement of Fluvial Suspended Sediment +Load and its Composition (No. 1.0.0; National Environmental Monitoring +Standards, p. 138). +\url{https://www.nems.org.nz/documents/suspended-sediment} +} +\seealso{ +Other numeric metrics: +\code{\link{kge}()}, +\code{\link{kge2012}()}, +\code{\link{mse}()}, +\code{\link{nse}()}, +\code{\link{pbias}()}, +\code{\link{press}()} + +Other accuracy metrics: +\code{\link{kge}()}, +\code{\link{kge2012}()}, +\code{\link{mse}()}, +\code{\link{nse}()}, +\code{\link{pbias}()}, +\code{\link{press}()} +} +\concept{accuracy metrics} +\concept{numeric metrics} diff --git a/man/tidyhydro-package.Rd b/man/tidyhydro-package.Rd index 4e9aba3..a44dc51 100644 --- a/man/tidyhydro-package.Rd +++ b/man/tidyhydro-package.Rd @@ -1,24 +1,24 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/tidyhydro-package.R -\docType{package} -\name{tidyhydro-package} -\alias{tidyhydro} -\alias{tidyhydro-package} -\title{tidyhydro: Tidy Metrics for Assessing Hydrological Models Performance} -\description{ -Provides tidy tools for comparing simulated and observed hydrological time series. Includes compatibility with the 'yardstick' package for model performance evaluation using commonly used metrics such as the Nash–Sutcliffe Efficiency (NSE), Kling–Gupta Efficiency (KGE), percent bias (pBIAS) and etc. -} -\seealso{ -Useful links: -\itemize{ - \item \url{https://github.com/atsyplenkov/tidyhydro} - \item \url{https://atsyplenkov.github.io/tidyhydro/} - \item Report bugs at \url{https://github.com/atsyplenkov/tidyhydro/issues} -} - -} -\author{ -\strong{Maintainer}: Anatoly Tsyplenkov \email{atsyplenkov@fastmail.com} (\href{https://orcid.org/0000-0003-4144-8402}{ORCID}) [copyright holder] - -} -\keyword{internal} +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/tidyhydro-package.R +\docType{package} +\name{tidyhydro-package} +\alias{tidyhydro} +\alias{tidyhydro-package} +\title{tidyhydro: Tidy Metrics for Assessing Hydrological Models Performance} +\description{ +Provides tidy tools for comparing simulated and observed hydrological time series. Includes compatibility with the 'yardstick' package for model performance evaluation using commonly used metrics such as the Nash–Sutcliffe Efficiency (NSE), Kling–Gupta Efficiency (KGE), percent bias (pBIAS) and etc. +} +\seealso{ +Useful links: +\itemize{ + \item \url{https://github.com/atsyplenkov/tidyhydro} + \item \url{https://atsyplenkov.github.io/tidyhydro/} + \item Report bugs at \url{https://github.com/atsyplenkov/tidyhydro/issues} +} + +} +\author{ +\strong{Maintainer}: Anatoly Tsyplenkov \email{atsyplenkov@fastmail.com} (\href{https://orcid.org/0000-0003-4144-8402}{ORCID}) [copyright holder] + +} +\keyword{internal} diff --git a/src/RcppExports.o b/src/RcppExports.o deleted file mode 100644 index 7cb312a..0000000 Binary files a/src/RcppExports.o and /dev/null differ diff --git a/src/kge.cpp b/src/kge.cpp index f58d04e..b0557bd 100644 --- a/src/kge.cpp +++ b/src/kge.cpp @@ -1,88 +1,88 @@ -#include -#include -#ifdef _OPENMP -#include -#endif -using namespace Rcpp; - -// [[Rcpp::export]] -SEXP kge_cpp(NumericVector obs, NumericVector sim, bool na_rm = true, std::string version = "2012") { - if (obs.size() != sim.size()) { - stop("'obs' and 'sim' must have the same length"); - } - if (version != "2009" && version != "2012") { - stop("Only versions '2009' and '2012' are supported"); - } - - const int n = obs.size(); - double mean_obs = 0.0, mean_sim = 0.0; - double var_obs = 0.0, var_sim = 0.0; - double r_num = 0.0; - int count = 0; - - // First pass: compute means - if (na_rm) { - double sum_obs = 0.0, sum_sim = 0.0; - #pragma omp parallel for reduction(+:sum_obs, sum_sim, count) schedule(static) if(n > 1000) - for (int i = 0; i < n; i++) { - if (!ISNAN(obs[i]) && !ISNAN(sim[i])) { - sum_obs += obs[i]; - sum_sim += sim[i]; - count++; - } - } - if (count == 0) return wrap(NA_REAL); - mean_obs = sum_obs / count; - mean_sim = sum_sim / count; - } else { - for (int i = 0; i < n; i++) { - mean_obs += obs[i]; - mean_sim += sim[i]; - } - mean_obs /= n; - mean_sim /= n; - count = n; - } - - // Second pass: compute variances and correlation numerator - if (na_rm) { - #pragma omp parallel for reduction(+:var_obs, var_sim, r_num) schedule(static) if(n > 1000) - for (int i = 0; i < n; i++) { - if (!ISNAN(obs[i]) && !ISNAN(sim[i])) { - const double d_obs = obs[i] - mean_obs; - const double d_sim = sim[i] - mean_sim; - var_obs += d_obs * d_obs; - var_sim += d_sim * d_sim; - r_num += d_obs * d_sim; - } - } - } else { - for (int i = 0; i < n; i++) { - const double d_obs = obs[i] - mean_obs; - const double d_sim = sim[i] - mean_sim; - var_obs += d_obs * d_obs; - var_sim += d_sim * d_sim; - r_num += d_obs * d_sim; - } - } - - if (var_obs == 0.0 || var_sim == 0.0) return wrap(NA_REAL); - - double r = r_num / std::sqrt(var_obs * var_sim); - double beta = mean_sim / mean_obs; - - double result; - if (version == "2009") { - double alpha = std::sqrt(var_sim / var_obs); - result = 1.0 - std::sqrt(std::pow(r - 1.0, 2.0) + - std::pow(alpha - 1.0, 2.0) + - std::pow(beta - 1.0, 2.0)); - } else { // version == "2012" - double gamma = (std::sqrt(var_sim)/mean_sim)/(std::sqrt(var_obs)/mean_obs); - result = 1.0 - std::sqrt(std::pow(r - 1.0, 2.0) + - std::pow(gamma - 1.0, 2.0) + - std::pow(beta - 1.0, 2.0)); - } - - return wrap(result); -} +#include +#include +#ifdef _OPENMP +#include +#endif +using namespace Rcpp; + +// [[Rcpp::export]] +SEXP kge_cpp(NumericVector obs, NumericVector sim, bool na_rm = true, std::string version = "2012") { + if (obs.size() != sim.size()) { + stop("'obs' and 'sim' must have the same length"); + } + if (version != "2009" && version != "2012") { + stop("Only versions '2009' and '2012' are supported"); + } + + const int n = obs.size(); + double mean_obs = 0.0, mean_sim = 0.0; + double var_obs = 0.0, var_sim = 0.0; + double r_num = 0.0; + int count = 0; + + // First pass: compute means + if (na_rm) { + double sum_obs = 0.0, sum_sim = 0.0; + #pragma omp parallel for reduction(+:sum_obs, sum_sim, count) schedule(static) if(n > 1000) + for (int i = 0; i < n; i++) { + if (!ISNAN(obs[i]) && !ISNAN(sim[i])) { + sum_obs += obs[i]; + sum_sim += sim[i]; + count++; + } + } + if (count == 0) return wrap(NA_REAL); + mean_obs = sum_obs / count; + mean_sim = sum_sim / count; + } else { + for (int i = 0; i < n; i++) { + mean_obs += obs[i]; + mean_sim += sim[i]; + } + mean_obs /= n; + mean_sim /= n; + count = n; + } + + // Second pass: compute variances and correlation numerator + if (na_rm) { + #pragma omp parallel for reduction(+:var_obs, var_sim, r_num) schedule(static) if(n > 1000) + for (int i = 0; i < n; i++) { + if (!ISNAN(obs[i]) && !ISNAN(sim[i])) { + const double d_obs = obs[i] - mean_obs; + const double d_sim = sim[i] - mean_sim; + var_obs += d_obs * d_obs; + var_sim += d_sim * d_sim; + r_num += d_obs * d_sim; + } + } + } else { + for (int i = 0; i < n; i++) { + const double d_obs = obs[i] - mean_obs; + const double d_sim = sim[i] - mean_sim; + var_obs += d_obs * d_obs; + var_sim += d_sim * d_sim; + r_num += d_obs * d_sim; + } + } + + if (var_obs == 0.0 || var_sim == 0.0) return wrap(NA_REAL); + + double r = r_num / std::sqrt(var_obs * var_sim); + double beta = mean_sim / mean_obs; + + double result; + if (version == "2009") { + double alpha = std::sqrt(var_sim / var_obs); + result = 1.0 - std::sqrt(std::pow(r - 1.0, 2.0) + + std::pow(alpha - 1.0, 2.0) + + std::pow(beta - 1.0, 2.0)); + } else { // version == "2012" + double gamma = (std::sqrt(var_sim)/mean_sim)/(std::sqrt(var_obs)/mean_obs); + result = 1.0 - std::sqrt(std::pow(r - 1.0, 2.0) + + std::pow(gamma - 1.0, 2.0) + + std::pow(beta - 1.0, 2.0)); + } + + return wrap(result); +} diff --git a/src/kge.o b/src/kge.o deleted file mode 100644 index 46b698c..0000000 Binary files a/src/kge.o and /dev/null differ diff --git a/src/mse.cpp b/src/mse.cpp index c913d0b..fa2eef2 100644 --- a/src/mse.cpp +++ b/src/mse.cpp @@ -1,42 +1,42 @@ -#include -// [[Rcpp::plugins(openmp)]] -#ifdef _OPENMP -#include -#endif -using namespace Rcpp; - -// [[Rcpp::export]] -SEXP mse_cpp(NumericVector truth, NumericVector estimate, bool na_rm = true) { - if (truth.size() != estimate.size()) { - stop("'truth' and 'estimate' must have the same length"); - } - - const int n = truth.length(); - const double* t = REAL(truth); - const double* e = REAL(estimate); - double num = 0.0; // numerator - double den = 0.0; // denominator - - // Second pass: calculate numerator and denominator - if (na_rm) { - #pragma omp parallel for reduction(+:num,den) schedule(static) if(n > 1000) - for (int i = 0; i < n; i++) { - if (!ISNAN(t[i]) && !ISNAN(e[i])) { - const double diff1 = t[i] - e[i]; - num += diff1 * diff1; - den += 1.0; - } - } - } else { - #pragma omp parallel for simd reduction(+:num,den) schedule(static) if(n > 1000) - for (int i = 0; i < n; i++) { - const double diff1 = t[i] - e[i]; - num += diff1 * diff1; - den += 1.0; - } - } - - double metric = num / den; - - return wrap(metric); -} +#include +// [[Rcpp::plugins(openmp)]] +#ifdef _OPENMP +#include +#endif +using namespace Rcpp; + +// [[Rcpp::export]] +SEXP mse_cpp(NumericVector truth, NumericVector estimate, bool na_rm = true) { + if (truth.size() != estimate.size()) { + stop("'truth' and 'estimate' must have the same length"); + } + + const int n = truth.length(); + const double* t = REAL(truth); + const double* e = REAL(estimate); + double num = 0.0; // numerator + double den = 0.0; // denominator + + // Second pass: calculate numerator and denominator + if (na_rm) { + #pragma omp parallel for reduction(+:num,den) schedule(static) if(n > 1000) + for (int i = 0; i < n; i++) { + if (!ISNAN(t[i]) && !ISNAN(e[i])) { + const double diff1 = t[i] - e[i]; + num += diff1 * diff1; + den += 1.0; + } + } + } else { + #pragma omp parallel for simd reduction(+:num,den) schedule(static) if(n > 1000) + for (int i = 0; i < n; i++) { + const double diff1 = t[i] - e[i]; + num += diff1 * diff1; + den += 1.0; + } + } + + double metric = num / den; + + return wrap(metric); +} diff --git a/src/mse.o b/src/mse.o deleted file mode 100644 index 524b736..0000000 Binary files a/src/mse.o and /dev/null differ diff --git a/src/nse.cpp b/src/nse.cpp index b523a57..cf90028 100644 --- a/src/nse.cpp +++ b/src/nse.cpp @@ -1,84 +1,84 @@ -#include -// [[Rcpp::plugins(openmp)]] -#ifdef _OPENMP -#include -#endif -using namespace Rcpp; - -// [[Rcpp::export]] -SEXP nse_cpp(NumericVector truth, NumericVector estimate, bool performance = false, bool na_rm = true) { - if (truth.size() != estimate.size()) { - stop("'truth' and 'estimate' must have the same length"); - } - - const int n = truth.length(); - const double* t = REAL(truth); - const double* e = REAL(estimate); - double num = 0.0; // numerator - double den = 0.0; // denominator - double t_mean = 0.0; // mean of truth - - // First pass: calculate mean and handle NAs - if (na_rm) { - double sum = 0.0; - int count = 0; - - #pragma omp parallel for reduction(+:sum,count) schedule(static) if(n > 1000) - for (int i = 0; i < n; i++) { - if (!ISNAN(t[i]) && !ISNAN(e[i])) { - sum += t[i]; - count++; - } - } - - t_mean = sum / count; - } else { - #pragma omp parallel for reduction(+:t_mean) schedule(static) if(n > 1000) - for (int i = 0; i < n; i++) { - t_mean += t[i]; - } - t_mean /= n; - } - - // Second pass: calculate numerator and denominator - if (na_rm) { - #pragma omp parallel for reduction(+:num,den) schedule(static) if(n > 1000) - for (int i = 0; i < n; i++) { - if (!ISNAN(t[i]) && !ISNAN(e[i])) { - const double diff1 = t[i] - e[i]; - const double diff2 = t[i] - t_mean; - num += diff1 * diff1; - den += diff2 * diff2; - } - } - } else { - #pragma omp parallel for simd reduction(+:num,den) schedule(static) if(n > 1000) - for (int i = 0; i < n; i++) { - const double diff1 = t[i] - e[i]; - const double diff2 = t[i] - t_mean; - num += diff1 * diff1; - den += diff2 * diff2; - } - } - - double metric = 1.0 - (num / den); - - if (!performance) { - return wrap(metric); - } else { - CharacterVector metric_values = CharacterVector::create("Poor", "Satisfactory", "Good", "Excellent"); - CharacterVector result(1); - - if (metric <= 0.5) { - result[0] = metric_values[0]; - } else if (metric > 0.5 && metric < 0.6) { - result[0] = metric_values[1]; - } else if (metric >= 0.6 && metric <= 0.8) { - result[0] = metric_values[2]; - } else { - result[0] = metric_values[3]; - } - - return result; - } -} +#include +// [[Rcpp::plugins(openmp)]] +#ifdef _OPENMP +#include +#endif +using namespace Rcpp; + +// [[Rcpp::export]] +SEXP nse_cpp(NumericVector truth, NumericVector estimate, bool performance = false, bool na_rm = true) { + if (truth.size() != estimate.size()) { + stop("'truth' and 'estimate' must have the same length"); + } + + const int n = truth.length(); + const double* t = REAL(truth); + const double* e = REAL(estimate); + double num = 0.0; // numerator + double den = 0.0; // denominator + double t_mean = 0.0; // mean of truth + + // First pass: calculate mean and handle NAs + if (na_rm) { + double sum = 0.0; + int count = 0; + + #pragma omp parallel for reduction(+:sum,count) schedule(static) if(n > 1000) + for (int i = 0; i < n; i++) { + if (!ISNAN(t[i]) && !ISNAN(e[i])) { + sum += t[i]; + count++; + } + } + + t_mean = sum / count; + } else { + #pragma omp parallel for reduction(+:t_mean) schedule(static) if(n > 1000) + for (int i = 0; i < n; i++) { + t_mean += t[i]; + } + t_mean /= n; + } + + // Second pass: calculate numerator and denominator + if (na_rm) { + #pragma omp parallel for reduction(+:num,den) schedule(static) if(n > 1000) + for (int i = 0; i < n; i++) { + if (!ISNAN(t[i]) && !ISNAN(e[i])) { + const double diff1 = t[i] - e[i]; + const double diff2 = t[i] - t_mean; + num += diff1 * diff1; + den += diff2 * diff2; + } + } + } else { + #pragma omp parallel for simd reduction(+:num,den) schedule(static) if(n > 1000) + for (int i = 0; i < n; i++) { + const double diff1 = t[i] - e[i]; + const double diff2 = t[i] - t_mean; + num += diff1 * diff1; + den += diff2 * diff2; + } + } + + double metric = 1.0 - (num / den); + + if (!performance) { + return wrap(metric); + } else { + CharacterVector metric_values = CharacterVector::create("Poor", "Satisfactory", "Good", "Excellent"); + CharacterVector result(1); + + if (metric <= 0.5) { + result[0] = metric_values[0]; + } else if (metric > 0.5 && metric < 0.6) { + result[0] = metric_values[1]; + } else if (metric >= 0.6 && metric <= 0.8) { + result[0] = metric_values[2]; + } else { + result[0] = metric_values[3]; + } + + return result; + } +} diff --git a/src/nse.o b/src/nse.o deleted file mode 100644 index ebf7334..0000000 Binary files a/src/nse.o and /dev/null differ diff --git a/src/pbias.cpp b/src/pbias.cpp index 8e56bea..4f2b4b2 100644 --- a/src/pbias.cpp +++ b/src/pbias.cpp @@ -1,59 +1,59 @@ -#include -// [[Rcpp::plugins(openmp)]] -#ifdef _OPENMP -#include -#endif -using namespace Rcpp; - -// [[Rcpp::export]] -SEXP pbias_cpp(NumericVector truth, NumericVector estimate, bool performance = false, bool na_rm = true) -{ - if (truth.size() != estimate.size()) { - stop("'truth' and 'estimate' must have the same length"); - } - - const int n = truth.length(); - const double* t = REAL(truth); - const double* e = REAL(estimate); - double num = 0.0; // sum(estimate - truth) - double den = 0.0; // sum(truth) - - if (na_rm) { - #pragma omp parallel for reduction(+:num,den) schedule(static) if(n > 1000) - for (int i = 0; i < n; i++) { - if (!ISNAN(t[i]) && !ISNAN(e[i])) { - num += e[i] - t[i]; - den += t[i]; - } - } - } else { - #pragma omp parallel for simd reduction(+:num,den) schedule(static) if(n > 1000) - for (int i = 0; i < n; i++) { - num += e[i] - t[i]; - den += t[i]; - } - } - - double metric = 100.0 * (num / den); - - if (!performance) { - return wrap(metric); - } else { - CharacterVector metric_values = CharacterVector::create("Poor", "Satisfactory", "Good", "Excellent"); - CharacterVector result(1); - - const double abs_metric = std::abs(metric); - - if (abs_metric >= 15.0) { - result[0] = metric_values[0]; - } else if (abs_metric >= 10.0) { - result[0] = metric_values[1]; - } else if (abs_metric >= 5.0) { - result[0] = metric_values[2]; - } else { - result[0] = metric_values[3]; - } - - return result; - } -} +#include +// [[Rcpp::plugins(openmp)]] +#ifdef _OPENMP +#include +#endif +using namespace Rcpp; + +// [[Rcpp::export]] +SEXP pbias_cpp(NumericVector truth, NumericVector estimate, bool performance = false, bool na_rm = true) +{ + if (truth.size() != estimate.size()) { + stop("'truth' and 'estimate' must have the same length"); + } + + const int n = truth.length(); + const double* t = REAL(truth); + const double* e = REAL(estimate); + double num = 0.0; // sum(estimate - truth) + double den = 0.0; // sum(truth) + + if (na_rm) { + #pragma omp parallel for reduction(+:num,den) schedule(static) if(n > 1000) + for (int i = 0; i < n; i++) { + if (!ISNAN(t[i]) && !ISNAN(e[i])) { + num += e[i] - t[i]; + den += t[i]; + } + } + } else { + #pragma omp parallel for simd reduction(+:num,den) schedule(static) if(n > 1000) + for (int i = 0; i < n; i++) { + num += e[i] - t[i]; + den += t[i]; + } + } + + double metric = 100.0 * (num / den); + + if (!performance) { + return wrap(metric); + } else { + CharacterVector metric_values = CharacterVector::create("Poor", "Satisfactory", "Good", "Excellent"); + CharacterVector result(1); + + const double abs_metric = std::abs(metric); + + if (abs_metric >= 15.0) { + result[0] = metric_values[0]; + } else if (abs_metric >= 10.0) { + result[0] = metric_values[1]; + } else if (abs_metric >= 5.0) { + result[0] = metric_values[2]; + } else { + result[0] = metric_values[3]; + } + + return result; + } +} diff --git a/src/pbias.o b/src/pbias.o deleted file mode 100644 index 569f35b..0000000 Binary files a/src/pbias.o and /dev/null differ diff --git a/src/press.o b/src/press.o deleted file mode 100644 index eccb3a0..0000000 Binary files a/src/press.o and /dev/null differ diff --git a/src/sfe.o b/src/sfe.o deleted file mode 100644 index 35f731d..0000000 Binary files a/src/sfe.o and /dev/null differ diff --git a/src/tidyhydro.dll b/src/tidyhydro.dll deleted file mode 100644 index c1991d5..0000000 Binary files a/src/tidyhydro.dll and /dev/null differ diff --git a/tests/testthat/test-hydrogof.R b/tests/testthat/test-hydrogof.R index b9e8666..ef1872e 100644 --- a/tests/testthat/test-hydrogof.R +++ b/tests/testthat/test-hydrogof.R @@ -1,266 +1,266 @@ -# Property-based testing -# https://www.etiennebacher.com/posts/2024-10-01-using-property-testing-in-r - -options( - quickcheck.tests = 20L, - quickcheck.shrinks = 10L, - quickcheck.discards = 10L -) - -test_that("nse", { - skip_if_not_installed("quickcheck") - skip_if_not_installed("hydroGOF") - - # With NA - # !NB: two tests to ensure that the C++ functions return the - # same results as hydroGOF with both NA values present and without - quickcheck::for_all( - obs = quickcheck::double_bounded( - left = -1000, - right = 1000, - len = 50, - any_na = TRUE - ), - sim = quickcheck::double_bounded( - left = -1000, - right = 1000, - len = 50, - any_na = TRUE - ), - property = function(obs, sim) { - new <- nse_vec(truth = obs, estimate = sim, na_rm = TRUE) - old <- hydroGOF::NSE(sim = sim, obs = obs, na.rm = TRUE) - - expect_equal(new, old) - } - ) - - # Without NA - quickcheck::for_all( - obs = quickcheck::double_bounded( - left = -1000, - right = 1000, - len = 50, - any_na = FALSE - ), - sim = quickcheck::double_bounded( - left = -1000, - right = 1000, - len = 50, - any_na = FALSE - ), - property = function(obs, sim) { - new <- nse_vec(truth = obs, estimate = sim, na_rm = TRUE) - old <- hydroGOF::NSE(sim = sim, obs = obs, na.rm = TRUE) - - expect_equal(new, old) - } - ) -}) - -test_that("kge", { - skip_if_not_installed("quickcheck") - skip_if_not_installed("hydroGOF") - - # With NA - quickcheck::for_all( - obs = quickcheck::double_bounded( - left = -1000, - right = 1000, - len = 50, - any_na = TRUE - ), - sim = quickcheck::double_bounded( - left = -1000, - right = 1000, - len = 50, - any_na = TRUE - ), - property = function(obs, sim) { - new <- kge_vec(truth = obs, estimate = sim, na_rm = TRUE) - old <- hydroGOF::KGE(sim = sim, obs = obs, na.rm = TRUE) - - expect_equal(new, old) - } - ) - - # Without NA - quickcheck::for_all( - obs = quickcheck::double_bounded( - left = -1000, - right = 1000, - len = 50, - any_na = FALSE - ), - sim = quickcheck::double_bounded( - left = -1000, - right = 1000, - len = 50, - any_na = FALSE - ), - property = function(obs, sim) { - new <- kge_vec(truth = obs, estimate = sim, na_rm = TRUE) - old <- hydroGOF::KGE(sim = sim, obs = obs, na.rm = TRUE) - - expect_equal(new, old) - } - ) -}) - - -test_that("kge2012", { - skip_if_not_installed("quickcheck") - skip_if_not_installed("hydroGOF") - - # With NA - quickcheck::for_all( - obs = quickcheck::double_bounded( - left = -1000, - right = 1000, - len = 50, - any_na = TRUE - ), - sim = quickcheck::double_bounded( - left = -1000, - right = 1000, - len = 50, - any_na = TRUE - ), - property = function(obs, sim) { - new <- kge2012_vec(truth = obs, estimate = sim, na_rm = TRUE) - old <- hydroGOF::KGE( - sim = sim, - obs = obs, - na.rm = TRUE, - method = "2012" - ) - - expect_equal(new, old) - } - ) - - # Without NA - quickcheck::for_all( - obs = quickcheck::double_bounded( - left = -1000, - right = 1000, - len = 50, - any_na = FALSE - ), - sim = quickcheck::double_bounded( - left = -1000, - right = 1000, - len = 50, - any_na = FALSE - ), - property = function(obs, sim) { - new <- kge2012_vec(truth = obs, estimate = sim, na_rm = TRUE) - old <- hydroGOF::KGE( - sim = sim, - obs = obs, - na.rm = TRUE, - method = "2012" - ) - - expect_equal(new, old) - } - ) -}) - -test_that("pbias", { - skip_if_not_installed("quickcheck") - skip_if_not_installed("hydroGOF") - - # With NA - quickcheck::for_all( - obs = quickcheck::double_bounded( - left = -1000, - right = 1000, - len = 50, - any_na = TRUE - ), - sim = quickcheck::double_bounded( - left = -1000, - right = 1000, - len = 50, - any_na = TRUE - ), - property = function(obs, sim) { - new <- pbias_vec(truth = obs, estimate = sim, na_rm = TRUE) - old <- hydroGOF::pbias(sim = sim, obs = obs, na.rm = TRUE, dec = 9) - - expect_equal(new, old) - } - ) - - # Without NA - quickcheck::for_all( - obs = quickcheck::double_bounded( - left = -1000, - right = 1000, - len = 50, - any_na = FALSE - ), - sim = quickcheck::double_bounded( - left = -1000, - right = 1000, - len = 50, - any_na = FALSE - ), - property = function(obs, sim) { - new <- pbias_vec(truth = obs, estimate = sim, na_rm = TRUE) - old <- hydroGOF::pbias(sim = sim, obs = obs, na.rm = TRUE, dec = 9) - - expect_equal(new, old) - } - ) -}) - -test_that("mse", { - skip_if_not_installed("quickcheck") - skip_if_not_installed("hydroGOF") - - # With NA - quickcheck::for_all( - obs = quickcheck::double_bounded( - left = -1000, - right = 1000, - len = 50, - any_na = TRUE - ), - sim = quickcheck::double_bounded( - left = -1000, - right = 1000, - len = 50, - any_na = TRUE - ), - property = function(obs, sim) { - new <- mse_vec(truth = obs, estimate = sim, na_rm = TRUE) - old <- hydroGOF::mse(sim = sim, obs = obs, na.rm = TRUE) - - expect_equal(new, old) - } - ) - - # Without NA - quickcheck::for_all( - obs = quickcheck::double_bounded( - left = -1000, - right = 1000, - len = 50, - any_na = FALSE - ), - sim = quickcheck::double_bounded( - left = -1000, - right = 1000, - len = 50, - any_na = FALSE - ), - property = function(obs, sim) { - new <- mse_vec(truth = obs, estimate = sim, na_rm = TRUE) - old <- hydroGOF::mse(sim = sim, obs = obs, na.rm = TRUE) - - expect_equal(new, old) - } - ) -}) +# Property-based testing +# https://www.etiennebacher.com/posts/2024-10-01-using-property-testing-in-r + +options( + quickcheck.tests = 20L, + quickcheck.shrinks = 10L, + quickcheck.discards = 10L +) + +test_that("nse", { + skip_if_not_installed("quickcheck") + skip_if_not_installed("hydroGOF") + + # With NA + # !NB: two tests to ensure that the C++ functions return the + # same results as hydroGOF with both NA values present and without + quickcheck::for_all( + obs = quickcheck::double_bounded( + left = -1000, + right = 1000, + len = 50, + any_na = TRUE + ), + sim = quickcheck::double_bounded( + left = -1000, + right = 1000, + len = 50, + any_na = TRUE + ), + property = function(obs, sim) { + new <- nse_vec(truth = obs, estimate = sim, na_rm = TRUE) + old <- hydroGOF::NSE(sim = sim, obs = obs, na.rm = TRUE) + + expect_equal(new, old) + } + ) + + # Without NA + quickcheck::for_all( + obs = quickcheck::double_bounded( + left = -1000, + right = 1000, + len = 50, + any_na = FALSE + ), + sim = quickcheck::double_bounded( + left = -1000, + right = 1000, + len = 50, + any_na = FALSE + ), + property = function(obs, sim) { + new <- nse_vec(truth = obs, estimate = sim, na_rm = TRUE) + old <- hydroGOF::NSE(sim = sim, obs = obs, na.rm = TRUE) + + expect_equal(new, old) + } + ) +}) + +test_that("kge", { + skip_if_not_installed("quickcheck") + skip_if_not_installed("hydroGOF") + + # With NA + quickcheck::for_all( + obs = quickcheck::double_bounded( + left = -1000, + right = 1000, + len = 50, + any_na = TRUE + ), + sim = quickcheck::double_bounded( + left = -1000, + right = 1000, + len = 50, + any_na = TRUE + ), + property = function(obs, sim) { + new <- kge_vec(truth = obs, estimate = sim, na_rm = TRUE) + old <- hydroGOF::KGE(sim = sim, obs = obs, na.rm = TRUE) + + expect_equal(new, old) + } + ) + + # Without NA + quickcheck::for_all( + obs = quickcheck::double_bounded( + left = -1000, + right = 1000, + len = 50, + any_na = FALSE + ), + sim = quickcheck::double_bounded( + left = -1000, + right = 1000, + len = 50, + any_na = FALSE + ), + property = function(obs, sim) { + new <- kge_vec(truth = obs, estimate = sim, na_rm = TRUE) + old <- hydroGOF::KGE(sim = sim, obs = obs, na.rm = TRUE) + + expect_equal(new, old) + } + ) +}) + + +test_that("kge2012", { + skip_if_not_installed("quickcheck") + skip_if_not_installed("hydroGOF") + + # With NA + quickcheck::for_all( + obs = quickcheck::double_bounded( + left = -1000, + right = 1000, + len = 50, + any_na = TRUE + ), + sim = quickcheck::double_bounded( + left = -1000, + right = 1000, + len = 50, + any_na = TRUE + ), + property = function(obs, sim) { + new <- kge2012_vec(truth = obs, estimate = sim, na_rm = TRUE) + old <- hydroGOF::KGE( + sim = sim, + obs = obs, + na.rm = TRUE, + method = "2012" + ) + + expect_equal(new, old) + } + ) + + # Without NA + quickcheck::for_all( + obs = quickcheck::double_bounded( + left = -1000, + right = 1000, + len = 50, + any_na = FALSE + ), + sim = quickcheck::double_bounded( + left = -1000, + right = 1000, + len = 50, + any_na = FALSE + ), + property = function(obs, sim) { + new <- kge2012_vec(truth = obs, estimate = sim, na_rm = TRUE) + old <- hydroGOF::KGE( + sim = sim, + obs = obs, + na.rm = TRUE, + method = "2012" + ) + + expect_equal(new, old) + } + ) +}) + +test_that("pbias", { + skip_if_not_installed("quickcheck") + skip_if_not_installed("hydroGOF") + + # With NA + quickcheck::for_all( + obs = quickcheck::double_bounded( + left = -1000, + right = 1000, + len = 50, + any_na = TRUE + ), + sim = quickcheck::double_bounded( + left = -1000, + right = 1000, + len = 50, + any_na = TRUE + ), + property = function(obs, sim) { + new <- pbias_vec(truth = obs, estimate = sim, na_rm = TRUE) + old <- hydroGOF::pbias(sim = sim, obs = obs, na.rm = TRUE, dec = 9) + + expect_equal(new, old) + } + ) + + # Without NA + quickcheck::for_all( + obs = quickcheck::double_bounded( + left = -1000, + right = 1000, + len = 50, + any_na = FALSE + ), + sim = quickcheck::double_bounded( + left = -1000, + right = 1000, + len = 50, + any_na = FALSE + ), + property = function(obs, sim) { + new <- pbias_vec(truth = obs, estimate = sim, na_rm = TRUE) + old <- hydroGOF::pbias(sim = sim, obs = obs, na.rm = TRUE, dec = 9) + + expect_equal(new, old) + } + ) +}) + +test_that("mse", { + skip_if_not_installed("quickcheck") + skip_if_not_installed("hydroGOF") + + # With NA + quickcheck::for_all( + obs = quickcheck::double_bounded( + left = -1000, + right = 1000, + len = 50, + any_na = TRUE + ), + sim = quickcheck::double_bounded( + left = -1000, + right = 1000, + len = 50, + any_na = TRUE + ), + property = function(obs, sim) { + new <- mse_vec(truth = obs, estimate = sim, na_rm = TRUE) + old <- hydroGOF::mse(sim = sim, obs = obs, na.rm = TRUE) + + expect_equal(new, old) + } + ) + + # Without NA + quickcheck::for_all( + obs = quickcheck::double_bounded( + left = -1000, + right = 1000, + len = 50, + any_na = FALSE + ), + sim = quickcheck::double_bounded( + left = -1000, + right = 1000, + len = 50, + any_na = FALSE + ), + property = function(obs, sim) { + new <- mse_vec(truth = obs, estimate = sim, na_rm = TRUE) + old <- hydroGOF::mse(sim = sim, obs = obs, na.rm = TRUE) + + expect_equal(new, old) + } + ) +}) diff --git a/tests/testthat/test-kge.R b/tests/testthat/test-kge.R index 4bdc553..a204896 100644 --- a/tests/testthat/test-kge.R +++ b/tests/testthat/test-kge.R @@ -1,68 +1,68 @@ -test_that("na_rm works as expected", { - ex_dat <- generate_numeric_test_data() - not_na <- !is.na(ex_dat$pred_na) - - # No missing data, na.rm = FALSE - expect_equal( - kge_vec(truth = ex_dat$obs, estimate = ex_dat$pred, na_rm = FALSE), - #fmt: skip - 1 - sqrt( - (cor(ex_dat$pred, ex_dat$obs) - 1)^2 + - (sd(ex_dat$pred) / sd(ex_dat$obs) - 1)^2 + - (mean(ex_dat$pred) / mean(ex_dat$obs) - 1)^2 - ) - ) - - # No missing data, na.rm = TRUE - expect_equal( - kge_vec(truth = ex_dat$obs, estimate = ex_dat$pred, na_rm = TRUE), - #fmt: skip - 1 - sqrt( - (cor(ex_dat$pred, ex_dat$obs) - 1)^2 + - (sd(ex_dat$pred) / sd(ex_dat$obs) - 1)^2 + - (mean(ex_dat$pred) / mean(ex_dat$obs) - 1)^2 - ) - ) - - # Missing data is present, na.rm = FALSE - expect_equal( - kge_vec(truth = ex_dat$obs, estimate = ex_dat$pred_na, na_rm = FALSE), - NA_real_ - ) - - # Missing data is present, na.rm = TRUE - expect_equal( - kge(ex_dat, truth = obs, estimate = pred_na, na_rm = TRUE)[[".estimate"]], - #fmt: skip - 1 - sqrt( - (cor(ex_dat$pred[not_na], ex_dat$obs[not_na]) - 1)^2 + - (sd(ex_dat$pred[not_na]) / sd(ex_dat$obs[not_na]) - 1)^2 + - (mean(ex_dat$pred[not_na]) / mean(ex_dat$obs[not_na]) - 1)^2 - ), - tolerance = 0.0001 - ) -}) - -test_that("Integer columns are allowed", { - ex_dat <- generate_numeric_test_data() - ex_dat$obs <- as.integer(ex_dat$obs) - - expect_equal( - kge(ex_dat, truth = "obs", estimate = "pred", na_rm = FALSE)[[".estimate"]], - #fmt: skip - 1 - sqrt( - (cor(ex_dat$pred, ex_dat$obs) - 1)^2 + - (sd(ex_dat$pred) / sd(ex_dat$obs) - 1)^2 + - (mean(ex_dat$pred) / mean(ex_dat$obs) - 1)^2 - ) - ) -}) - -test_that("Internal function works as expected", { - ex_dat <- generate_numeric_test_data() - - expect_true( - kge_cpp(ex_dat$obs, ex_dat$pred, na_rm = TRUE, version = "2009") != - kge_cpp(ex_dat$obs, ex_dat$pred, na_rm = TRUE, version = "2012") - ) -}) +test_that("na_rm works as expected", { + ex_dat <- generate_numeric_test_data() + not_na <- !is.na(ex_dat$pred_na) + + # No missing data, na.rm = FALSE + expect_equal( + kge_vec(truth = ex_dat$obs, estimate = ex_dat$pred, na_rm = FALSE), + #fmt: skip + 1 - sqrt( + (cor(ex_dat$pred, ex_dat$obs) - 1)^2 + + (sd(ex_dat$pred) / sd(ex_dat$obs) - 1)^2 + + (mean(ex_dat$pred) / mean(ex_dat$obs) - 1)^2 + ) + ) + + # No missing data, na.rm = TRUE + expect_equal( + kge_vec(truth = ex_dat$obs, estimate = ex_dat$pred, na_rm = TRUE), + #fmt: skip + 1 - sqrt( + (cor(ex_dat$pred, ex_dat$obs) - 1)^2 + + (sd(ex_dat$pred) / sd(ex_dat$obs) - 1)^2 + + (mean(ex_dat$pred) / mean(ex_dat$obs) - 1)^2 + ) + ) + + # Missing data is present, na.rm = FALSE + expect_equal( + kge_vec(truth = ex_dat$obs, estimate = ex_dat$pred_na, na_rm = FALSE), + NA_real_ + ) + + # Missing data is present, na.rm = TRUE + expect_equal( + kge(ex_dat, truth = obs, estimate = pred_na, na_rm = TRUE)[[".estimate"]], + #fmt: skip + 1 - sqrt( + (cor(ex_dat$pred[not_na], ex_dat$obs[not_na]) - 1)^2 + + (sd(ex_dat$pred[not_na]) / sd(ex_dat$obs[not_na]) - 1)^2 + + (mean(ex_dat$pred[not_na]) / mean(ex_dat$obs[not_na]) - 1)^2 + ), + tolerance = 0.0001 + ) +}) + +test_that("Integer columns are allowed", { + ex_dat <- generate_numeric_test_data() + ex_dat$obs <- as.integer(ex_dat$obs) + + expect_equal( + kge(ex_dat, truth = "obs", estimate = "pred", na_rm = FALSE)[[".estimate"]], + #fmt: skip + 1 - sqrt( + (cor(ex_dat$pred, ex_dat$obs) - 1)^2 + + (sd(ex_dat$pred) / sd(ex_dat$obs) - 1)^2 + + (mean(ex_dat$pred) / mean(ex_dat$obs) - 1)^2 + ) + ) +}) + +test_that("Internal function works as expected", { + ex_dat <- generate_numeric_test_data() + + expect_true( + kge_cpp(ex_dat$obs, ex_dat$pred, na_rm = TRUE, version = "2009") != + kge_cpp(ex_dat$obs, ex_dat$pred, na_rm = TRUE, version = "2012") + ) +}) diff --git a/tests/testthat/test-mse.R b/tests/testthat/test-mse.R index 938d7c8..3334913 100644 --- a/tests/testthat/test-mse.R +++ b/tests/testthat/test-mse.R @@ -1,37 +1,37 @@ -test_that("na_rm works as expected", { - ex_dat <- generate_numeric_test_data() - not_na <- !is.na(ex_dat$pred_na) - - # No missing data, na.rm = FALSE - expect_equal( - mse_vec(truth = ex_dat$obs, estimate = ex_dat$pred, na_rm = FALSE), - mean((ex_dat$pred - ex_dat$obs)^2) - ) - # No missing data, na.rm = TRUE - expect_equal( - mse_vec(truth = ex_dat$obs, estimate = ex_dat$pred, na_rm = TRUE), - mean((ex_dat$pred - ex_dat$obs)^2) - ) - - # Missing data is present, na.rm = FALSE - expect_equal( - mse_vec(truth = ex_dat$obs, estimate = ex_dat$pred_na, na_rm = FALSE), - NA_real_ - ) - - # Missing data is present, na.rm = TRUE - expect_equal( - mse(ex_dat, truth = obs, estimate = pred_na, na_rm = TRUE)[[".estimate"]], - mean((ex_dat$pred_na - ex_dat$obs)^2, na.rm = TRUE) - ) -}) - -test_that("Integer columns are allowed", { - ex_dat <- generate_numeric_test_data() - ex_dat$obs <- as.integer(ex_dat$obs) - - expect_equal( - mse(ex_dat, truth = "obs", estimate = "pred", na_rm = FALSE)[[".estimate"]], - mean((ex_dat$pred - ex_dat$obs)^2, na.rm = FALSE) - ) -}) +test_that("na_rm works as expected", { + ex_dat <- generate_numeric_test_data() + not_na <- !is.na(ex_dat$pred_na) + + # No missing data, na.rm = FALSE + expect_equal( + mse_vec(truth = ex_dat$obs, estimate = ex_dat$pred, na_rm = FALSE), + mean((ex_dat$pred - ex_dat$obs)^2) + ) + # No missing data, na.rm = TRUE + expect_equal( + mse_vec(truth = ex_dat$obs, estimate = ex_dat$pred, na_rm = TRUE), + mean((ex_dat$pred - ex_dat$obs)^2) + ) + + # Missing data is present, na.rm = FALSE + expect_equal( + mse_vec(truth = ex_dat$obs, estimate = ex_dat$pred_na, na_rm = FALSE), + NA_real_ + ) + + # Missing data is present, na.rm = TRUE + expect_equal( + mse(ex_dat, truth = obs, estimate = pred_na, na_rm = TRUE)[[".estimate"]], + mean((ex_dat$pred_na - ex_dat$obs)^2, na.rm = TRUE) + ) +}) + +test_that("Integer columns are allowed", { + ex_dat <- generate_numeric_test_data() + ex_dat$obs <- as.integer(ex_dat$obs) + + expect_equal( + mse(ex_dat, truth = "obs", estimate = "pred", na_rm = FALSE)[[".estimate"]], + mean((ex_dat$pred - ex_dat$obs)^2, na.rm = FALSE) + ) +}) diff --git a/tests/testthat/test-pbias.R b/tests/testthat/test-pbias.R index 340094c..40a02a5 100644 --- a/tests/testthat/test-pbias.R +++ b/tests/testthat/test-pbias.R @@ -1,73 +1,73 @@ -test_that("na_rm works as expected", { - ex_dat <- generate_numeric_test_data() - not_na <- !is.na(ex_dat$pred_na) - - # No missing data, na.rm = FALSE - expect_equal( - pbias_vec(truth = ex_dat$obs, estimate = ex_dat$pred, na_rm = FALSE), - #fmt:skip - 100 * (sum(ex_dat$pred - ex_dat$obs) / sum(ex_dat$obs)) - ) - # No missing data, na.rm = TRUE - expect_equal( - pbias_vec(truth = ex_dat$obs, estimate = ex_dat$pred, na_rm = TRUE), - #fmt:skip - 100 * (sum(ex_dat$pred - ex_dat$obs) / sum(ex_dat$obs)) - ) - - # Missing data is present, na.rm = FALSE - expect_equal( - pbias_vec(truth = ex_dat$obs, estimate = ex_dat$pred_na, na_rm = FALSE), - NA_real_ - ) - - # Missing data is present, na.rm = TRUE - expect_equal( - pbias(ex_dat, truth = obs, estimate = pred_na, na_rm = TRUE)[[".estimate"]], - #fmt:skip - 100 * - (sum(ex_dat$pred[not_na] - ex_dat$obs[not_na]) / sum(ex_dat$obs[not_na])), - tolerance = 0.0001 - ) -}) - -test_that("Integer columns are allowed", { - ex_dat <- generate_numeric_test_data() - ex_dat$obs <- as.integer(ex_dat$obs) - - expect_equal( - pbias_vec(truth = ex_dat$obs, estimate = ex_dat$pred, na_rm = FALSE), - #fmt:skip - 100 * (sum(ex_dat$pred - ex_dat$obs) / sum(ex_dat$obs)) - ) -}) - -test_that("Result similar to {hydroGOF} package", { - skip_if_not_installed("hydroGOF") - - ex_dat <- generate_numeric_test_data() - not_na <- !is.na(ex_dat$pred_na) - - # General case - expect_equal( - pbias_vec(truth = ex_dat$obs, estimate = ex_dat$pred, na_rm = FALSE), - hydroGOF::pbias(obs = ex_dat$obs, sim = ex_dat$pred), - tolerance = 0.1 - ) - - # With missing data - expect_equal( - pbias_vec(truth = ex_dat$obs, estimate = ex_dat$pred_na, na_rm = TRUE), - hydroGOF::pbias(obs = ex_dat$obs, sim = ex_dat$pred_na, na.rm = TRUE), - tolerance = 0.0001 - ) -}) - -test_that("Result interpretation is returned", { - ex_dat <- generate_numeric_test_data() - - expect_equal( - pbias_vec(truth = ex_dat$obs, estimate = ex_dat$pred, performance = TRUE), - "Poor" - ) -}) +test_that("na_rm works as expected", { + ex_dat <- generate_numeric_test_data() + not_na <- !is.na(ex_dat$pred_na) + + # No missing data, na.rm = FALSE + expect_equal( + pbias_vec(truth = ex_dat$obs, estimate = ex_dat$pred, na_rm = FALSE), + #fmt:skip + 100 * (sum(ex_dat$pred - ex_dat$obs) / sum(ex_dat$obs)) + ) + # No missing data, na.rm = TRUE + expect_equal( + pbias_vec(truth = ex_dat$obs, estimate = ex_dat$pred, na_rm = TRUE), + #fmt:skip + 100 * (sum(ex_dat$pred - ex_dat$obs) / sum(ex_dat$obs)) + ) + + # Missing data is present, na.rm = FALSE + expect_equal( + pbias_vec(truth = ex_dat$obs, estimate = ex_dat$pred_na, na_rm = FALSE), + NA_real_ + ) + + # Missing data is present, na.rm = TRUE + expect_equal( + pbias(ex_dat, truth = obs, estimate = pred_na, na_rm = TRUE)[[".estimate"]], + #fmt:skip + 100 * + (sum(ex_dat$pred[not_na] - ex_dat$obs[not_na]) / sum(ex_dat$obs[not_na])), + tolerance = 0.0001 + ) +}) + +test_that("Integer columns are allowed", { + ex_dat <- generate_numeric_test_data() + ex_dat$obs <- as.integer(ex_dat$obs) + + expect_equal( + pbias_vec(truth = ex_dat$obs, estimate = ex_dat$pred, na_rm = FALSE), + #fmt:skip + 100 * (sum(ex_dat$pred - ex_dat$obs) / sum(ex_dat$obs)) + ) +}) + +test_that("Result similar to {hydroGOF} package", { + skip_if_not_installed("hydroGOF") + + ex_dat <- generate_numeric_test_data() + not_na <- !is.na(ex_dat$pred_na) + + # General case + expect_equal( + pbias_vec(truth = ex_dat$obs, estimate = ex_dat$pred, na_rm = FALSE), + hydroGOF::pbias(obs = ex_dat$obs, sim = ex_dat$pred), + tolerance = 0.1 + ) + + # With missing data + expect_equal( + pbias_vec(truth = ex_dat$obs, estimate = ex_dat$pred_na, na_rm = TRUE), + hydroGOF::pbias(obs = ex_dat$obs, sim = ex_dat$pred_na, na.rm = TRUE), + tolerance = 0.0001 + ) +}) + +test_that("Result interpretation is returned", { + ex_dat <- generate_numeric_test_data() + + expect_equal( + pbias_vec(truth = ex_dat$obs, estimate = ex_dat$pred, performance = TRUE), + "Poor" + ) +}) diff --git a/tests/testthat/test-system-crash.R b/tests/testthat/test-system-crash.R index 9408ee8..9312a85 100644 --- a/tests/testthat/test-system-crash.R +++ b/tests/testthat/test-system-crash.R @@ -1,141 +1,141 @@ -# Property-based testing -# https://www.etiennebacher.com/posts/2024-10-01-using-property-testing-in-r - -options( - quickcheck.tests = 20L, - quickcheck.shrinks = 10L, - quickcheck.discards = 10L -) - -test_that("nse", { - skip_if_not_installed("quickcheck") - - quickcheck::for_all( - obs = quickcheck::any_atomic(any_na = TRUE), - sim = quickcheck::any_atomic(any_na = TRUE), - na_flag = quickcheck::logical_(any_na = FALSE), - property = function(obs, sim, na_flag) { - suppressWarnings( - try( - nse_vec(truth = obs, estimate = sim, na_rm = na_flag), - silent = TRUE - ) - ) - expect_true(TRUE) - } - ) -}) - -test_that("mse", { - skip_if_not_installed("quickcheck") - - quickcheck::for_all( - obs = quickcheck::any_atomic(any_na = TRUE), - sim = quickcheck::any_atomic(any_na = TRUE), - na_flag = quickcheck::logical_(any_na = FALSE), - property = function(obs, sim, na_flag) { - suppressWarnings( - try( - mse_vec(truth = obs, estimate = sim, na_rm = na_flag), - silent = TRUE - ) - ) - expect_true(TRUE) - } - ) -}) - -test_that("kge", { - skip_if_not_installed("quickcheck") - - quickcheck::for_all( - obs = quickcheck::any_atomic(any_na = TRUE), - sim = quickcheck::any_atomic(any_na = TRUE), - na_flag = quickcheck::logical_(any_na = FALSE), - property = function(obs, sim, na_flag) { - suppressWarnings( - try( - kge_vec(truth = obs, estimate = sim, na_rm = na_flag), - silent = TRUE - ) - ) - expect_true(TRUE) - } - ) -}) - -test_that("kge2012", { - skip_if_not_installed("quickcheck") - - quickcheck::for_all( - obs = quickcheck::any_atomic(any_na = TRUE), - sim = quickcheck::any_atomic(any_na = TRUE), - na_flag = quickcheck::logical_(any_na = FALSE), - property = function(obs, sim, na_flag) { - suppressWarnings( - try( - kge2012_vec(truth = obs, estimate = sim, na_rm = na_flag), - silent = TRUE - ) - ) - expect_true(TRUE) - } - ) -}) - -test_that("pbias", { - skip_if_not_installed("quickcheck") - - quickcheck::for_all( - obs = quickcheck::any_atomic(any_na = TRUE), - sim = quickcheck::any_atomic(any_na = TRUE), - na_flag = quickcheck::logical_(any_na = FALSE), - property = function(obs, sim, na_flag) { - suppressWarnings( - try( - pbias_vec(truth = obs, estimate = sim, na_rm = na_flag), - silent = TRUE - ) - ) - expect_true(TRUE) - } - ) -}) - -test_that("sfe", { - skip_if_not_installed("quickcheck") - - quickcheck::for_all( - obs = quickcheck::any_atomic(any_na = TRUE), - sim = quickcheck::any_atomic(any_na = TRUE), - na_flag = quickcheck::logical_(any_na = FALSE), - property = function(obs, sim, na_flag) { - suppressWarnings( - try( - sfe_vec(truth = obs, estimate = sim, na_rm = na_flag), - silent = TRUE - ) - ) - expect_true(TRUE) - } - ) -}) - -test_that("press", { - skip_if_not_installed("quickcheck") - - quickcheck::for_all( - obs = quickcheck::any_atomic(any_na = TRUE), - sim = quickcheck::any_atomic(any_na = TRUE), - na_flag = quickcheck::logical_(any_na = FALSE), - property = function(obs, sim, na_flag) { - suppressWarnings( - try( - press_vec(truth = obs, estimate = sim, na_rm = na_flag), - silent = TRUE - ) - ) - expect_true(TRUE) - } - ) -}) +# Property-based testing +# https://www.etiennebacher.com/posts/2024-10-01-using-property-testing-in-r + +options( + quickcheck.tests = 20L, + quickcheck.shrinks = 10L, + quickcheck.discards = 10L +) + +test_that("nse", { + skip_if_not_installed("quickcheck") + + quickcheck::for_all( + obs = quickcheck::any_atomic(any_na = TRUE), + sim = quickcheck::any_atomic(any_na = TRUE), + na_flag = quickcheck::logical_(any_na = FALSE), + property = function(obs, sim, na_flag) { + suppressWarnings( + try( + nse_vec(truth = obs, estimate = sim, na_rm = na_flag), + silent = TRUE + ) + ) + expect_true(TRUE) + } + ) +}) + +test_that("mse", { + skip_if_not_installed("quickcheck") + + quickcheck::for_all( + obs = quickcheck::any_atomic(any_na = TRUE), + sim = quickcheck::any_atomic(any_na = TRUE), + na_flag = quickcheck::logical_(any_na = FALSE), + property = function(obs, sim, na_flag) { + suppressWarnings( + try( + mse_vec(truth = obs, estimate = sim, na_rm = na_flag), + silent = TRUE + ) + ) + expect_true(TRUE) + } + ) +}) + +test_that("kge", { + skip_if_not_installed("quickcheck") + + quickcheck::for_all( + obs = quickcheck::any_atomic(any_na = TRUE), + sim = quickcheck::any_atomic(any_na = TRUE), + na_flag = quickcheck::logical_(any_na = FALSE), + property = function(obs, sim, na_flag) { + suppressWarnings( + try( + kge_vec(truth = obs, estimate = sim, na_rm = na_flag), + silent = TRUE + ) + ) + expect_true(TRUE) + } + ) +}) + +test_that("kge2012", { + skip_if_not_installed("quickcheck") + + quickcheck::for_all( + obs = quickcheck::any_atomic(any_na = TRUE), + sim = quickcheck::any_atomic(any_na = TRUE), + na_flag = quickcheck::logical_(any_na = FALSE), + property = function(obs, sim, na_flag) { + suppressWarnings( + try( + kge2012_vec(truth = obs, estimate = sim, na_rm = na_flag), + silent = TRUE + ) + ) + expect_true(TRUE) + } + ) +}) + +test_that("pbias", { + skip_if_not_installed("quickcheck") + + quickcheck::for_all( + obs = quickcheck::any_atomic(any_na = TRUE), + sim = quickcheck::any_atomic(any_na = TRUE), + na_flag = quickcheck::logical_(any_na = FALSE), + property = function(obs, sim, na_flag) { + suppressWarnings( + try( + pbias_vec(truth = obs, estimate = sim, na_rm = na_flag), + silent = TRUE + ) + ) + expect_true(TRUE) + } + ) +}) + +test_that("sfe", { + skip_if_not_installed("quickcheck") + + quickcheck::for_all( + obs = quickcheck::any_atomic(any_na = TRUE), + sim = quickcheck::any_atomic(any_na = TRUE), + na_flag = quickcheck::logical_(any_na = FALSE), + property = function(obs, sim, na_flag) { + suppressWarnings( + try( + sfe_vec(truth = obs, estimate = sim, na_rm = na_flag), + silent = TRUE + ) + ) + expect_true(TRUE) + } + ) +}) + +test_that("press", { + skip_if_not_installed("quickcheck") + + quickcheck::for_all( + obs = quickcheck::any_atomic(any_na = TRUE), + sim = quickcheck::any_atomic(any_na = TRUE), + na_flag = quickcheck::logical_(any_na = FALSE), + property = function(obs, sim, na_flag) { + suppressWarnings( + try( + press_vec(truth = obs, estimate = sim, na_rm = na_flag), + silent = TRUE + ) + ) + expect_true(TRUE) + } + ) +}) diff --git a/vignettes/.gitignore b/vignettes/.gitignore index 075b254..ebd7da3 100644 --- a/vignettes/.gitignore +++ b/vignettes/.gitignore @@ -1 +1 @@ -/.quarto/ +/.quarto/ diff --git a/vignettes/articles/.gitignore b/vignettes/articles/.gitignore index fbda3f7..ffdf081 100644 --- a/vignettes/articles/.gitignore +++ b/vignettes/articles/.gitignore @@ -1,5 +1,5 @@ -*.html -*.R -*_files - -/.quarto/ +*.html +*.R +*_files + +/.quarto/