Delphi版的线性回归分析

本文介绍了一个Delphi实现的线性回归分析类TLinearRegression,该类支持一元及多元线性回归分析,并提供了丰富的统计指标计算方法,如相关系数、回归方差等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章《C语言版的线性回归分析函数》发布后,不少朋友留言或给我来信,询问能否提供Delphi版的线性回归分析代码,因C语言版是我以前DOS下的老代码稍作整理后发布的,所以没有现成的Delphi代码,今天比较闲,于是将C代码改写为Delphi代码贴在下面,有关的回归公式说明及例子图示可参见《C语言版的线性回归分析函数》,这里不再累叙,由于改写时间仓促,可能有错误,请不吝指出,亦可来信建议:maozefa@hotmail.com

线性回归分析代码:

unitRegression;

interface

usesSysUtils;

type
PEquationsData
= ^ TEquationsData;
TEquationsData
= array[ 0 .. 0 ]ofDouble;
// 线性回归
TLinearRegression = class (TObject)
private
FData:PEquationsData;
FAnswer:PEquationsData;
FSquareSum:Double;
FSurplusSum:Double;
FRowCount:Integer;
FColCount:Integer;
FModify:Boolean;
functionGetAnswer(Index:Integer):Double;
functionGetItem(ARow,ACol:Integer):Double;
procedureSetItem(ARow,ACol:Integer;
const Value:Double);
procedureSetColCount(
const Value:Integer);
procedureSetRowCount(
const Value:Integer);
procedureSetSize(
const ARowCount,AColCount:Integer);
procedureSetModify(
const Value:Boolean);
functionGetCorrelation:Double;
functionGetDeviatSum:Double;
functionGetFTest:Double;
functionGetSurplus:Double;
functionGetVariance:Double;
functionGetStandardDiffer:Double;
functionGetEstimate(ARow:Integer):Double;
public
constructorCreate(
const AData; const ARowCount,AColCount:Integer);overload;
destructorDestroy;
override ;
// 计算回归方程
procedureCalculation;
// 设置回归数据
// AData[ARowCount*AColCount]二维数组;X1i,X2i,...Xni,Yi(i=0toARowCount-1)
// ARowCount:数据行数;AColCount数据列数
procedureSetData( const AData; const ARowCount,AColCount:Integer);
// 数据列数(自变量个数+Y)
propertyColCount:IntegerreadFColCountwriteSetColCount;
// 数据行数
propertyRowCount:IntegerreadFRowCountwriteSetRowCount;
// 原始数据
propertyData[ARow,ACol:Integer]:DoublereadGetItemwriteSetItem; default ;
propertyModify:BooleanreadFModify;
// 回归系数数组(B0,B1...Bn)
propertyAnswer[Index:Integer]:DoublereadGetAnswer;
// Y估计值
propertyEstimate[ARow:Integer]:DoublereadGetEstimate;
// 回归平方和
propertyRegresSquareSum:DoublereadFSquareSum;
// 剩余平方和
propertySurplusSquareSum:DoublereadFSurplusSum;
// 离差平方和
propertyDeviatSquareSum:DoublereadGetDeviatSum;
// 回归方差
propertyRegresVariance:DoublereadGetVariance;
// 剩余方差
propertySurplusVariance:DoublereadGetSurplus;
// 标准误差
propertyStandardDiffer:DoublereadGetStandardDiffer;
// 相关系数
propertyCorrelation:DoublereadGetCorrelation;
// F检验
propertyF_Test:DoublereadGetFTest;
end;

// 解线性方程。AData[count*(count+1)]矩阵数组;count:方程元数;
// Answer[count]:求解数组。返回:True求解成功,否则无解或者无穷解
functionLinearEquations( const AData;Count:Integer;varAnswer:arrayofDouble):Boolean;

implementation

const
SMatrixSizeError
= ' Regressiondatamatrixcannotbelessthan2*2 ' ;
SIndexOutOfRange
= ' indexoutofrange ' ;
SEquationNoSolution
= ' EquationnosolutionorInfiniteSolutions ' ;

functionLinearEquations(
const AData;Count:Integer;varAnswer:arrayofDouble):Boolean;
var
j,m,n,ColCount:Integer;
tmp:Double;
Data,d:PEquationsData;
begin
Result:
= False;
if Count < 2 thenExit;

