PHP實現簡單線性回歸之數學庫的重要性

簡介

與其它開放源碼語言(比如 Perl 和 Python)相比,PHP 社區缺少強有力的工作來開發數學庫。

造成這種狀況的一個原因可能是由于已經存在大量成熟的數學工具,這可能阻礙了社區自行開發 PHP 工具的工作。例如,我曾研究過一個功能強大的工具 S System,它擁有一組令人印象深刻的統計庫,專門被設計成用來分析數據集,並且在 1998 年由于其語言設計而獲得了 ACM 獎。如果 S 或者其開放源碼同類 R 僅僅是一個 exec_shell 調用,那麽爲何還要麻煩用 PHP 實現相同的統計計算功能呢?有關 S System、它的 ACM 獎或 R 的更多信息,請參閱相關參考資料。

難道這不是在浪費開發人員的精力嗎?如果開發 PHP 數學庫的動機是出自節省開發人員的精力以及使用最好的工具來完成工作,那麽 PHP 現在的課題是很有意義的。

另一方面,出于教學動機可能會鼓勵對 PHP 數學庫的開發。對于大約 10% 的人來說,數學是個值得探索的有趣課題。對于那些同時還熟練應用 PHP 的人來說,PHP 數學庫的開發可以增強數學學習過程,換句話說,不要只 閱讀有關 T 測試的章節,還要 實現一個能計算相應的中間值並用標准格式顯示它們的類。

通過指導和訓練,我希望證明開發 PHP 數學庫並不是一項很難的任務,它可能代表一項有趣的技術和學習難題。在本文中,我將提供一個 PHP 數學庫示例,名爲 SimpleLinearRegression ,它演示了一個可以用來開發 PHP 數學庫的通用方法。讓我們從討論一些通用的原則開始,這些原則指導我開發這個 SimpleLinearRegression 類。

指導原則

我使用了六個通用原則來指導 SimpleLinearRegression 類的開發。

每個分析模型建立一個類。

使用逆向鏈接來開發類。

預計有大量的 getter。

存儲中間結果。

爲詳細的 API 制定首選項。

盡善盡美並非目標。

讓我們更詳細地逐條研究這些指導方針。

每個分析模型建立一個類

每種主要的分析測試或過程應當有一個名稱與測試或過程名相同的 PHP 類,這個類包含了輸入函數、計算中間值和彙總值的函數和輸出函數(將中間值和彙總值用文本或圖形格式全部顯示在屏幕上)。

使用逆向鏈接來開發類

在數學編程中,編碼的目標通常是分析過程(比如 MultipleRegression 、 TimeSeries 或 ChiSquared )所希望生成的標准輸出值。從解決問題的角度出發,這意味著您可以使用逆向鏈接來開發數學類的方法。

例如,彙總輸出屏幕顯示了一個或多個彙總統計結果。這些彙總統計結果依賴于中間統計結果的計算,這些中間統計結果又可能會涉及到更深一層的中間統計結果,以此類推。這個基于逆向鏈接的開發方法導出了下一個原則。

預計有大量的 getter

數學類的大部分類開發工作都涉及到計算中間值和彙總值。實際上,這意味著,如果您的類包含許多計算中間值和彙總值的 getter 方法,您不應當感到驚訝。

存儲中間結果

將中間計算結果存儲在結果對象內,這樣您就可以將中間結果用作後續計算的輸入。在 S 語言設計中實施了這一原則。在當前環境下,通過選擇實例變量來表示計算得到的中間值和彙總結果,從而實施了該原則。

爲詳細的 API 制定首選項

當爲 SimpleLinearRegression 類中的成員函數和實例變量制定命名方案時,我發現:如果我使用較長的名稱(類似于 getSumSquaredError 這樣的名稱,而不是 getYY2 )來描述成員函數和實例變量,那麽就更容易了解函數的操作內容和變量所代表的意義。

我沒有完全放棄簡寫名稱;但是,當我用簡寫形式的名稱時,我得設法提供注釋以完整闡述該名稱的含義。我的看法是:高度簡寫的命名方案在數學編程中很常見,但它們使得理解和證明某個數學例程是否按部就班更爲困難,而原本不必造成此種困難。

盡善盡美並非目標

