assertive ex 2: the harmonic mean function

## assertive has some important changes.  Read ?changes for details.

Consider this function that calculates the harmonic mean, defined as the reciprocal of the arithmetic mean of the reciprocal of the data, for x > 0.

harmmean <- function(x, na.rm = FALSE)
{
  1 / mean(1 / x, na.rm = na.rm)
}

Update this function to include some checks on the function inputs. In particular, you should check that x is numeric and always positive, and that na.rm is a single logical value. (Whether you want to throw an error for bad input or try to correct the problem is up to your judgement.)

We can more or less copy and paste from the geomean example.

# usual setup
library(assertive)
library(knitr)
opts_chunk$set(error = TRUE)

# modify this function
harmmean2 <- function(x, na.rm = FALSE)
{
  assert_is_numeric(x)
  if(any(is_non_positive(x), na.rm = TRUE))
  {
    warning("The harmonic mean requires positive inputs.")
    return(NaN)
  }
  na.rm <- coerce_to(use_first(na.rm), "logical")
  1 / mean(1 / x, na.rm = na.rm)
}

Actually, the harmonic mean works for all non-zero x, so if you want to support negative values, you can do something like this.

# modify this function
harmmean3 <- function(x, na.rm = FALSE)
{
  assert_is_numeric(x)
  if(any(is_true(x == 0)))
  {
    warning("The harmonic mean requires non-zero inputs.")
    return(NaN)
  }
  na.rm <- coerce_to(use_first(na.rm), "logical")
  1 / mean(1 / x, na.rm = na.rm)
}

To make sure that your function works like you think it should, try running the following examples

# a numeric vector of positive numbers
x <- rlnorm(100)
harmmean2(x)
## [1] 0.8561971
# a numeric vector with negative numbers
x_neg <- -rlnorm(100)
harmmean2(x_neg)
## Warning in harmmean2(x_neg): The harmonic mean requires positive inputs.
## [1] NaN
# a numeric vector with zeroes
x_zero <- -1:1
harmmean2(x_zero)
## Warning in harmmean2(x_zero): The harmonic mean requires positive inputs.
## [1] NaN
# a character vector
x_char <- "1.234"
harmmean2(x_char)
## Error in harmmean2(x_char): x is not of type 'numeric'; it has class 'character'.
# a numeric vector with missing values, and na.rm = FALSE
x_na <- rlnorm(100)
x_na[sample(100, 20)] <- NA
harmmean2(x_na)
## [1] NA
# a numeric vector with missing values, and na.rm = TRUE
harmmean2(x_na, na.rm = TRUE)
## [1] 0.5841596
# a numeric vector, and na.rm has length more than one
harmmean2(x_na, na.rm = 1:10)
## Warning: Only the first value of 'na.rm' will be used.
## Warning: Coercing use_first(na.rm) to class 'logical'.
## [1] 0.5841596