Skip to content

Design Decisions

Karolis Koncevičius edited this page Apr 7, 2023 · 7 revisions

This page documents the design choices taken by the package. Any deviation from these rules should be fixed or documented as an exception case.

Function Names

Function names are composed of 3 elements separated by underscores where needed:

[row/col]_testname_variant

The variant part can be dropped when not applicable or when only a single variant for that test is implemented so far.

A few examples: row_oneway_equalvar, row_bartlett

In order to make the function names shorter the word test is not included.

Single Test Per Function

Functions should provide a single type of test.

This means that some of the tests that in base R are implemented under a single function will be split into different functions. For example in base R function t.test() has parameters that can specify the type of t.test to use: equal variance or Welch adjusted, paired or non paired.

In this package those types of choices are separated into separate functions for the following reasons:

  1. Output structure returned by a function is not dependant on the input values.
  2. User is made to choose the test explicitly with no hidden defaults.
  3. This convention makes it easier to add more test types later.

Input Values

The functions try to make sense of the provided inputs when possible. All the cases when the inputs are incorrectly specified should throw an error.

Edge cases should be handled gracefully. For example when input is a numeric matrix with 0 rows - the result is a 0 row data.frame.

Below is a short list of implemented input rules:

  1. Main parameters are numeric matrices.
  2. Vectors are transformed into a 1-row matrix.
  3. Data frames are automatically transformed into matrices if all of their columns are numeric.
  4. When two matrices are required - either number of their rows should match or the second matrix must have only single row/column. In which case the same row/column will be repeated for all values of x.
  5. Group specifications and additional parameters typically can have only one value that will be applied to all the rows.
  6. In some cases additional parameters can have a separate value for each row. Those cases are specified in the help documentation.

Outputs

Outputs are contained in a data.frame with each row providing the result of the test performed on the corresponding row of the input matrix.

Output categories

Columns hold the relevant results that can be divided into 3 main categories:

  1. Descriptive statistics related to the test. Typically ordered by increasing complexity. For example: 1) number of observations, 2) means, 3) variances.

  2. Outputs related to the test itself. Typically ordered by increasing complexity. For example: 1) degrees of freedom, 2) test statistic, 3) p-value, 4) confidence interval.

  3. Input parameters that were chosen for the row. Ordered by their appearance in the function call. For example: 1) alternative hypothesis type, 2) mean of null hypothesis, 3) confidence level.

In the output data.frame these categories are displayed in order: 1st descriptive statistics, 2nd test output, and 3rd input parameters.

Column names

Column names of the output are written in consistent fashion and typically have two parts: field and specification, separated by a dot.

All the fields are written as a single word and abbreviated if needed:

  • obs - number of observations
  • mean - estimated mean
  • var - estimated variance
  • df - degrees of freedom
  • statistic - test statistic
  • pvalue - p-value
  • stderr - standard error
  • cor - estimated correlation

Specifications are included only when necessary - when field is used more than once or when clarification is necessary.

  • obs.x - number of x observations
  • obs.tot - total number of observations
  • mean.x - mean of x
  • mean.diff - mean of x and y difference
  • conf.low - lower confidence interval
  • conf.high - higher confidence interval

Row names

Row names are transfered from the main input matrix. If the row names of the matrix were not unique - they are made unique using make.unique(). In case input matrix had no row names the numbers 1:nrow(x) are used.

Compatibility with R

Results of tests should be as compatible as possible with the ones implemented in base R. Allowed exceptions are cases where R's implementation is incorrect or limiting.

A good example is oneway.test() which works only if all groups have more than 2 observations even when var.equal is set to TRUE. The strict requirement for the test to run technically is for at least one group to have more than 1 observation. Therefore in such cases row_oneway_equalvar() works even if base R version throws an error.

For another such example consider bartlett.test(). This function works without any warnings when supplied with constant data and returns NA values:

bartlett.test(rep(1,4), c("a","a","b","b"))
        Bartlett test of homogeneity of variances

