Excel 如何将LinEst函数应用于行?

Excel 如何将LinEst函数应用于行?,excel,vba,Excel,Vba,多年来,我一直在使用WorksheetFunction.LinEst进行二次回归,没有遇到任何问题。我的数据始终存储在Excel工作表的列中 现在我收到的数据是行,而不是列。我对WorksheetFunction.LinEst的调用失败。 如果我在工作表中处理与公式相同的命令,则该命令有效 我没有转换数据的选项。我使用的是最新版本的Windows 10和Microsoft Office 365 我在这里找不到任何用VBA编写的、数据存储成行的示例 这是我调用以执行回归的子程序的干净副本。我已删除

多年来,我一直在使用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
最后,这里是我的例程的完整版本以及调试和验证代码。仅供参考(请不要批评):

Sub-getpolynomialregressioncoverties(Xs作为Excel.Range,Ys作为Excel.Range,ByRef x1作为Double,ByRef x2作为Double,ByRef x3作为Double)
'
'计算存储在Xs和Ys范围内的数据的最佳拟合系数
'
Dim rgCoeff’这将是一个为最佳拟合二次曲线计算的系数的可变数组
#如果RELEASE=0,则
Dim iRow As Long“仅用于调试目的。
Dim iCol作为“长”仅用于调试目的。
'
'确认范围大小相同。
'
如果是(Xs.Rows.Count Ys.Rows.Count)和(Xs.Columns.Count Ys.Columns.Count),则停止
'
'确认范围中的所有数据都是数字,而不是空白
'
对于iRow=1到Ys.Rows.Count
对于iCol=1到Xs.Columns.Count
如果IsNumeric(Xs.Cells(iRow,iCol))=False或IsNumeric(Ys.Cells(iRow,iCol))=False或Trim(Xs.Cells(iRow,iCol))=“”或Trim(Ys.Cells(iRow,iCol))=“”则停止
下一个iCol
下一步
多芬特
#如果结束
rgCoeff=Application.WorksheetFunction.LinEst(Ys,Application.Power(Xs,数组(1,2)))
x1=rgCoeff(1)
x2=rgCoeff(2)
x3=rgCoeff(3)
端接头

TLDR:对于行中的数据,您需要使用
数组(数组(1),数组(2))
而不是
数组(1,2)


问题不在于
工作表函数.LinEst
函数,而在于
应用程序.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
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(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
    XsArray = Application.Power(Xs, Array(1, 2))

    rgCoeff = Application.WorksheetFunction.LinEst(Ys, XsArray)
    
    x1 = rgCoeff(1)
    x2 = rgCoeff(2)
    x3 = rgCoeff(3)
End Sub
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))
返回一个参差不齐的数组,但据我所知,由于它需要两个索引来返回一个元素,VBA将类似地将其解释为二维数组,这些索引将被视为(列)矩阵的坐标:(0,0)和(1,0)

或者

如果不喜欢锯齿状阵列,则始终可以创建带有循环的真实二维阵列:

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

谢谢QHarr,我看到了你的评论,虽然它告诉我它被删除了。我不确定我是否理解你的意图。你是说如果我把数据放在行中,而不是列中,我必须使用你描述的方法吗?当数据在列中时,我当前的方法非常有效。我只是不明白为什么同样的方法不能在行中工作。一个更好的解释出现了。但是看起来,就像我删除的消息一样,数组(1,2)需要更改。天哪,你的答案很完美,我已经确认了好几次了。多亏了您的洞察力,我将发布我的例程的更新版本,无论是行还是列都能正常工作@SixSigmaGuy–我很高兴这对我很有帮助!顺便说一句,我没有直接引用它,但我个人使用了一个带有条件的if语句
Xs.Rows.Count>Xs.Columns.Count
,以检查它是一行还是一列(以防有用)。而且,听起来我的回答解决了你的问题,但你还没有接受。我有什么遗漏吗?关于接受它。对不起,我想是的。我有now@SixSigmaGuy–无需担心额外的编辑内容。谢谢