#excel #vba #matrix #covariance
#excel #vba #матрица #ковариация
Вопрос:
Я должен уменьшить значения в матрице дисперсии-ковариации в сторону дисперсии (диагональные значения в матрице) с коэффициентом сжатия (лямбда), так что: лямбда * матрица сжатия (1-лямбда) * матрица отклонения, где:
Ковариационная матрица дисперсии равна:
Function VarCovar(rng As Range) As Variant
Dim i As Integer
Dim j As Integer
Dim numcols As Integer
numcols = rng.Columns.Count
numrows = rng.Rows.Count
Dim matrix() As Double
ReDim matrix(numcols - 1, numcols - 1)
For i = 1 To numcols
For j = 1 To numcols
matrix(i - 1, j - 1) = Application.WorksheetFunction.Covar(rng.Columns(i), rng.Columns(j)) * numrows / (numrows - 1)
Next j
Next i
VarCovar = matrix
это дает мне матрицу, которая выглядит, например, так:
0.40 -0.10 0.11
-0.10 0.17 -0.03
0.11 -0.03 0.19
Тогда у меня возникают проблемы с созданием матрицы усадки, которая должна выглядеть как:
0.40 0.00 0.00
0.00 0.17 0.00
0.00 0.00 0.19
т.е. возвращает ТОЛЬКО диагональные значения (= отклонения переменных) и ноль во всех остальных ячейках.
Таким образом, каким-то образом возвращая матрицу, содержащую только значения для when строка = номер столбца, т. Е. (1,1), (2,2) и (3,3) значения.
Кто-нибудь, кто может помочь с этим?
Комментарии:
1. не проще ли, если внутри вашего цикла у вас будет if, указывающий, что if i = <> j then .value = 0
2. @Jo.lass почему так сложно? Просто удалите
j
цикл и заменитеj
наi
.3. @Jo.lass куда бы вы поместили это выражение if в кодировке?
4. @Pernille не делайте этого, это замедлит ваш код. Я исправил свой ответ, пожалуйста, взгляните.
Ответ №1:
Вам нужен только один цикл, который отсчитывается от i = 1 to 3
заполнения Matrix(1, 1)
, Matrix(2, 2)
и Matrix(3, 3)
используя Matrix(i, i)
Function VarCovar(InputMatix As Range) As Variant
Dim MatrixColumns As Long
MatrixColumns = InputMatix.Columns.Count
Dim MatrixRows As Long
MatrixRows = InputMatix.Rows.Count
Dim Matrix() As Double
ReDim Matrix(1 To MatrixColumns, 1 To MatrixColumns)
Dim i As Long
For i = 1 To MatrixColumns
Matrix(i, i) = Application.WorksheetFunction.Covar(InputMatix.Columns(i), InputMatix.Columns(i)) * MatrixRows / (MatrixRows - 1)
Next i
VarCovar = Matrix
End Function
Обратите внимание, что я изменил Matrix
размеры Matrix(1 To MatrixDimension, 1 To MatrixDimension)
, чтобы начать с 1
и не 0
, чтобы вы могли легко использовать это для записи в ячейки:
Sub test()
Range("A5:C7").Value = VarCovar(Range("A1:C3"))
End Sub
Комментарии:
1. Спасибо за вашу помощь! У меня все еще возникают проблемы с этим (извините, я совершенно новичок в VBA и не до конца понимаю все кодирование) У меня есть эта область, скажем, A3: F27, которая возвращает значения для разных переменных (6 переменных с 24 наблюдениями в каждой). Функция, которую вы только что написали, не работает как: VarCovar(A3: F27), поскольку она приходит с сообщением «не симметричная матрица». Затем я попытался переименовать вашу функцию в «VarCovarZeros» и попробовал: VarCovarZeros (VarCovar(A3: F27)) Где VarCovar — это «моя» исходная функция. Это возвращает #VALUE! , т. е. не работает. Как я могу это изменить?
2. Мне нужно преобразовать «Необработанные данные» в матрицу, которая дает только отклонения в диагонали и нулях в другом месте, или преобразовать «мою» матрицу VarCovar в матрицу, которая имеет (1,1), (2,2), (3,3) … и т.д. Значения в ней и нули в других местах. Имеет ли это смысл?
3. @Pernille А, кажется, я понял. Я изменил свой ответ, пожалуйста, попробуйте еще раз.