0
$\begingroup$

Why is the Spearman or other type of correlation in R is unable to produce p values on only two data points?

I would like to do correlation with only two observations and produce p vlues of significance. However, in R, any type of correlation (pearson, spearman, kendall's tau), is unable to produce p values of just 2 observations.

There is a nice explanation why correlation of just 2 observations will result -1 or +1 but not why p values are unable to be calculated:Why is the Pearson correlation 1 when only two data values are available?

Example:

corr.test(c(1,2), c(3,4))$p

[1] NaN
Warning messages:
1: In corr.test(c(1, 2), c(3, 4)) :
  Number of subjects must be greater than 3 to find confidence intervals.
2: In sqrt(n - 3) : NaNs produced

is it because p-value is calculated using a t-distribution with n - 2 degrees of freedom ? The formula for the test statistic is t=rn−2√1−r2√ .

Then, what is an alternative to produce such significance? If I reduce n-2 to just "n-1"? What will be the negative side?

R formula of "corr.test"

t <- (r * sqrt(n - 2))/sqrt(1 - r^2)
    p <- -2 * expm1(pt(abs(t), (n - 2), log.p = TRUE))
    se <- sqrt((1 - r * r)/(n - 2))

If the only possible r correlation coefficient values between of just two observations are -1, 0, and 1, then the possible pvalues with (n-1 AND not n-2) is: --- Which produces division with zero error. Note: t.student distribution was used with df=1 to produce in librecalc pvalues. Libre Calc Calculations to produce pvalues on Example with just two observations

To counteract that, then we may adjust r correlation coefficient 1 to 0.99 and 1 to -.99. Then, pvalues on t-student distribution is produced with no div/0! error. Note: t.student distribution was used with df=1 to produce in librecalc pvalues.

Libre Calc Calculations to produce pvalues on Example with just two observations

*Edit Note, in the images, the whole calculation inside "sqrt" at numerator, is "1 * SQRT(2-1) = 1 * SQRT(1)= 1".

$\endgroup$
6
  • 2
    $\begingroup$ Re: "I would like to do correlation with only two observations and produce p values of significance:" That's possible only if you are performing one-sided tests with a threshold $\alpha$ of 50% or greater. $\endgroup$
    – whuber
    Aug 10, 2020 at 16:53
  • $\begingroup$ Can you elaborate on that and how I can run it on R? $\endgroup$ Aug 10, 2020 at 16:54
  • 3
    $\begingroup$ Sure: if your null hypothesis is zero correlation and the alternative is (for example) that the correlation is positive, then observing a negative slope is a tiny bit of evidence against the alternative. Because the chance of a negative slope (assuming a continuous probability distribution of the residuals) is 50% under the null, by definition the p-value is 50%. (If you observe a positive slope, the p-value is 100%.) You will have no trouble writing an R function to do this calculation! If you need further explanation, see stats.stackexchange.com/questions/tagged/p-value?tab=Votes. $\endgroup$
    – whuber
    Aug 10, 2020 at 16:58
  • $\begingroup$ Re the edit: if you change $n-2$ to $n-1$ in the calculation, you will get the wrong p-value, that's all. $\endgroup$
    – whuber
    Aug 10, 2020 at 17:38
  • 3
    $\begingroup$ Why are you finding the correlation between two points? You always can draw a straight line through two points. The correlation is either a perfect 1 or -1. $\endgroup$
    – Dave
    Aug 10, 2020 at 17:46

1 Answer 1

-3
$\begingroup$

Finally, what I did.

I changed the R function corr.test:

 r <- r/1.001
      t <- (r * sqrt(n - 1))/sqrt(1 - r^2)
      p <- -2 * expm1(pt(abs(t), (n - 1), log.p = TRUE))

a) I changed the Formula: where n-2 became n-1 in order to remove "0" from numerator.

b) I divided the whole r correlation coefficient matrix with r/1.001 in order to change "1" or "-1" values into 0.9999 or - 0.999, in order to remove "division by zero" error (denumerator thing).

---Then it is possible to produce "r values" and "p values" of just two observations. ---I know that the result will be not have much "generability", but just correlating two observations per case do not have much generability, anyhow!

