2010-01-28 49 views
2

我在C编程类中写了一个程序来获取2组实数的相关系数。我已经给出了方程,它引用了维基百科,所以我仔细检查了那里的方程。这里是公式,这似乎是从我的研究非常标准的链接:Odd Pearson相关系数结果

alt text

我写的程序,但是当我跑了我得到的数字比1我的结果时,我知道这是不正确的。我查了几遍代码,但找不到任何不合适的地方,所以我试着用n除以n而不是n,这给了我预期的-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; 

} 

(它看起来像我的代码格式不工作,对此深表遗憾。使用标签和按钮尝试,但不能弄明白。它看起来像我得到了它有些工作,比以前更好。)

+0

你能发布格式化的代码吗?这将使它更容易遵循。 – Mick 2010-01-28 09:34:21

+1

您是否尝试过使用'double'或甚至'long double'而不是'float'? – kennytm 2010-01-28 09:34:39

+0

@David:新的格式比以前更糟::(缩进4个空格或1个标签来标记一段代码,在发布之前查看预览 – kennytm 2010-01-28 09:39:14

回答

7

你正在计算标准差为:

sx = sqrt((sx/n)); 

,类似的还有sy

你已经使用公式中的分母计算该使用n-1reason:有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-1sxsy计算将提高你的准确度,然后忽略最后的分工,以及:

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

成为

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

和:

r /= (n); 

消失完全。

编辑:既然你问...

  1. 没有理由使用float,除非你要。 double给你更好的精度。
  2. 默认情况下,stdout在大多数系统上都是行缓冲的,所以在您致电scanf()之前,您的提示可能不会出现。为确保您的提示显示,请拨打printf()后拨打fflush(stdout);
  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);也不需要括号。
+0

谢谢Alok,那是做的伎俩,和链接的解释这是有道理的。我们给出的关于分配的等式使用n作为标准差的分母,所以它一定是教授的疏忽。 非常感谢您的帮助,很高兴知道我不是疯了。 – 2010-01-28 10:00:29

+0

很高兴帮助,也看到我的编辑优化。如果你想要一些积极的批评,我可以给你一些关于你的C编程的反馈:-) – 2010-01-28 10:03:19

+1

我总是欣赏建设性的批评,我可以做的任何事情来改善我的技术和风格。 – 2010-01-28 10:05:44