Here is a completely different regression line method, (For fun).
The only statistic is a mean, the rest is empirical.
Code: Select all
Function segmentdistance(lx1 As Double, _
ly1 As Double, _
lx2 As Double, _
ly2 As Double, _
px As Double,_
py As Double, _
Byref ox As Double=0,_
Byref oy As Double=0) As Double
Dim As Double M1,M2,C1,C2,B
B=(Lx2-Lx1):If B=0 Then B=1e-20
M2=(Ly2-Ly1)/B:If M2=0 Then M2=1e-20
M1=-1/M2
C1=py-M1*px
C2=(Ly1*Lx2-Lx1*Ly2)/B
Var L1=((px-lx1)*(px-lx1)+(py-ly1)*(py-ly1)),L2=((px-lx2)*(px-lx2)+(py-ly2)*(py-ly2))
Var a=((lx1-lx2)*(lx1-lx2) + (ly1-ly2)*(ly1-ly2))
Var a1=a+L1
Var a2=a+L2
Var f1=a1>L2,f2=a2>L1
If f1 Xor f2 Then
Var d1=((px-Lx1)*(px-Lx1)+(py-Ly1)*(py-Ly1))
Var d2=((px-Lx2)*(px-Lx2)+(py-Ly2)*(py-Ly2))
If d1<d2 Then Ox=Lx1:Oy=Ly1 : Return Sqr(d1) Else Ox=Lx2:Oy=Ly2:Return Sqr(d2)
End If
Var M=M1-M2:If M=0 Then M=1e-20
Ox=(C2-C1)/(M1-M2)
Oy=(M1*C2-M2*C1)/M
Return Sqr((px-Ox)*(px-Ox)+(py-Oy)*(py-Oy))
End Function
Sub rotate2d(pivotx As Double,pivoty As Double,px As Double,py As Double,a As Double,Byref rotx As Double,Byref roty As Double)',scale)
rotx=(Cos(a*.0174533)*(px-pivotx)-Sin(a*.0174533)*(py-pivoty))+pivotx
roty=(Sin(a*.0174533)*(px-pivotx)+Cos(a*.0174533)*(py-pivoty))+pivoty
End Sub
Sub GetRegressionLine(x() As Double,y() As Double,ans() As Double)
Redim ans (1 To 6)
Dim As Double mx,my
Dim As Double lx=1e9,ly=1e9,ux=-1e9,uy=-1e9
Dim As Double lastux,lastuy,lastlx,lastly
Dim As Double ix,iy 'intertcept points
Dim As Double tot,length,a
Dim As Double min=1e6,lastmin
For n As Long=Lbound(x) To Ubound(x)
mx+=x(n)
my+=y(n)
If lx>x(n) Then lx=x(n)
If ly>y(n) Then ly=y(n)
If ux<x(n) Then ux=x(n)
If uy<y(n) Then uy=y(n)
Next n
mx=mx/(Ubound(x)-Lbound(x)+1)'means
my=my/(Ubound(x)-Lbound(x)+1)
length=Sqr((ux-lx)^2+(uy-ly)^2)
lx=mx-1.5*length/2
ux=mx+1.5*length/2
ly=my
uy=my
'test rotate direction
Dim As Double tlx=lx,tly=ly,tux=ux,tuy=uy,t1,t2
For k As Long=1 To 2
rotate2d(mx,my,tlx,tly,.1,tlx,tly)
rotate2d(mx,my,tux,tuy,.1,tux,tuy)
For n As Long=Lbound(x) To Ubound(x)
Var d=segmentdistance(tlx,tly,tux,tuy,x(n),y(n),ix,iy)
If k=1 Then t1+=d
If k=2 Then t2+=d
Next n
Next k
a=.0001
If t2>t1 Then a=-.0001
Do
tot=0
'swing the lines round the mean and test the total distance of the points from the line.
rotate2d(mx,my,lx,ly,a,lx,ly)
rotate2d(mx,my,ux,uy,a,ux,uy)
For n As Long=Lbound(x) To Ubound(x)
Var d=segmentdistance(lx,ly,ux,uy,x(n),y(n),ix,iy)
tot+=d
Next n
If min>tot Then min=tot
If lastmin=min Then 'BINGO, you have passed the minimum distance
ans(1)=lastlx
ans(2)=lastly
ans(3)=lastux
ans(4)=lastuy
ans(5)=(lastuy-lastly)/(lastux-lastlx) 'gradient(M)
ans(6)=-lastlx*ans(5)+lastly 'intercept(C)
Exit Do
End If
lastmin=min
lastux=ux
lastuy=uy
lastlx=lx
lastly=ly
Loop
End Sub
Screen 20
Dim As Integer xres,yres
Screeninfo xres,yres
Dim As Long mx,my,flag,btn
Window(0,0)-(xres,yres)
Redim As Double x(),y()
Dim As Long count
start:
Do
'grid
for x as long=0 to xres step 100
line(x,0)-(x,yres),8
next x
for x as long=0 to yres step 100
line(0,x)-(xres,x),8
next x
Getmouse mx,my,,btn
Locate 4
Print "Mouse click some points on the screen, press escape when points are complete"
Locate 6
Print String(30," ")
Locate 6
Print mx;" ";yres-my
If flag=0 And btn=1 Then
count+=1
Circle(mx,yres-my),5:flag=1
Redim Preserve x(1 To count)
Redim Preserve y(1 To count)
x(count)=mx
y(count)=yres-my
End If
flag=btn
Sleep 50
Loop Until Inkey=Chr(27)
'========= get result() =====
Cls
Redim As Double result()
GetRegressionLine(x(),y(),result())
Circle(result(1),result(2)),4,5 'end points, not always on the screen.
Circle(result(3),result(4)),4,5
Line(result(1),result(2))-(result(3),result(4)) 'regression line
Dim As Double ix,iy 'intercepts
Dim As Double predictions(1 To Ubound(x))
Dim As Double sum
For n As Long=Lbound(x) To Ubound(x)
Var d=segmentdistance(result(1),result(2),result(3),result(4),x(n),y(n),ix,iy)
Circle(x(n),y(n)),5
'line(x(n),y(n))-(ix,iy),8
Circle(x(n),result(5)*x(n)+result(6)),3,3,,,,f
predictions(n)=result(5)*x(n)+result(6)
Line(x(n),y(n))-(x(n),predictions(n)),8
sum+=(y(n)-predictions(n))^2
Next n
Var sumerror=sum/(Ubound(x)-Lbound(x)+1)
Var rmse=Sqr(sumerror)
'grid
for x as long=0 to xres step 100
line(x,0)-(x,yres),8
next x
for x as long=0 to yres step 100
line(0,x)-(xres,x),8
next x
Locate 7
Print "Equation of regression line:"
Print "y = ";result(5);"*x";Iif(Sgn(result(6))=1," +","");result(6)
Locate 12
Color 3
Print "predictions"
For n As Long=1 To Ubound(predictions)
Print Csng(predictions(n));"";
Next n
Print
Print "RMSE = ";rmse
Color 15
Print " again y/n ?"
count=0
If Input(1)="y" Then Cls: Goto start
http://www.mediafire.com/file/d3tk9j0fm ... n.zip/file