這個編碼練習的目標不是一定要爲 PHP 開發高度優化和嚴格的數學引擎。在早期階段,應當強調學習實現意義重大的分析測試,以及解決這方面的難題。

實例變量

當對統計測試或過程進行建模時,您需要指出聲明哪些實例變量。

實例變量的選擇可以通過說明由分析過程生成的中間值和彙總值來確定。每個中間值和彙總值都可以有一個相應的實例變量,將變量的值作爲對象屬性。

我采用這樣的分析來確定爲清單 1 中的 SimpleLinearRegression 類聲明哪些變量。可以對 MultipleRegression 、 ANOVA 或 TimeSeries 過程執行類似的分析。

清單 1. SimpleLinearRegression 類的實例變量

<?php

// Copyright 2003, Paul Meagher

// Distributed under GPL

class SimpleLinearRegression {

var $n;

var $X = array();

var $Y = array();

var $ConfInt;

var $Alpha;

var $XMean;

var $YMean;

var $SumXX;

var $SumXY;

var $SumYY;

var $Slope;

var $YInt;

var $PredictedY = array();

var $Error = array();

var $SquaredError = array();

var $TotalError;

var $SumError;

var $SumSquaredError;

var $ErrorVariance;

var $StdErr;

var $SlopeStdErr;

var $SlopeVal; // T value of Slope

var $YIntStdErr;

var $YIntTVal; // T value for Y Intercept

var $R;

var $RSquared;

var $DF; // Degrees of Freedom

var $SlopeProb; // Probability of Slope Estimate

var $YIntProb; // Probability of Y Intercept Estimate

var $AlphaTVal; // T Value for given alpha setting

var $ConfIntOfSlope;

var $RPath = "/usr/local/bin/R"; // Your path here

var $format = "%01.2f"; // Used for formatting output

}

?>

構造函數

SimpleLinearRegression 類的構造函數方法接受一個 X和一個 Y向量,每個向量都有相同數量的值。您還可以爲您預計的 Y值設置一個缺省爲 95% 的置信區間(confidence interval)。

構造函數方法從驗證數據形式是否適合于處理開始。一旦輸入向量通過了“大小相等”和“值大于 1”測試,就執行算法的核心部分。

執行這項任務涉及到通過一系列 getter

方法計算統計過程的中間值和彙總值。將每個方法調用的返回值賦給該類的一個實例變量。用這種方法存儲計算結果確保了前後鏈接的計算中的調用例程可以使用中

間值和彙總值。還可以通過調用該類的輸出方法來顯示這些結果,如清單 2 所描述的那樣。

清單 2. 調用類輸出方法

<?php

// Copyright 2003, Paul Meagher

// Distributed under GPL

function SimpleLinearRegression($X, $Y, $ConfidenceInterval="95") {

$numX = count($X);

$numY = count($Y);

if ($numX != $numY) {

die("Error: Size of X and Y vectors must be the same.");

}

if ($numX <= 1) {

die("Error: Size of input array must be at least 2.");

}

$this->n = $numX;

$this->X = $X;

$this->Y = $Y;

$this->ConfInt = $ConfidenceInterval;

$this->Alpha = (1 + ($this->ConfInt / 100) ) / 2;

$this->XMean = $this->getMean($this->X);

$this->YMean = $this->getMean($this->Y);

$this->SumXX = $this->getSumXX();

$this->SumYY = $this->getSumYY();

$this->SumXY = $this->getSumXY();

$this->Slope = $this->getSlope();

$this->YInt = $this->getYInt();

$this->PredictedY = $this->getPredictedY();

$this->Error = $this->getError();

$this->SquaredError = $this->getSquaredError();

$this->SumError = $this->getSumError();

$this->TotalError = $this->getTotalError();

$this->SumSquaredError = $this->getSumSquaredError();

$this->ErrorVariance = $this->getErrorVariance();

$this->StdErr = $this->getStdErr();

$this->SlopeStdErr = $this->getSlopeStdErr();

$this->YIntStdErr = $this->getYIntStdErr();

$this->SlopeTVal = $this->getSlopeTVal();

$this->YIntTVal = $this->getYIntTVal();

$this->R = $this->getR();

$this->RSquared = $this->getRSquared();

$this->DF = $this->getDF();

$this->SlopeProb = $this->getStudentProb($this->SlopeTVal, $this->DF);

$this->YIntProb = $this->getStudentProb($this->YIntTVal, $this->DF);

$this->AlphaTVal = $this->getInverseStudentProb($this->Alpha, $this->DF);

$this->ConfIntOfSlope = $this->getConfIntOfSlope();

return true;

}

