stats <- function ( x = NULL ) #*****************************************************************************80 # ## stats() does stats. # # Discussion: # # This function computes statistical quantities for a sequence of values # X which are supplied one at a time, like a data stream. The statistical # quantities are updated every time a new value of X is supplied. # # Because we are dealing with a data stream, and not saving the previous # data values, it is not possible to compute the median and mode. # # Licensing: # # This code is distributed under the MIT license. # # Modified: # # 11 May 2021 # # Author: # # John Burkardt # # Input: # # real X, the next item in the sequence. # If X is set to Inf, then its value is ignored, and the current data # is returned. # If no argument is specified, then all internal data is reset to 0. # # Output: # # integer N: the number of items in the sequence. # # real X_SUM: the sum of the values. # # real X_MIN, X_MEAN, X_MAX: the minimum, mean, and maximum values. # # real X_VAR, X_STD: the variance and standard deviation. # { # # Persistent data is stored as attributes associated with the function. # n_internal <- attr ( stats, "n_internal" ) x_max_internal <- attr ( stats, "x_max_internal" ) x_mean_internal <- attr ( stats, "x_mean_internal" ) x_min_internal <- attr ( stats, "x_min_internal" ) x_std_internal <- attr ( stats, "x_std_internal" ) x_sum_internal <- attr ( stats, "x_sum_internal" ) x_var_internal <- attr ( stats, "x_var_internal" ) # # Initialize the persistent data on first call, and again if x not input. # Note that we need to use a DOUBLE ARROW assignment here! # This makes the assignment "globally". # if ( is.null ( n_internal ) ) { n_internal = 0 x_max_internal = -Inf x_mean_internal = 0.0 x_min_internal = Inf x_std_internal = 0.0 x_sum_internal = 0.0 x_var_internal = 0.0 attr ( stats, "n_internal" ) <<- n_internal attr ( stats, "x_max_internal" ) <<- x_max_internal attr ( stats, "x_mean_internal" ) <<- x_mean_internal attr ( stats, "x_min_internal" ) <<- x_min_internal attr ( stats, "x_std_internal" ) <<- x_std_internal attr ( stats, "x_sum_internal" ) <<- x_sum_internal attr ( stats, "x_var_internal" ) <<- x_var_internal } # # Action based on input value X: # if ( is.null ( x ) ) { n_internal = 0 x_max_internal = -Inf x_mean_internal = 0.0 x_min_internal = Inf x_std_internal = 0.0 x_sum_internal = 0.0 x_var_internal = 0.0 } # # X = Inf. Do nothing. # This allows user to read current memory. # else if ( x == Inf ) { } # # X supplied, and not Inf. # else { n_internal = n_internal + 1 x_max_internal = max ( x_max_internal, x ) x_min_internal = min ( x_min_internal, x ) x_sum_internal = x_sum_internal + x x_mean_old = x_mean_internal x_mean_internal = x_sum_internal / n_internal if ( n_internal == 1 ) { x_var_internal = 0.0 x_std_internal = 0.0 } else { x_var_internal = ( x_var_internal * ( n_internal - 2 ) + ( x - x_mean_old ) * ( x - x_mean_internal ) ) / ( n_internal - 1 ) x_std_internal = sqrt ( x_var_internal ) } } # # Save values. # attr ( stats, "n_internal" ) <<- n_internal attr ( stats, "x_max_internal" ) <<- x_max_internal attr ( stats, "x_mean_internal" ) <<- x_mean_internal attr ( stats, "x_min_internal" ) <<- x_min_internal attr ( stats, "x_std_internal" ) <<- x_std_internal attr ( stats, "x_sum_internal" ) <<- x_sum_internal attr ( stats, "x_var_internal" ) <<- x_var_internal # # Set output values. # n = n_internal x_max = x_max_internal x_min = x_min_internal x_sum = x_sum_internal x_mean = x_mean_internal x_var = x_var_internal x_std = x_std_internal output = c ( n, x_sum, x_min, x_mean, x_max, x_var, x_std ) return ( output ) }