2010-01-28 68 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