J'utilise la fonction WorksheetFunction.LinEst pour effectuer une régression quadratique depuis des années sans aucun problème. Mes données ont toujours été stockées en colonnes dans la feuille de calcul Excel.
Maintenant, on m'envoie des données en lignes, plutôt qu'en colonnes. Mes appels à WorksheetFunction.LinEst échouent.
Si je traite la même commande comme une formule dans la feuille de travail, cela fonctionne.
Je n'ai pas la possibilité de transposer les données. J'utilise les versions les plus récentes de Windows 10 et de Microsoft Office 365.
Je n'ai pas trouvé ici d'exemples écrits en VBA où les données sont stockées en lignes.
Voici une copie propre de la sous-routine que j'appelle pour effectuer la régression. J'ai enlevé tout le code de débogage, pour le rendre plus lisible.
La version complète est plus bas.
Après ce code, il y a un code que j'ai écrit pour démontrer l'échec.
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
Le code suivant crée un jeu de données simple pour calculer les coefficients de la fonction y = x^2. En utilisant les mêmes données, d'abord stockées en colonnes, puis stockées en lignes, mon code fonctionne avec les données en colonnes, mais échoue avec les données en lignes.
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
Voici le résultat que j'obtiens dans ma fenêtre immédiate lorsque j'exécute le code de test :
With data in columns, x1 = 1 , x2 = 0 , x3 = 0
Error Using Rows 1004 Unable to get the LinEst property of the WorksheetFunction class
Enfin, voici la version complète de ma routine avec le code de débogage et de validation. Fournie à titre de référence uniquement (merci de ne pas la critiquer) :
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