?>

方法名及其序列是通過結合逆向鏈接和參考大學本科學生使用的統計學教科書推導得出的,該教科書一步一步地說明了如何計算中間值。我需要計算的中間值的名稱帶有“get”前綴,從而推導出方法名。

使模型與數據相吻合

SimpleLinearRegression 過程用于産生與數據相吻合的直線,其中直線具有以下標准方程:

y = b + mx

該方程的 PHP 格式看起來類似于清單 3:

清單 3. 使模型與數據相吻合的 PHP 方程

$PredictedY[$i] = $YIntercept + $Slope * $X[$i]

SimpleLinearRegression 類使用最小二乘法准則推導出 Y 軸截距(Y Intercept)和斜率(Slope)參數的估計值。這些估計的參數用來構造線性方程(請參閱 清單 3),該方程對 X和 Y值之間的關系進行建模。

使用推導出的線性方程,您就可以得到每個 X值對應的預測 Y值。如果線性方程與數據非常吻合,那麽 Y的觀測值與預測值趨近于一致。

如何確定是否非常吻合

SimpleLinearRegression 類生成了相當多的彙總值。一個重要的彙總值是 T統計值,它可以用來衡量一個線性方程與數據的 吻合程度。如果非常吻合,那麽 T 統計值往往很大。如果 T 統計值很小,那麽應當用一個模型替換該線性方程,該模型假設 Y值的均值是最佳預測值(也就是說,一組值的均值通常是下一個觀測值有用的預測值,使之成爲缺省模型)。

要測試 T 統計值是否大得足以不把 Y值的均值作爲最佳預測值,您需要計算獲取 T 統計值的隨機概率。如果獲取 T 統計值的概率很低,那麽您可以否定均值是最佳預測值這個無效假設,與此相對應,也就確信簡單線性模型與數據非常吻合。

那麽,如何計算 T 統計值的概率呢?

計算 T 統計值概率

由于 PHP 缺少計算 T 統計值概率的數學例程,因此我決定將此任務交給統計計算包 R(請參閱 參考資料中的 www.r-project.org)來獲得必要的值。我還想提醒大家注意該包,因爲:

R 提供了許多想法,PHP 開發人員可能會在 PHP 數學庫中模擬這些想法。

有了 R,可以確定從 PHP 數學庫獲得的值與那些從成熟的免費可用的開放源碼統計包中獲得的值是否一致。 清單 4 中的代碼演示了交給 R 來處理以獲取一個值是多麽容易。

清單 4. 交給 R 統計計算包來處理以獲取一個值

<?php

// Copyright 2003, Paul Meagher

// Distributed under GPL

class SimpleLinearRegression {

var $RPath = "/usr/local/bin/R"; // Your path here

function getStudentProb($T, $df) {

$Probability = 0.0;

$cmd = "echo 'dt($T, $df)' | $this->RPath --slave";

$result = shell_exec($cmd);

list($LineNumber, $Probability) = explode(" ", trim($result));

return $Probability;

}

function getInverseStudentProb($alpha, $df) {

$InverseProbability = 0.0;

$cmd = "echo 'qt($alpha, $df)' | $this->RPath --slave";

$result = shell_exec($cmd);

list($LineNumber, $InverseProbability) = explode(" ", trim($result));

return $InverseProbability;

}

}

?>

請注意,這裏已經設置了到 R 可執行文件的路徑,並在兩個函數中使用了該路徑。第一個函數根據學生的 T 分布返回了與 T 統計值相關的概率值,而第二個反函數計算了與給定的 alpha 設置相對應的 T 統計值。 getStudentProb 方法用來評估線性模型的吻合程度; getInverseStudentProb 方法返回一個中間值,它用來計算每個預測的 Y值的置信區間。

