顯示具有 統計 標籤的文章。 顯示所有文章
顯示具有 統計 標籤的文章。 顯示所有文章

2013年8月4日 星期日

用 PHP 計算樣本相關係數

今天看 "真希望老師這樣教統計" 越看越有趣, 其中相關係數的計算, 書裡講的都是關於母體的計算, 但現實例子大都是有限樣本, 這時就要考慮自由度減 1 問題. 所謂相關係數是指 X,Y 兩組數據之間的關連性 :

X,Y 的相關係數=(X,Y 的共變異數) / (X 的樣本標準差 * Y 的樣本標準差)

而所謂樣本共變異數則是 :

X,Y 的共變異數=X,Y 的離均差交乘積和 / (樣本數 - 1)

這裡在母體共變異數是不用減 1 的, 在樣本因自由度少 1 故要減 1.

      $X=Array(25,23,27,35,30);
      $Y=Array(35,27,36,45,42);
      $xavg=array_sum($X)/count($X); //X 平均值
      $yavg=array_sum($Y)/count($Y); //Y 平均值
      $xsum=array_sum($X);           //X 總和
      $ysum=array_sum($Y);           //Y 總和
      $x_square_sum=0;               //X 平方和累計
      $y_square_sum=0;               //Y 平方和累計
      $XMD=Array();                  //X 離均差
      $YMD=Array();                  //Y 離均差
      $mdcross_sum=0;                //X,Y 離均差交乘積和
      $count=count($X);              //元素個數
      for ($i=0; $i <$count; ++$i) {
           $xdif=(float)$X[$i]-$xavg; //X 離均差
           $ydif=(float)$Y[$i]-$yavg; //Y 離均差
           $XMD[$i]=$xdif;
           $YMD[$i]=$ydif;
           $mdcross_sum += $xdif*$ydif;       //X,Y 離均差交乘積和
           $xdif_square_sum += pow($xdif, 2); //X 離均差平方和
           $x_square_sum += pow($X[$i], 2);   //X 平方和累計
           $y_square_sum += pow($Y[$i], 2);   //Y 平方和累計
           } //end of for
      //計算樣本標準差 & 乘積
      $xstd=sqrt(($x_square_sum-pow($xsum,2)/$count)/($count-1));
      $ystd=sqrt(($y_square_sum-pow($ysum,2)/$count)/($count-1));
      $xystd=$xstd*$ystd; //兩標準差乘積
      //計算樣本共變異數
      $covar=$mdcross_sum/($count-1);
      //計算相關係數
      $corr=$covar/$xystd;  //答案是 0.94137554144354

其實同樣數據, 我用母體公式計算相關係數, 答案也是 0.94, 沒什麼差異.

參考網站 :
http://stat.nuk.edu.tw/prost/content2/statics_6.htm (樣本共變異數)
http://greenhornfinancefootnote.blogspot.tw/2007/08/blog-post_27.html  (樣本標準差)

2013年8月3日 星期六

用 PHP 求線性迴歸方程式

今天去左新還書借書, 找到這本 "真希望老師這樣教統計", 覺得很面熟, 好像有買過, 又怕萬一沒買, 所以先借再說, 結果回家一找, 真的在書架上有, 下週再還吧. 稍微翻了一下, 剛好翻到上回討論的變異係數, 哇, 解說非常清楚, 這種好書買來竟然擱在書架上這麼久! 接著看到介紹迴歸分析, 如果兩組數據相關係數很高, 可以用一條近似直線 Y=a + bX 來預估, 謂之線性迴歸, 嘿, 那這斜率 b 是否可以用來代表營益率的變化趨勢呢?
根據統計學理論, Y=a + bX 中,

b=X,Y 離均差交乘積和 / X 離均差平方和
a=Y 平均值 - b * X 平均值

其 PHP 程式如下 :