data:  rep(1, 4) and c("a", "a", "b", "b")
Bartlett's K-squared = NaN, df = 1, p-value = NA

The typical behaviour in such situations for base R tests is to throw an error:

t.test(c(1,1,1,1) ~ c("a","a","b","b"))
Error in t.test.default(x = c(1, 1), y = c(1, 1)) :
  data are essentially constant

Functions in this package try to be consistent with each other and be as informative as possible. Therefore in such cases row_bartlett() will throw a warning even if base R function does not.

row_bartlett(c(1,1,1,1), c("a","a","b","b"))
  obs.tot obs.groups var.pooled df statistic pvalue
1       4          2          0  1        NA     NA
Warning message:
row_bartlett: 1 of the rows had zero variance in all of the groups.
First occurrence at row 1

Warnings and Errors

Errors are produced only when the input parameters are not correctly specified.

Warnings are shown in situations when there was something wrong with doing a test itself given the specified input parameters (i.e. all the values were constant).

Such a decision for warnings was taken because users will typically perform multiple tests (one for each row). The function cannot fail when one or few of those tests cannot be completed. So even when R base tests throw an error the functions in this package will instead produce an informative warning for the row that failed and if needed will set all it's return values related to the test to NA so that the user will not be able to use them by mistake.

Note that in these cases only test-related values like test statistic, p-value and confidence interval are set to NA. Other returned values: number of observations, means, variances and similar will still be returned as usual.

As an example of such behaviour consider the case when base t-test with Welch correction fails because it has not enough observations:

t.test(c(1,2), 3)
Error in t.test.default(c(1, 2), 3) : not enough 'y' observations

Function in this package proceeds, but throws a warning and takes care to set the failed outputs to NA:

row_t_welch(c(1,2), 3)
  obs.x obs.y obs.tot mean.x mean.y mean.diff var.x var.y  stderr  df statistic pvalue conf.low conf.high alternative mean.null conf.level
1     2     1       3    1.5      3      -1.5   0.5   NaN     NaN NaN        NA     NA       NA        NA   two.sided         0       0.95
Warning message:
row_t_welch: 1 of the rows had less than 2 "y" observations.
First occurrence at row 1

This allows the function continue working in cases where typically we have enough observations per group but some rows might not have enough due to NA values.

mat1 <- rbind(c(1,2), c(3,NA))
mat2 <- rbind(c(2,3), c(0,4))
row_t_welch(mat1, mat2)
  obs.x obs.y obs.tot mean.x mean.y mean.diff var.x var.y stderr     df statistic    pvalue  conf.low conf.high alternative mean.null conf.level
1     2     2       4    1.5    2.5        -1   0.5   0.5 0.7071068   2 -1.414214 0.2928932 -4.042435  2.042435   two.sided         0       0.95
2     1     2       3    3.0    2.0         1   NaN   8.0       NaN NaN        NA        NA        NA        NA   two.sided         0       0.95
row_t_welch: 1 of the rows had less than 2 "x" observations.
First occurrence at row 2

NA and NaN values

NA and NaN values from the input matrices are silently removed and each row is treated like a vector that has no NA/NaN values.

When NA or NaN values are present in the parameter specifying the groups the corresponding values from the input matrices are dropped before doing the tests. For example if the specified group variable has a NA:

x <- rnorm(5)
g <- c(NA,"a", "a", "b", "b")
row_oneway_welch(x=x, g=g)
  obs.tot obs.groups df.between df.within  statistic    pvalue
1       4          2          1  1.440393 0.02349341 0.8968457

then the entire first column from the input matrix x corresponding to that group will be removed. And the result will be equivalent to:

row_oneway_welch(x=x[-1], g=g[-1])
  obs.tot obs.groups df.between df.within  statistic    pvalue
1       4          2          1  1.440393 0.02349341 0.8968457

Other parameters might allow or not allow NA values depending on context. For example you cannot specify NA as wanted null when doing a test because not knowing your null hypothesis makes little sense.

On the other hand specifying NA as a confidence level will suppress confidence intervals and increase computation speed.