I have this loop to take groups of 4 cells in one worksheet and average them into another worksheet. When the one line reads z = z+3 it runs, but if I change it to z = z+4 it doesn't (Runtime error 1004 Unable to get the Average property of the WorksheetFunction class). Why is this?
Dim summary As Worksheet
Set summary = ThisWorkbook.Sheets("Sheet3")
Dim cost As Worksheet
Set cost = ThisWorkbook.Sheets("Sheet4")
Dim y As Integer
Dim z As Integer
z = 2
For y = 2 To 17
cost.Cells(y, 3) = Round(Application.WorksheetFunction.Average(Range(summary.Cells(4, z), summary.Cells(4, (z + 3)))), 0)
z = z + 4
Next y
If you run your routine with z=z+3, then the final (where y=17) area averaged is $AX$4:$BA$4
However, if with z=z+4, all those extra cells mean the final area averaged is $BN$4:$BQ$4.
As you've stated in your comments that your data only extends to $AX$4, once y reaches 14 all of the cells being averaged are empty, and the function fails.
Related
Sub CalculateWFR()
'select 1st sheet
Worksheets(1).Activate
'select range A:W
Worksheets(1).Cells.Select
Columns("A:W").Select
'copy paste sheet programare in results
Sheets("Programare").Range("A:W").Copy Destination:=Sheets("Result").Range("A:W")
'compare values from column U with column V and put +/-/= if value from U2 is higher,smaller or equals value from column V2
Dim X As Integer Dim y As Integer
X = Worksheets("Result").Range("U2").Value
y = Worksheets("Result").Range("V2").Value
If X > y Then
Worksheets("Result").Range("X2") = "+"
ElseIf X < y Then
Worksheets("Result").Range("X2") = "-"
ElseIf X = y Then
Worksheets("Result").Range("X2") = "="
End If
End Sub
I am trying to loop the above code on column X, which has over 1000 Rows. Also there are no blank spaces. How can I do this?
As #Zerk suggested try to figure out how this works.
Looping and Selecting is not required at all.
Try to think this as you were to put formula in column X and then google how to put that formula through VBA.
Sub test()
Sheets("Programare").Range("A:W").Copy Destination:=Sheets("Result").Range("A:W")
Sheets("Result").Range("X2:X1000").Formula = "=IF(U2>V2,""+"",IF(V2>U2,""-"",IF(U2=V2,""="","""")))"
End Sub
I am new to VBA and I wanted to make a code that counts some values from one sheet and writes the results to another one. It counts multiple columns in the sh sheet and every single resulting value should be written in a seperate column in the other sheet. The code works well for the first 2 values, but by the third value sometimes it gives me the right result but most times it just returns 0 like it dont count the column at all. Here my code:
Function counter()
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("some_sheet")
Dim k As Long
Dim l As Long
k = sh.Range("A1048576").End(xlUp).Row
h = k - 1
l = Application.WorksheetFunction.CountIf(Range("C1:C"&h), "Word")
Sheets("other_sheet").Cells(1, 1) = sh.Name
Sheets("other_sheet").Cells(1, 2) = h
Sheets("other_sheet").Cells(1, 3) = l
End Function
I have a 1x1 array from the following:
Dim wbottom As Variant
wbottom = WorksheetFunction.MMult(WorksheetFunction.transpose(e), wtop)
I'm trying to get the number in the array. wbottom(0,0) and wbottom(1,1) give "subscript out of range". ReDim-ming gives nothing when I try to print out the number with MsgBox. How do I fix this?
If the resulting matrix is 1x1, the resulting array is 1-dimensional, with the only valid subscript being 1. See below, where A1:E1 and A3:A7 contain values for a 1x5 and 5x1 matrix respectively (so that the multiplication results in a 1x1 matrix):
Sub mmultTest()
Dim v As Variant
v = WorksheetFunction.MMult(Range("A1:E1"), Range("A3:A7"))
Debug.Print LBound(v)
Debug.Print UBound(v)
Debug.Print v(1)
End Sub
The output is as follows:
1
1
55
You could try
wbottom = WorksheetFunction.SumProduct(e, wtop)
Transposing a column into a row and then multiplying it by a column to get a 1x1 matrix gives you a 1x1 matrix whose sole element is the dot-product of the two columns. The function SumProduct is the dot product already, and doesn't require transposing and then unpacking the value.
To test this, I set up a worksheet to look like
A B
------
1 4
2 5
3 6
then ran the following code:
Sub test()
Dim A As Range, B As Range, product As Variant
Set A = Range("A1:A3")
Set B = Range("B1:B3")
With Application.WorksheetFunction
product = .MMult(.Transpose(A), B) 'what you have
Debug.Print TypeName(product)
Debug.Print product(1)
product = .SumProduct(A, B)
Debug.Print TypeName(product)
Debug.Print product
End With
End Sub
with the resulting output:
Variant()
32
Double
32
I am attempting to replicate a function for WLS (Weighted Least Squares) that I have found in a textbook in excel. There is a value error coming up and I think that I am doing something wrong in using the function.
The following is the VBA code for a supporting function Diag(w) and the function itself WLSregress():
Function Diag(W) As Variant
Dim n, i, j, k As Integer
Dim temp As Variant
n = W.Count
ReDim temp(n, n)
For i = 1 To n
For j = 1 To n
If j = i Then temp(i, j) = W(i) Else temp(i, j) = 0
Next j
Next i
Diag = temp
End Function
Function WLSregress(y As Variant, X As Variant, W As Variant) As Variant
Wmat = Diag(W)
n = W.Count
Dim Xtrans, Xw, XwX, XwXinv, Xwy As Variant
Dim m1, m2, m3, m4 As Variant
Dim output() As Variant
Xtrans = Application.Tranpose(X)
Xw = Application.MMult(Xtrans, Wmat)
XwX = Application.MMult(Xw, X)
XwXinv = Application.MInverse(XwX)
Xwy = Application.MMult(Xw, y)
b = Application.MMult(XwXinv, Xwy)
k = Application.Count(b)
ReDim output(k) As Variant
For bcnt = 1 To k
output(bcnt) = b(bcnt, 1)
Next bcnt
WLSregress = Application.Transpose(output)
End Function
This function should return the WLS estimator for the explanatory variables of equation being estimated. I understand the code leading up to the k = Application.Count(b) line but not too sure how the output bit is working.
If anyone could help me figure out why this isn't working I would be very grateful.
The following is an example image of the function trying to work.
By default, Excel will start sizing its arrays with 0 if you don't indicate otherwise. For example,
Redim arr(2,2)
will actually give you a 3 x 3 array
0 1 2
0 blank | blank | blank
1 blank | blank | blank
2 blank | blank | blank
Because of this, when you have ReDim temp(n, n), you're actually creating an array with one more row and column than you actually want. In your example, you would expect the Dialog for A3:18 to be a 16 x 16 dialog, but it will actually create a 17 x 17 dialog, throwing off your matrix multiplications (i.e. Application.MMult)
Replace this line
ReDim temp(n, n)
With this line
ReDim temp(1 to n, 1 to n)
And you should now get results returned. Up to you to determine whether the result is accurate or not.
How do I write a VBA Macro that would take the power of a matrix (to an arbitrary user-specified power) that is located in cells A1 to C3?
Taking your question literally in the mathematical sense, this macro raises the matrix to a power (4 in the example) by repeatedly calling Excel's MMULT function.
Dim i As Long
Dim pow As Long
Dim vIn As Variant
Dim vOut As Variant
pow = 4 ' or whatever
' Fetch matrix from sheet
vIn = Range("A1:C3")
' Raise to power
vOut = vIn
For i = 1 To pow - 1
vOut = WorksheetFunction.MMult(vOut, vIn)
Next i
' Write result to sheet
Range("E1:G3") = vOut
I used the function below. Please note that, when the exponent is 0, the function returns the identity matrix, otherwise the matrix multiplied by itself the exponent number of times.
'Raises matrix to a power
Function PowerMatrixNew(rngInp As Range, lngPow As Integer) As Variant()
'create identitu for power 0
Dim identity() As Variant
ReDim identity(rngInp.Rows.Count, rngInp.Rows.Count)
Dim i As Integer
Dim j As Integer
For i = 1 To rngInp.Rows.Count
For j = 1 To rngInp.Rows.Count
If (i = j) Then
identity(i, j) = 1
Else
identity(i, j) = 0
End If
Next j
Next i
PowerMatrixNew = identity
For i = 1 To lngPow
PowerMatrixNew = Application.WorksheetFunction.MMult(rngInp, PowerMatrixNew)
Next
End Function
There was a question like this some years ago which I remember because it was called matrix arithmetic but not as I was taught at school.
Fill cells A1:C3 with the numbers 1 to 9. Set cell A5 to 2. Select cells A7:C9 and type
=power(A1:C3,A5) ctrl+shift+enter
and cells A7:C9 will be set to the squares of the values in A1:C3. Change A5 to 3 and cells A7:C9 will be set to the cubes of the values in A1:C3.
The equivalent in VBA is:
Range("a7:c9").FormulaArray = "=Power(a1:c3, a5)"