多年来,我一直在使用WorksheetFunction.LinEst进行二次回归而没有问题。我的数据始终存储在Excel工作表的列中。
现在,我正在按行而不是按列发送数据。我对WorksheetFunction.LinEst的调用失败。
如果我在工作表中处理与公式相同的命令,则它会起作用。
我没有选择转置数据的选项。我正在使用Windows 10和Microsoft Office 365的最新发行版本。
我在这里找不到用VBA编写的将数据存储在行中的任何示例。
这是我用来执行回归的子例程的干净副本。我删除了所有调试代码,以使其更具可读性。
完整版本则更进一步。
在此代码之后,我编写了一些代码来演示失败。
Sub GetPolynomialRegressionCoefficients(Xs As Excel.Range, Ys As Excel.Range, ByRef x1 As Double, ByRef x2 As Double, ByRef x3 As Double)
'
' Calculates the best fit cooeficients of the the data stored in ranges Xs and Ys
'
Dim rgCoeff ' This will be a variant array of the coefficients calculated for the best fit quadratic curve
rgCoeff = Application.WorksheetFunction.LinEst(Ys, Application.Power(Xs, Array(1, 2)))
x1 = rgCoeff(1)
x2 = rgCoeff(2)
x3 = rgCoeff(3)
End Sub
接下来的代码创建一个简单的数据集,以计算y = x ^ 2函数的系数。使用相同的数据(先存储在列中,然后存储在行中),我的代码可以处理列中的数据,但不能处理行中的数据。
Sub TestGetPolynomialRegressionCoefficients()
Dim rXs As Excel.Range ' Range for the X values
Dim rYs As Excel.Range ' Range for the Y values
Dim ws As Excel.Worksheet
Dim iRow As Long
Dim iCol As Long
Dim x As Long
Dim x1 As Double
Dim x2 As Double
Dim x3 As Double
Set ws = ThisWorkbook.Worksheets("LinEstTest")
'
' Works! - Test data y = x^2 with data in columns
'
ws.Cells.Clear
For x = 0 To 9
iRow = x + 1
ws.Cells(iRow, 1) = x ' these will be the domain (the Xs)
ws.Cells(iRow, 2) = x * x ' these will be the range (the Ys)
Next x
Set rXs = ws.Range(ws.Cells(1, 1), ws.Cells(10, 1))
Set rYs = ws.Range(ws.Cells(1, 2), ws.Cells(10, 2))
On Error Resume Next
x1 = -1: x2 = -1: x3 = -1
GetPolynomialRegressionCoefficients rXs, rYs, x1, x2, x3
If Err <> 0 Then
Debug.Print "Error using Columns "; Err; " "; Err.Description
Else
Debug.Print "With data in columns, x1 = "; x1; ", x2 = "; x2; ", x3 = "; x3
End If
'
' Fails! - Test data y = x^2 with data in rows
'
ws.Cells.Clear
For x = 0 To 9
iCol = x + 1
ws.Cells(1, iCol) = x ' these will be the domain (the Xs)
ws.Cells(2, iCol) = x * x ' these will be the range (the Ys)
Next x
Set rXs = ws.Range(ws.Cells(1, 1), ws.Cells(1, 10))
Set rYs = ws.Range(ws.Cells(2, 1), ws.Cells(2, 10))
On Error Resume Next
x1 = -1: x2 = -1: x3 = -1
GetPolynomialRegressionCoefficients rXs, rYs, x1, x2, x3
'
' Get Error message dialog:
'
' Microsoft Visual Basic
' Run-time error '1004':
' Unable to get the LinEst property of the WorksheetFunction class
'
If Err <> 0 Then
Debug.Print "Error Using Rows "; Err; " "; Err.Description
Else
Debug.Print "With data in rows, x1 = "; x1; ", x2 = "; x2; ", x3 = "; x3
End If
End Sub
这是我运行测试代码时在即时窗口中得到的输出:
With data in columns, x1 = 1 , x2 = 0 , x3 = 0
Error Using Rows 1004 Unable to get the LinEst property of the WorksheetFunction class
最后,这是我的例程的完整版,其中包含调试和验证代码。仅供参考(请不要批评):
Sub GetPolynomialRegressionCoefficients(Xs As Excel.Range, Ys As Excel.Range, ByRef x1 As Double, ByRef x2 As Double, ByRef x3 As Double)
'
' Calculates the best fit cooeficients of the the data stored in ranges Xs and Ys
'
Dim rgCoeff ' This will be a variant array of the coefficients calculated for the best fit quadratic curve
#If RELEASE = 0 Then
Dim iRow As Long ' Used only for debugging purposes.
Dim iCol As Long ' Used only for debugging purposes.
'
' Confirm that the ranges are the same size.
'
If (Xs.Rows.Count <> Ys.Rows.Count) And (Xs.Columns.Count <> Ys.Columns.Count) Then Stop
'
' Confirm that all the data in the ranges is numeric and not blank
'
For iRow = 1 To Ys.Rows.Count
For iCol = 1 To Xs.Columns.Count
If IsNumeric(Xs.Cells(iRow, iCol)) = False Or IsNumeric(Ys.Cells(iRow, iCol)) = False Or Trim(Xs.Cells(iRow, iCol)) = "" Or Trim(Ys.Cells(iRow, iCol)) = "" Then Stop
Next iCol
Next iRow
DoEvents
#End If
rgCoeff = Application.WorksheetFunction.LinEst(Ys, Application.Power(Xs, Array(1, 2)))
x1 = rgCoeff(1)
x2 = rgCoeff(2)
x3 = rgCoeff(3)
End Sub
TLDR:对于行中的数据,您需要使用Array(Array(1), Array(2))
而不是Array(1, 2)
问题不是WorksheetFunction.LinEst
功能而是Application.Power
功能。要检查这一点,可以添加一个名为XsArray的中间变量,如下所示:
Sub GetPolynomialRegressionCoefficients(Xs As Excel.Range, Ys As Excel.Range, ByRef x1 As Double, ByRef x2 As Double, ByRef x3 As Double)
'
' Calculates the best fit coefficients of the data stored in ranges Xs and Ys
'
Dim rgCoeff ' This will be a variant array of the coefficients calculated for the best fit quadratic curve
Dim XsArray As Variant
XsArray = Application.Power(Xs, Array(1, 2))
rgCoeff = Application.WorksheetFunction.LinEst(Ys, XsArray)
x1 = rgCoeff(1)
x2 = rgCoeff(2)
x3 = rgCoeff(3)
End Sub
而且,如果您打开“本地窗口”(在放置断点之后),您将看到这是错误的出处:
我找不到关于此的任何现有解释,但据我了解,Power函数有点像矩阵乘法一样工作:您要么想让行矩阵乘以一列矩阵,反之亦然,您不想两行矩阵或两列矩阵。
此处的事情是Array(1,2)
VBA将其视为行矩阵,因为它是一个简单的1D数组。因此,当Xs
是“列范围”时,一切都很好,但是当它是“行范围”时,我们需要传递将被视为列矩阵的内容。实现此目的的一种方法是这样的:
Sub GetPolynomialRegressionCoefficients(Xs As Excel.Range, Ys As Excel.Range, ByRef x1 As Double, ByRef x2 As Double, ByRef x3 As Double)
'
' Calculates the best fit coefficients of the data stored in ranges Xs and Ys
'
Dim rgCoeff ' This will be a variant array of the coefficients calculated for the best fit quadratic curve
Dim XsArray As Variant
If Xs.Rows.Count > Xs.Columns.Count Then
XsArray = Application.Power(Xs, Array(1, 2))
Else
XsArray = Application.Power(Xs, Array(Array(1), Array(2)))
End If
rgCoeff = Application.WorksheetFunction.LinEst(Ys, XsArray)
x1 = rgCoeff(1)
x2 = rgCoeff(2)
x3 = rgCoeff(3)
End Sub
说明
该表达式Array(Array(1), Array(2))
返回一个锯齿状的数组,但是据我了解,由于它需要2个索引才能返回一个元素,因此VBA会将其类似地解释为2D数组,并且这些索引将被视为(列)矩阵的坐标:(0, 0)和(1,0)。
或者
如果您不喜欢锯齿状的数组,则总是可以创建一个带有循环的真实2D数组:
Dim XsArray As Variant, PowersArray As Variant
If Xs.Rows.Count > Xs.Columns.Count Then
PowersArray = Array(1, 2)
XsArray = Application.Power(Xs, PowersArray)
Else
ReDim PowersArray(0 To 1, 0)
Dim i As Integer
For i = 0 To 1
PowersArray(i, 0) = i + 1
Next i
XsArray = Application.Power(Xs, PowersArray)
End If
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句