ColCount:
= Count + 1 ;
GetMem(Data,Count
* ColCount * Sizeof(Double));
GetMem(d,ColCount
* Sizeof(Double));
try
Move(AData,Data
^ ,Count * ColCount * Sizeof(Double));
for m: = 0 toCount - 2 do
begin
n:
= m + 1 ;
// 如果主对角线元素为0,行交换
while (n < Count)and(Data ^ [m * ColCount + m] = 0.0 ) do
begin
if Data ^ [n * ColCount + m] <> 0.0 then
begin
Move(Data
^ [m * ColCount + m],d ^ ,ColCount * Sizeof(Double));
Move(Data
^ [n * ColCount + m],Data ^ [m * ColCount + m],ColCount * Sizeof(Double));
Move(d
^ ,Data ^ [n * ColCount + m],ColCount * Sizeof(Double));
end;
Inc(n);
end;
// 行交换后,主对角线元素仍然为0,无解
if Data ^ [m * ColCount + m] = 0.0 thenExit;
// 消元
for n: = m + 1 toCount - 1 do
begin
tmp:
= Data ^ [n * ColCount + m] / Data ^ [m * ColCount + m];
for j: = mtoCount do
Data
^ [n * ColCount + j]: = Data ^ [n * ColCount + j] - tmp * Data ^ [m * ColCount + j];
end;
end;
FillChar(d
^ ,Count * Sizeof(Double), 0 );
// 求得count-1的元
Answer[Count - 1 ]: = Data ^ [(Count - 1 ) * ColCount + Count] /
Data
^ [(Count - 1 ) * ColCount + Count - 1 ];
// 逐行代入求各元
for m: = Count - 2 downto 0 do
begin
for j: = Count - 1 downtom + 1 do
d
^ [m]: = d ^ [m] + Answer[j] * Data ^ [m * ColCount + j];
Answer[m]:
= (Data ^ [m * ColCount + Count] - d ^ [m]) / Data ^ [m * ColCount + m];
end;
Result:
= True;
finally
FreeMem(d);
FreeMem(Data);
end;
end;

{TLinearRegression}

procedureTLinearRegression.Calculation;
var
m,n,i,count:Integer;
dat:PEquationsData;
a,b,d:Double;
begin
if (FRowCount < 2 )or(FColCount < 2 )then
raiseException.Create(SMatrixSizeError);
if notFModifythenExit;
GetMem(dat,FColCount
* (FColCount + 1 ) * Sizeof(Double));
try
count:
= FColCount - 1 ;
dat
^ [ 0 ]: = FRowCount;
for n: = 0 tocount - 1 do
begin
a:
= 0.0 ;
b:
= 0.0 ;
for m: = 0 toFRowCount - 1 do
begin
d:
= FData ^ [m * FColCount + n];
a:
= a + d;
b:
= b + d * d;
end;
dat
^ [n + 1 ]: = a;
dat
^ [(n + 1 ) * (FColCount + 1 )]: = a;
dat
^ [(n + 1 ) * (FColCount + 1 ) + n + 1 ]: = b;
for i: = n + 1 tocount - 1 do
begin
a:
= 0.0 ;
for m: = 0 toFRowCount - 1 do
a:
= a + FData ^ [m * FColCount + n] * FData ^ [m * FColCount + i];
dat
^ [(n + 1 ) * (FColCount + 1 ) + i + 1 ]: = a;
dat
^ [(i + 1 ) * (FColCount + 1 ) + n + 1 ]: = a;
end;
end;
b:
= 0.0 ;
for m: = 0 toFRowCount - 1 do
b:
= b + FData ^ [m * FColCount + count];
dat
^ [FColCount]: = b;
for n: = 0 tocount - 1 do
begin
a:
= 0.0 ;
for m: = 0 toFRowCount - 1 do
a:
= a + FData ^ [m * FColCount + n] * FData ^ [m * FColCount + count];
dat
^ [(n + 1 ) * (FColCount + 1 ) + FColCount]: = a;
end;
if notLinearEquations(dat ^ ,FColCount,FAnswer ^ )then
raiseException.Create(SEquationNoSolution);
FSquareSum:
= 0.0 ;
FSurplusSum:
= 0.0 ;
b:
= b / FRowCount;
for m: = 0 toFRowCount - 1 do
begin
a:
= FAnswer ^ [ 0 ];
for i: = 1 tocount do
a:
= a + FData ^ [m * FColCount + i - 1 ] * FAnswer[i];
FSquareSum:
= FSquareSum + (a - b) * (a - b);
d:
= FData ^ [m * FColCount + count];
FSurplusSum:
= FSurplusSum + (d - a) * (d - a);
end;
SetModify(False);
finally
FreeMem(dat);
end;
end;

constructorTLinearRegression.Create(
const AData; const ARowCount,
AColCount:Integer);
begin
SetData(AData,ARowCount,AColCount);
end;