由于篇幅有限,我不可能逐個詳細說明這個類中的所有函數,因此如果您想搞清楚簡單線性回歸分析中所涉及的術語和步驟,我鼓勵您參考大學本科學生使用的統計學教科書。

燃耗研究

要演示如何使用該類,我可以使用來自公共事業中燃耗(burnout)研究中的數據。Michael Leiter 和 Kimberly Ann Meechan 研究了稱爲 消耗指數(Exhaustion Index)的燃耗度量單位和稱之爲 集中度(Concentration)的獨立變量之間的關系。集中度是指人們的社交接觸中來自其工作環境的那部分比例。

要研究他們樣本中個人的消耗指數值與集中度值之間的關系,請將這些值裝入適當命名的數組中,並用這些數組值對該類進行實例化。對類進行實例化後,顯示該類所生成的某些彙總值以評估線性模型與數據的吻合程度。

清單 5 顯示了裝入數據和顯示彙總值的腳本:

清單 5. 用于裝入數據並顯示彙總值的腳本

<?php

// BurnoutStudy.php

// Copyright 2003, Paul Meagher

// Distributed under GPL

include "SimpleLinearRegression.php";

// Load data from burnout study

$Concentration = array(20,60,38,88,79,87,

68,12,35,70,80,92,

77,86,83,79,75,81,

75,77,77,77,17,85,96);

$ExhaustionIndex = array(100,525,300,980,310,900,

410,296,120,501,920,810,

506,493,892,527,600,855,

709,791,718,684,141,400,970);

$slr = new SimpleLinearRegression($Concentration, $ExhaustionIndex);

$YInt = sprintf($slr->format, $slr->YInt);

$Slope = sprintf($slr->format, $slr->Slope);

$SlopeTVal = sprintf($slr->format, $slr->SlopeTVal);

$SlopeProb = sprintf("%01.6f", $slr->SlopeProb);

?>

<table border='1' cellpadding='5'>

<tr>

<th align='right'>Equation:</th>

<td></td>

</tr>

<tr>

<th align='right'>T:</th>

<td></td>

</tr>

<tr>

<th align='right'>Prob > T:</th>

<td><td>

</tr>

</table>

通過 Web 浏覽器運行該腳本,産生以下輸出:

Equation:

Exhaustion = -29.50 + (8.87 * Concentration)

T:

6.03

Prob > T:

0.000005

這張表的最後一行指出獲取這樣大 T值的 隨機概率非常低。可以得出這樣的結論:與僅僅使用消耗值的均值相比,簡單線性模型的預測能力更好。

知道了某個人的工作場所聯系的集中度,就可以用來預測他們可能正在消耗的燃耗程度。這個方程告訴我們:集中度值每增加 1 個單位,社會服務領域中一個人的消耗值就會增加 8 個單位。這進一步證明了:要減少潛在的燃耗,社會服務領域中的個人應當考慮在其工作場所之外結交朋友。

這只是粗略地描述了這些結果可能表示的含義。爲全面研究這個數據集的含義,您可能想更詳細地研究這個數據以確信這是正確的解釋。在下一篇文章中我將討論應當執行其它哪些分析。

您學到了什麽?

其一,要開發意義重大的基于 PHP 的數學包,您不必是一名火箭科學家。堅持標准的面向對象技術,以及明確地采用逆向鏈接問題解決方法,就可以相對方便地使用 PHP 實現某些較爲基本的統計過程。

從教學的觀點出發,我認爲:如果只是因爲要求您在較高和較低的抽象層次思考統計測試或例程,那麽這個練習是非常有用的。換句話說,補充您的統計測試或過程學習的一個好辦法就是將這個過程作爲算法實現。

要實現統計測試通常需要超出所給定的信息範圍並創造性地解決和發現問題。對于發現對某個學科認識的不足而言,它也是一個好辦法。

不利的一面,您發現 PHP 對于取樣分布缺乏內在手段,而這是實現大多數統計測試所必需的。您需要交給 R 來處理以獲取這些值,但是我擔心您會沒時間或沒興趣安裝 R。某些常見概率函數的本機 PHP 實現可以解決這個問題。