線性迴歸方程式 : http://mybidrobot.allalla.com/finance/regression.php [看原始碼]

    $X=explode(",",$_REQUEST["X"]);
    $Y=explode(",",$_REQUEST["Y"]);
    $xavg=array_sum($X)/count($X); //X 平均值
    $yavg=array_sum($Y)/count($Y); //Y 平均值
    $XMD=Array();         //X 離均差
    $YMD=Array();         //Y 離均差
    $mdcross_sum=0;       //X,Y 離均差交乘積和
    $xdif_square_sum=0;   //X 離均差平方和
    $count=count($X);
    for ($i=0; $i<count($X); $i++) {
         $xdif=(float)$X[$i]-$xavg; //X 離均差
         $ydif=(float)$Y[$i]-$yavg; //Y 離均差
         $XMD[$i]=$xdif;
         $YMD[$i]=$ydif;
         $mdcross_sum += $xdif*$ydif;       //X,Y 離均差交乘積和
         $xdif_square_sum += pow($xdif, 2); //X 離均差平方和
         } //end of for
    $b=round($mdcross_sum/$xdif_square_sum, 2);  //計算斜率 b
    $a=round($yavg-$b*$xavg,2);                  //計算常數項 a
    echo "X=".join(", ",$X)."<br>";
    echo "Y=".join(", ",$Y)."<br>";
    echo "常數項 a=".$a."<br>";
    echo "斜率 b=".$b."<br>";
    echo "線性迴歸方程式 Y = ".$a." + (".$b.")X<br>";
    echo "X 平均值=".$xavg."<br>";
    echo "Y 平均值=".$yavg."<br>";
    echo "X 離均差=".join(", ",$XMD)."<br>";
    echo "Y 離均差=".join(", ",$YMD)."<br>";
    echo "X,Y 離均差交乘積和=".$mdcross_sum."<br>";
    echo "X 離均差平方和=".$xdif_square_sum."<br>";

參考 : SQL server一元线性回归统计说明

2013年7月31日 星期三

年複合成長率

年複合成長率常在新聞或理財書籍中看到, 今天在寫 "看懂新聞 2" 的閱讀筆記時, 剛好看到這詞彙, 找了一下網路資料 (如下), 原來就是用複利的觀念來看成長率, 複利公式 :

FV=PV(1+i)**n          終值=初值(1+利息)**周期

年複合成長率就是反求複利公式中的利息 :

i=(FV/PV)**(1/n)-1  

也就是終值除以初值, 開 n 次方後, 再減 1 即得.

例如台積電的損益表, 2003 年營收為 2030 億, 2012 年已成長為 5063 億, 平均每年成長 (5063-2030)/10=303.3 億, 平均成長率為 303.3/2030=14.94%, 十年來其年複合成長率為 9.41%. 可見平均成長率會比較大, 保險業務員常拿平均成長率來跟客戶說利息有多高, 但以年複合成長率來算, 就沒這麼高了.

我把這公式寫成 PHP 程式如下 :

年複合成長率 : http://mybidrobot.allalla.com/finance/cagr.php [看原始碼]

$PV=(float)$_REQUEST["PV"];
$FV=(float)$_REQUEST["FV"];
$n=(float)$_REQUEST["n"];
if ($PV != 0 && $n != 0) {
    $cagr=round((pow($FV/$PV,1/$n)-1)*100,2);
    echo "初值=$PV<br>終值=$FV<br>周期=$n<br>".
             "年複合成長率=$cagr%<br>".
             "<input type='button' value='回上一頁' ".
             "onclick='history.go(-1)'>";
     }
else {      
     echo "初值與周期不可為 0<br>".
              "<input type='button' value='回上一頁' ".
              "onclick='history.go(-1)'>";;
      }

參考資料 :

** 請問什麼是年複合成長率(CAGR, Compound Annual Growth Rate) ?
** 複利

2013年7月25日 星期四

變異係數與標準差

評估兩組數據的穩定度時, 譬如兩個企業的營益率變化, 應該使用變異係數, 而不是標準差, 因為不同公司的營益率會有不同水準. 根據維基的解釋 :

"變異係數只對由比率純量計算出來的數值有意義, 變異係數是一個無因次量, 因此在比較兩組因次不同或均值不同的數據時, 應該用變異係數而不是標準差來作為比較的參考。"

變異係數=標準差/平均值

變異係數 CV : http://mybidrobot.allalla.com/finance/cv.php [看原始碼]

我們用一個簡單程式來說明, 例如一組五個數據 : 100,100,100,100,100, 標準差與變異係數當然是 0, 如果其中一個數據由 100 降一半為 50,100,100,100,100, 那麼標準差是 22.361, 而變異係數是 25. 這跟 10,20,20,20,20 這組同樣是有一個數據降一半的變異係數是一樣的, 都是 25, 但這組標準差是 4.472. 所以看標準差是無法比較的, 要化成變異係數去比. 這種除以平均值的手法其實也就是所謂的正規化的一種方式, 所以, 變異係數可以說是正規化的標準差.

$arr=Array(50,100,100,100,100);
$sum=0; //總和
$square=0;  //平方和
$count=count($arr);
for ($j=0; $j<$count $j++) { 
       $sum += $arr[$j]; //和累計
       $square += pow($arr[$j], 2); //平方和累計 (計算標準差用)
       } //end of for
$avg=round($sum/$count,2);  //計算平均值
$std=sqrt(($square-pow($sum,2)/
$count)/($count-1)); //計算樣本標準差
if ($avg != 0) {$CV=round(100*$std/$avg);}  // //計算變異係數
else {$CV=9999;}  //表示極大值