奇数Pearson相关系数结果

时间:2010-01-28 09:31:24

标签: c

我在C编程课程中有一个编程来编写一个程序来获得2组实数的相关系数。我已经给了方程式,它引用了维基百科,所以我仔细检查了那里的方程式。这是一个方程式的链接,这似乎是我研究的标准:

alt text

我已经编写了程序,但是当我运行它时,我得到的数字大于1,我知道这是不正确的。我多次查看我的代码,但找不到任何不合适的地方,所以我尝试在结束时用n除以n-1,这给了我预期的-1到1范围的值,所以我测试了它反对我在网上找到的数据值以及相关系数计算器(http://easycalculation.com/statistics/correlation.php),我现在得到了我输入的所有数字的正确结果。我无法弄清楚为什么会这样,所以我想在这里可以得到一些帮助。这是我的程序代码,如果还有什么突出我在这里做错了我会很乐意听到一些建议,但主要是我想弄清楚为什么我得到了正确的结果与出现的是一个错误的等式。

然后读入两个数组(x和y)的值,然后计算 两组数字之间的相关系数。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(void) {
   int n;  /* value to determine array length */
   /* declare variables to hold results for each equation for x and y
   initialize all to zero to prepare for summation */
   float r = 0.0, xbar = 0.0, ybar = 0.0, sx = 0.0, sy = 0.0;

   /*get number n input from user */
   printf("Please enter a number n: ");
   scanf("%d", &n);

   if( n < 1) {
      printf("n must be a positive number.\nPlease enter a new value: ");
      scanf("%d", &n);
      if( n < 1) {
         printf("Invalid input, exiting...\n");
         return 0;
      }
   }

   /*initialize arrays x and y with length of n */
   float x[n], y[n];
   /*use for loop to read in values of x*/
   int i;
   for(i = 0; i < n; ++i) {
      printf("Please enter a number for x: ");
      scanf("%f", &x[i]);
   }
   /*use for loop to read in values of y*/
   for(i = 0; i < n; ++i) {
      printf("Please enter a number for y: ");
      scanf("%f", &y[i]);
   }

   /*compute xbar */
   for(i = 0; i < n; ++i) {
      xbar += x[i];
   }
   xbar /= n;
   /*compute ybar*/
   for(i = 0; i < n; ++i) {
      ybar += y[i];
   }
   ybar /= n;

   /* compute standard deviation of x*/
   for(i = 0; i < n; ++i) {
      sx += (x[i] - xbar) * (x[i] - xbar);
   }
   sx = sqrt((sx / n));
   /* compute standard deviation of y */
   for(i = 0; i < n; ++i) {
      sy += (y[i] - ybar) * (y[i] - ybar);
   }
   sy = sqrt((sy / n));

   /*compute r, the correlation coefficient between the two arrays */
   for( i = 0; i < n; ++i ) {
      r += (((x[i] - xbar)/sx) * ((y[i] - ybar)/sy));
   }
   r /= (n); /* originally divided by n-1, but gave incorrect results
   dividing by n instead produces the desired output */
   /* print results */ 
   printf("The correlation coefficient of the entered lists is: %6.4f\n", r);
   return 0;

}

(看起来我的代码格式化不起作用,对此非常抱歉。尝试使用标签和按钮,但无法弄明白。看起来我有点工作,比以前更好。)

1 个答案:

答案 0 :(得分:7)

您计算的标准偏差为:

sx = sqrt((sx / n));

,同样适用于sy

您使用的公式在分母中使用n-1来计算此公式(reason:有n-1个自由度,因此您应该除以n-1)。因此,您的sxsy实际上是sx'sy',其中sx' = sx*sqrt(n-1)/sqrt(n)sy' = sy*sqrt(n-1)/sqrt(n)。所以,sx' * sy' = sx * sy * (n-1)/n。由于sx*sy位于分母中,因此您的计算偏差为n/(n-1)。将其除以n可以得出除求和之外所需的因子。

因此,如果您更改了代码以计算样本标准偏差(除以n-1),您最终可以除以n-1,您的代码将获得您期望的结果。为了提高效率,由于除法将取消,因此您可以节省一些计算并提高准确度,只需在n-1sx的计算中除以sy,然后省略最终的分工:

sx = sqrt((sx / n));
sy = sqrt((sy / n));

成为

sx = sqrt(sx);
sy = sqrt(sy);

r /= (n);

完全消失。

编辑:因为你问过......

  1. 除非必须,否则没有理由使用floatdouble为您提供更好的精确度。
  2. 默认情况下,stdout在大多数系统上都是行缓冲的,因此在致电scanf()之前,您的提示可能不会显示。要确保您的提示显示,请在fflush(stdout);来电后printf()进行操作。
  3. 安全使用scanf()非常困难。对于读取数字,当有人输入不在数据类型范围内的数字时,scanf()具有未定义的行为。此外,对于有人输入非整数以响应您的提示的情况也是如此。对于您的情况,您可以将n作为命令行参数传递,然后使用strtol(argv[1])来解析该数字。如果您仍想阅读stdin,请使用fgets() + sscanf()组合或fgets() + strtol()
  4. 您可以减少程序中的循环次数。例如,您可以在同一循环中计算xbarybar。更好的是,您可以编写一个函数double avg(double *data, int n)来计算n值的平均值,然后执行:xbar=avg(x, n);ybar=avg(y, n);
  5. 同样,您可以定义一个函数double std(double *data, int n),然后使用它来计算sxsy
  6. 最后,虽然没关系,但你的括号太多了:sqrt((sx / n));最好写成sqrt(sx / n);r /= (n);也不需要括号。