corr_tst_2obs <-function (x, y = NULL, use = "pairwise", method = "pearson", 
                   adjust = "holm", alpha = 0.05, ci = TRUE, minlength = 5) 
{
  cl <- match.call()
  if (is.null(y)) {
    r <- cor(x, use = use, method = method)
    sym <- TRUE
    n <- t(!is.na(x)) %*% (!is.na(x))
  }
  else {
    r <- cor(x, y, use = use, method = method)
    sym = FALSE
    n <- t(!is.na(x)) %*% (!is.na(y))
  }
  if ((use == "complete") | (min(n) == max(n))) 
    n <- min(n)
  r <- r/1.001
  t <- (r * sqrt(n - 1))/sqrt(1 - r^2)
  p <- -2 * expm1(pt(abs(t), (n - 1), log.p = TRUE))
  se <- sqrt((1 - r * r)/(n - 2))
  nvar <- ncol(r)
  p[p > 1] <- 1
  if (adjust != "none") {
    if (is.null(y)) {
      lp <- upper.tri(p)
      pa <- p[lp]
      pa <- p.adjust(pa, adjust)
      p[upper.tri(p, diag = FALSE)] <- pa
    }
    else {
      p[] <- p.adjust(p, adjust)
    }
  }
  z <- fisherz(r[lower.tri(r)])
  if (ci) {
    if (min(n) < 4) {
      warning("Number of subjects must be greater than 3 to find confidence intervals.")
    }
    if (sym) {
      ncors <- nvar * (nvar - 1)/2
    }
    else ncors <- prod(dim(r))
    if (adjust != "holm") {
      dif.corrected <- qnorm(1 - alpha/(2 * ncors))
    }
    else {
      ord <- order(abs(z), decreasing = FALSE)
      dif.corrected <- qnorm(1 - alpha/(2 * order(ord)))
    }
    alpha <- 1 - alpha/2
    dif <- qnorm(alpha)
    if (sym) {
      if (is.matrix(n)) {
        sef <- 1/sqrt(n[lower.tri(n)] - 3)
      }
      else {
        sef <- 1/sqrt(n - 3)
      }
      lower <- fisherz2r(z - dif * sef)
      upper <- fisherz2r(z + dif * sef)
      lower.corrected <- fisherz2r(z - dif.corrected * 
                                     sef)
      upper.corrected <- fisherz2r(z + dif.corrected * 
                                     sef)
      ci <- data.frame(lower = lower, r = r[lower.tri(r)], 
                       upper = upper, p = p[lower.tri(p)])
      ci.adj <- data.frame(lower.adj = lower.corrected, 
                           upper.adj = upper.corrected)
      cnR <- abbreviate(colnames(r), minlength = minlength)
      k <- 1
      for (i in 1:(nvar - 1)) {
        for (j in (i + 1):nvar) {
          rownames(ci)[k] <- paste(cnR[i], cnR[j], sep = "-")
          k <- k + 1
        }
      }
    }
    else {
      n.x <- NCOL(x)
      n.y <- NCOL(y)
      z <- fisherz(r)
      if (adjust != "holm") {
        dif.corrected <- qnorm(1 - (1 - alpha)/(n.x * 
                                                  n.y))
      }
      else {
        ord <- order(abs(z), decreasing = FALSE)
        dif.corrected <- qnorm(1 - (1 - alpha)/(order(ord)))
      }
      sef <- 1/sqrt(n - 3)
      lower <- as.vector(fisherz2r(z - dif * sef))
      upper <- as.vector(fisherz2r(z + dif * sef))
      lower.corrected <- fisherz2r(z - dif.corrected * 
                                     sef)
      upper.corrected <- fisherz2r(z + dif.corrected * 
                                     sef)
      ci <- data.frame(lower = lower, r = as.vector(r), 
                       upper = upper, p = as.vector(p))
      ci.adj <- data.frame(lower.adj = as.vector(lower.corrected), 
                           r = as.vector(r), upper.adj = as.vector(upper.corrected))
      cnR <- abbreviate(rownames(r), minlength = minlength)
      cnC <- abbreviate(colnames(r), minlength = minlength)
      k <- 1
      for (i in 1:NCOL(y)) {
        for (j in 1:NCOL(x)) {
          rownames(ci)[k] <- paste(cnR[j], cnC[i], sep = "-")
          k <- k + 1
        }
      }
    }
  }
  else {
    ci <- sef <- ci.adj <- NULL
  }
  result <- list(r = r, n = n, t = t, p = p, se = se, sef = sef, 
                 adjust = adjust, sym = sym, ci = ci, ci.adj = ci.adj, 
                 Call = cl)
  class(result) <- c("psych", "corr.test")
  return(result)
}

Edit note: if the correlation coefficient is -1 or 1, your results are by DEFAULT statistically significant, because R correlation coefficient is at its maximum value. When it equals zero, then the result is not statistical significant. Therefore, maybe this function that I made of, it may not be of use.

$\endgroup$
1
  • 2
    $\begingroup$ Correlating two observations makes no sense to me. The correlation is going to be $\pm 1$. Perhaps what you want to consider is something about how likely it is that you have positive correlation given the slope between your two points. $\endgroup$
    – Dave
    Aug 10, 2020 at 18:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.