另一個問題是:該類生成許多中間值和彙總值,但是彙總輸出實際上沒有利用這一點。我提供了一些難處理的輸出,但是這既不夠充分也沒進行很好的組織,以致您無法充分地解釋分析結果。實際上,我完全不知道如何可以將輸出方法集成到該類中。這需要得到解決。

最後,要弄明白數據,不僅僅是察看彙總值就可以了。您還需要明白各個數據點是如何分布的。最好的辦法之一是將您的數據繪制成圖表。再次聲明,我對這方面不太了解,但是如果要用這個類來分析實際數據的話就需要解決這個問題。

PHP實現簡單線性回歸之數學庫的重要性
  簡介  與其它開放源碼語言(比如 Perl 和 Python)相比,PHP 社區缺少強有力的工作來開發數學庫。  造成這種狀況的一個原因可能是由于已經存在大量成熟的數學工具,這可能阻礙了社區自行開發 PHP 工具的工作...查看完整版>>PHP實現簡單線性回歸之數學庫的重要性
 
中文TTS 的簡單實現(基于linux)之 語音庫的實現
語音庫保存著常用漢字的發音(多音的漢字只記錄其一種發音,這也是本系統的一個缺陷,需要以後完善),所以先要得到一漢字集,這個漢字集包含了大部分常用的漢字,然後在根據這個漢字集,來一個個的取得漢字的發音,...查看完整版>>中文TTS 的簡單實現(基于linux)之 語音庫的實現
 
PHP實現簡單線性回歸之數據研究工具
PHP實現簡單線性回歸之數據研究工具
  概念   簡單線性回歸建模背後的基本目標是從成對的 X值和 Y值(即 X和 Y測量值)組成的二維平面中找到最吻合的直線。一旦用 最小方差法找到這條直線,就可以執行各種統計測試,以確定這條直線與觀測到的 Y值的...查看完整版>>PHP實現簡單線性回歸之數據研究工具
 
Java實現一元線性回歸
最近在寫一個熒光圖像分析軟件,需要自己擬合方程。一元回歸線公式的算法參考了《Java數值方法》,擬合度R^2(絕對系數)是自己寫的,歡迎討論。計算結果和Excel完全一致。總共三個文件:DataPoint.java/** * A data...查看完整版>>Java實現一元線性回歸
 
簡單實現StandbySQLServer數據庫的方法
  一、什麽要備份數據庫 ?  在現實IT世界裏,我們使用的服務器硬件可能因爲使用時間過長,而發生故障;  Windows系列服務器有可能藍屏或者感染病毒;SQL Server數據庫也可能因爲誤操作或Bug而停止運行。  如...查看完整版>>簡單實現StandbySQLServer數據庫的方法
 
php 實現簡單的權限管理
<?php/*權限設計有一個全局的管理員root每個欄目有個管理員權限爲其他權限的合每單個權限爲2的倍數list/read 1add 2edit 2del 4all admin*/if( 5&2){ echo 1;}else{ echo 0;}/*簡單的...查看完整版>>php 實現簡單的權限管理
 
用php簡單實現Search Engine Friendly的URL
上次寫了Search Engine Friendly的URL設計 - 俺在這個事上面折騰,要實現這個 的url轉換,實際上還有不同的辦法.比如說我用的是虛擬主機,也想實現url優化,但是我沒有服務器權限,這時候可以從PATH_INFO來下手.訪問這個u...查看完整版>>用php簡單實現Search Engine Friendly的URL
 
PHP單子模式(SINGLETON)的簡單實現
參考了 的討論,用以下代碼簡單實現單子模式(SINGLETON): 代碼片段: /*** Class: SingletonPool * Store multiple singletons (of different classes, naturally). **/ class Singleton { /** * 返回唯...查看完整版>>PHP單子模式(SINGLETON)的簡單實現
 
Editplus + Zend Encoder實現簡單PHP源碼加密IDE環境
主頁:http://www.maxss.net/電郵:maxss.net@163.com 軟件環境:Windows 2000 Pro/SeverEditplusPHP 4.3.4Zend Optimizer 2.5Zend Encoder Unlimited 1.2 關于Editplus和PHP的介紹我就不多說了。首先說說Zend Optimiz...查看完整版>>Editplus + Zend Encoder實現簡單PHP源碼加密IDE環境
 
 
回到王朝網路移動版首頁