destructorTLinearRegression.Destroy;
begin
SetSize(
0 , 0 );
end;

functionTLinearRegression.GetAnswer(Index:Integer):Double;
begin
if (Index < 0 )or(Index >= FColCount)then
raiseException.Create(SIndexOutOfRange);
if notAssigned(FAnswer)then
Result:
= 0.0
else
Result:
= FAnswer ^ [Index];
end;

functionTLinearRegression.GetCorrelation:Double;
begin
Result:
= DeviatSquareSum;
if Result <> 0.0 then
Result:
= Sqrt(FSquareSum / Result);
end;

functionTLinearRegression.GetDeviatSum:Double;
begin
Result:
= FSquareSum + FSurplusSum;
end;

functionTLinearRegression.GetEstimate(ARow:Integer):Double;
var
I:Integer;
begin
if (ARow < 0 )or(ARow >= FRowCount)then
raiseException.Create(SIndexOutOfRange);
Result:
= Answer[ 0 ];
for I: = 1 toColCount - 1 do
Result:
= Result + FData ^ [ARow * FColCount + I - 1 ] * Answer[I];
end;

functionTLinearRegression.GetFTest:Double;
begin
Result:
= SurplusVariance;
if Result <> 0.0 then
Result:
= RegresVariance / Result;
end;

functionTLinearRegression.GetItem(ARow,ACol:Integer):Double;
begin
if (ARow < 0 )or(ARow >= FRowCount)or(ACol < 0 )or(ACol >= FColCount)then
raiseException.Create(SIndexOutOfRange);
Result:
= FData ^ [ARow * FColCount + ACol];
end;

functionTLinearRegression.GetStandardDiffer:Double;
begin
Result:
= Sqrt(SurplusVariance);
end;

functionTLinearRegression.GetSurplus:Double;
begin
if FRowCount - FColCount < 1 then
Result:
= 0.0
else
Result:
= FSurplusSum / (FRowCount - FColCount);
end;

functionTLinearRegression.GetVariance:Double;
begin
if FColCount < 2 then
Result:
= 0.0
else
Result:
= FSquareSum / (FColCount - 1 );
end;

procedureTLinearRegression.SetColCount(
const Value:Integer);
begin
if Value < 2 then
raiseException.Create(SMatrixSizeError);
SetSize(FRowCount,Value);
end;

procedureTLinearRegression.SetData(
const AData; const ARowCount,AColCount:Integer);
begin
if (ARowCount < 2 )or(AColCount < 2 )then
raiseException.Create(SMatrixSizeError);
SetSize(ARowCount,AColCount);
Move(AData,FData
^ ,FRowCount * FColCount * Sizeof(Double));
end;

procedureTLinearRegression.SetItem(ARow,ACol:Integer;
const Value:Double);
begin
if (ARow < 0 )or(ARow >= FRowCount)or(ACol < 0 )or(ACol >= FColCount)then
raiseException.Create(SIndexOutOfRange);
if FData ^ [ARow * (FColCount) + ACol] <> Valuethen
begin
FData
^ [ARow * (FColCount) + ACol]: = Value;
SetModify(True);
end;
end;

procedureTLinearRegression.SetModify(
const Value:Boolean);
begin
if FModify <> Valuethen
begin
FModify:
= Value;
if FModifythen
begin
FillChar(FAnswer
^ ,FColCount * Sizeof(Double), 0 );
FSquareSum:
= 0.0 ;
FSurplusSum:
= 0.0 ;
end;
end;
end;

procedureTLinearRegression.SetRowCount(
const Value:Integer);
begin
if Value < 2 then
raiseException.Create(SMatrixSizeError);
SetSize(Value,FColCount);
end;

procedureTLinearRegression.SetSize(
const ARowCount,AColCount:Integer);
begin
if (FRowCount = ARowCount)and(FColCount = AColCount)then
Exit;
if Assigned(FData)then
begin
FreeMem(FData);
FData:
= nil;
FreeMem(FAnswer);
FAnswer:
= nil;
FModify:
= False;
end;

FRowCount:
= ARowCount;
FColCount:
= AColCount;

if (FRowCount = 0 )or(FColCount = 0 )thenExit;

GetMem(FData,FRowCount
* FColCount * Sizeof(Double));
FillChar(FData
^ ,FRowCount * FColCount * Sizeof(Double), 0 );
GetMem(FAnswer,FColCount
* Sizeof(Double));
SetModify(True);
end;

end.

因为一元线性回归分析本是多元线性回归分析的一个特例,因此原C代码中的一元线性回归函数取消,一元线性回归和多元线性回归都使用TLinearRegression类。下面是Pascal控制台应用程序例子:

programLinearRegression;

{$APPTYPECONSOLE}

uses
SysUtils,
Regression
in ' ....pasRegression.pas ' ;

const
data1:array[
1 .. 12 , 1 .. 2 ]ofDouble = (
// XY
( 187.1 , 25.4 ),
(
179.5 , 22.8 ),
(
157.0 , 20.6 ),
(
197.0 , 21.8 ),
(
239.4 , 32.4 ),
(
217.8 , 24.4 ),
(
227.1 , 29.3 ),
(
233.4 , 27.9 ),
(
242.0 , 27.8 ),
(
251.9 , 34.2 ),
(
230.0 , 29.2 ),
(
271.8 , 30.0 )
);

data:array[
1 .. 15 , 1 .. 5 ]ofDouble = (
// X1X2X3X4Y
( 316 , 1536 , 874 , 981 , 3894 ),
(
385 , 1771 , 777 , 1386 , 4628 ),
(
299 , 1565 , 678 , 1672 , 4569 ),
(
326 , 1970 , 785 , 1864 , 5340 ),
(
441 , 1890 , 785 , 2143 , 5449 ),
(
460 , 2050 , 709 , 2176 , 5599 ),
(
470 , 1873 , 673 , 1769 , 5010 ),
(
504 , 1955 , 793 , 2207 , 5694 ),
(
348 , 2016 , 968 , 2251 , 5792 ),
(
400 , 2199 , 944 , 2390 , 6126 ),
(
496 , 1328 , 749 , 2287 , 5025 ),
(
497 , 1920 , 952 , 2388 , 5924 ),
(
533 , 1400 , 1452 , 2093 , 5657 ),
(
506 , 1612 , 1587 , 2083 , 6019 ),
(
458 , 1613 , 1485 , 2390 , 6141 )
);

procedureDisplay(s:
string ;R:TLinearRegression);
var
i:Integer;
v,o:Double;
begin
Writeln(s);
Writeln(
' 回归方程式: ' );
Write(
' Y= ' ,R.Answer[ 0 ]: 1 : 5 );
for i: = 1 toR.ColCount - 1 do
Write(
' + ' ,R.Answer[i]: 1 : 5 , ' *X ' ,i);
Writeln;
Writeln(
' 回归显著性检验: ' );
Writeln(
' 回归平方和: ' ,R.RegresSquareSum: 12 : 4 , ' 回归方差: ' ,R.RegresVariance: 12 : 4 );
Writeln(
' 剩余平方和: '
[软件名称] CurveFit [功能] 1.进行y=a0+a1*x+a2*x^2+...+am*x^m多项式拟合; 2.进行y=Ax^B形式的指数拟合; 3.图形显示拟合曲线(值),残差曲线(值),调整图形显示属性(点的形状、大小,图形背景颜色),并可保存图形; 4.在评价标准:相关指数小于0.5的情况下,给出建议删除的点的序号。 5.计算结果保存为“数据源+--拟合形式结果.txt”的文件 [数学原理] 最小二乘法 [数据源文件格式] 文本源(*.txt) Excel源(*.xls) (打开Excel表格时,会出现暂时的延迟) [数据源格式] x y x1 y1 x2 y2 x3 y3 x4 y4 . . . . . . xn yn [例子] 见文件:正确格式TXT.txt,正确格式TXT--多项式拟合结果,正确格式TXT-指数拟合结果;正确格式EXCEL.xls,正确格式EXCEL--多项式拟合结果,正确格式EXCEL-指数拟合结果; [快速上手] 按照规定格式准备数据源; 打开程序; 选择数据源; 自动进行多项式拟合; 在图中点右键可进行多项操作; 图形显示拟合曲线(值),残差曲线(值),调整图形显示属性(点的形状、大小,图形背景颜色),并可保存图形; 自动保存计算结果 [高级使用] 按照规定格式准备数据源; 打开程序; 选择数据源; 自动进行多项式拟合; 修改拟合精度 修改多项式拟合的最高次幂(若为多项式拟合) 选择拟合形式 在图中点右键可进行多项操作; 图形显示拟合曲线(值),残差曲线(值),调整图形显示属性(点的形状、大小,图形背景颜色),并可保存图形; 自动保存计算结果 [注意] 必须按照规定格式输入数据,否则出错。 数据点个数应大于等于3,否则不无拟合意义。 最高拟合幂次方在0-10之间的正整数,即:m=[1,9],默认,m=1; 精度值:一般取小数点以后6位就可满足要求,不可盲目追究精度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值