I'm am trying to optimize a sub that uses Excel´s sumif function since it takes several time to finish.
The specific line (contained in to a for loop) is this one:
Cupones = Application.WorksheetFunction.SumIf(Range("Test_FecFinCup"), Arr_FecFlujos(i), Range("Test_MtoCup"))
Where the ranges are named ranges in the workbook, and Arr_FecFlujos() is an array of dates
That, code works fine, except for it takes to much time to finish.
I am trying this two approaches
Arrays:
Declare my arrays
With Test
Fluj = .Range(Range("Test_Emision").Cells(2, 1), Range("Test_Emision").Cells(2, 1).End(xlDown)).Rows.Count
Arr_FecFinCup = .Range("Test_FecFinCup")
Arr_MtoCup = .Range("Test_MtoCup")
End With
Cupones = Application.WorksheetFunction.SumIf(Arr_FecFinCup, Arr_FecFlujos(i), Arr_MtoCup)
Error tells me I need to work with Range Objects, so I changed to:
With Test
Set Rango1 = .Range("Test_FecIniCup")
Set Rango2 = .Range("Test_MtoCup")
End With
Cupones = Application.WorksheetFunction.SumIf(Rango1, Arr_FecFlujos(i), Rango2)
That one, doesn't shows any error messages, but the sum is incorrect.
Can anybody tell me what's working wrong with these methods and perhaps point me in the correct direction?
It seems that you try to sum a range of numbers using a range of criteria:
WorksheetFunction.SumIf(Arr_FecFinCup, Arr_FecFlujos(i), Arr_MtoCup)
As i know, if the criteria parameter is given a range, Excel don't iterate over that range but instead look for the one value in the criteria_range that coincides with the row of the cell that it is calculating.
For example
Range("D3") = WorksheetFunction.SumIf(Range("A1:A10"),Range("B1:B10"))
Excel will actually calculate as follow
Range("D3") = WorksheetFunction.SumIf(Range("A1:A10"),Range("B3"))
If there is no coincident, then the return is 0
For example
Range("D7") = WorksheetFunction.SumIf(Range("A1:A10"),Range("B1:B5"))
Then D7 is always 0 because looking for [B7] in [B1:B5] is out of range.
Therefore, to do a sum with multiple criterias, the correct way is using SUMIFS as suggested by #mrtiq.
Related
I have an existing .py file that prints a classifier.predict for a SVC model. I would like to loop through each row in the X feature set to return a prediction.
I am currently trying to define the element from which to iterate over so as to allow for definition of the test statistic feature set X.
The test statistic feature set X is written in code as:
X_1 = xspace.iloc[testval-1:testval, 0:5]
testval is the element name used in the for loop in the above line:
for testval in X.T.iterrows():
print(testval)
I am having trouble returning a basic set of index values for X (X is the pandas dataframe)
I have tested the following with no success.
for index in X.T.iterrows():
print(index)
for index in X.T.iteritems():
print(index)
I am looking for the set of index values, with base 1 if possible, like 1,2,3,4,5,6,7,8,9,10...n
seemingly simple stuff...i haven't located an existing question via stackoverflow or google.
ALSO, the individual dataframes I used as the basis for X were refined with the line:
df1.set_index('Date', inplace = True)
Because dates were used as the basis for the concatenation of the individual dataframes the loops as written above are returning date values rather than
location values as I would prefer hence:
X_1 = xspace.iloc[testval-1:testval, 0:5]
where iloc, location is noted
please ask for additional code if you'd like to see more
the loops i've done thus far are returning date values, I would like to return index values of the location of the rows to accommodate the line:
X_1 = xspace.iloc[testval-1:testval, 0:5]
The loop structure below seems to be working for my application.
i = 1
j = list(range(1, len(X),1)
for i in j:
Excel's FORECAST functions take a 1-dimensional array for both the 'known Xs' argument and the 'known Ys' argument, and then returns a single value as the answer.
I'd like to use a 2-dimensional array for the 'known Ys' argument, and return an array (1-dimensional) as the answer.
In other words, I want to return a set (array) of forecasts that correspond to a set (array) of Y-values, covering the same time-scale (X-values).
(There's a reason I need this...I need to multiply the result I get by a couple of other arrays.)
But if I take a formula that works fine, like
FORECAST.LINEAR($H$1,A2:G2,$A$1:$G$1)
and then change the 1-dimensional array to 2-dimensional (G7 instead of G2):
FORECAST.LINEAR($H$1,A2:G7,$A$1:$G$1)
and press Ctrl+Alt+Enter, I get an error (#N/A).
Same with the TREND function.
I know some Excel functions don't like taking an array as an argument--though sometimes there are ways around this (like here: Can Excel's INDEX function return array?). But I can't figure out if it's possible to 'dereference' things in my situation...I certainly haven't managed to incorporate this approach here.
Addendum in response to comment: The data below are representative (though the real data have a lot more rows and columns!). The top row represents the 'known X's (this is a time scale) and the subsequent rows are the data. The result I want to end up with is an array representing the forecasted Y-value corresponding to X=8...here, I believe that would be
11.71; 14.43; 177.71; 25.71; 16.71; 10.86;
So here is an attempt, I'm still not sure what you are after, but let me try.
I've went the UDF way and my assumption is that you feed the function with a range that has as many rows as columns.
Function GetResult(RNG1 As Range, RNG2 As Range) As Double
Dim X As Double, RNG3 As Range, ARR() As Variant
ReDim ARR(RNG2.Rows.Count - 1)
For X = 1 To RNG2.Rows.Count
Set RNG3 = Application.Intersect(RNG2, Rows(X + 1))
ARR(X - 1) = Application.WorksheetFunction.Forecast(RNG2.Columns.Count + 1, RNG3, RNG1)
Next X
GetResult = Application.WorksheetFunction.Forecast(RNG2.Columns.Count + 1, ARR, RNG1.Value)
End Function
On the sample data you give (with the extraction of column 7), it would look like this:
The function will create a forecast for each line and stores it in an 1-dimensional array. Then it will use all these forecasts to create a final forecast.
Is this close to what you expect?
I did research this question but could not find the specific answer I was looking for and am actually even more confused at present.
I created a macro that would run through rows on a sheet and run boolean checks on a number of cells in each row that looked for the presence or absence of specific values, or calculated the outcome of a specific inequality. On the basis of those checks, the macro may or may not pass the row number into a specific array. That part is working fine.
My issue is, now that I have the row numbers (stored in variant arrays) - I cannot figure out how to properly concatenate that data into a range and then take a bulk excel action on those items. What I'd like to do is create a range of those values and then delete all of those rows at once rather than looping through.
My macro is on my work computer, but here's something I wrote that should explain what I'm trying to do:
Sub Test()
Dim Str As String
Dim r As Range
Dim i, a As Integer
Dim Count As Integer
Dim RngArray()
Count = ThisWorkbook.Sheets("Sheet1").Cells(Rows.Count, "A:A").End(xlUp).Row
ReDim RngArray(Count)
a = 0
For i = 1 To Count
If Not i = Count Then
RngArray(a) = i
Str = Str & RngArray(a) & ":" & RngArray(a) & ", "
a = a + 1
ElseIf i = Count Then
RngArray(a) = i
Str = Str & RngArray(a) & ":" & RngArray(a)
a = a + 1
Else: End If
Next i
Set r = Range(Str)'Error Can Appear here depending on my concatenation technique
Range(Str).EntireRow.Delete 'error will always appear here
End Sub
I've combined a few steps here and left out any Boolean checks; in my actual macro the values in the arrays are already stored and I loop from LBound to UBound and concatenate those values into a string of the form ("1:1, 2:2, 3:3, ...., n:n")
The reason why I did this is that the rows are all over the sheet and I wanted to get to a point where I could pass the argument
Range("1:1, 2:2, 3:3, ..., n:n").EntireRow.Delete
I think it's clear that I'm just not understanding how to pass the correct information to the range object. When I try to run this I get a "Method Range of Object Global" error message.
My short term fix is to just loop through and clear the rows and then remove all of the blank rows (the macro keeps track of absolute positions of the rows, not the rows after an iterative delete) - but I'd like to figure out HOW to do this my way and why it's not working.
I'm open to other solutions as well, but I'd like to understand what I'm doing wrong here. I should also mention that I used the Join() to try to find a workaround and still received the same type of error.
Thank you.
After some experimentation with my dataset for the macro above, I discovered that it worked on small sets of data in A:A but not larger sets.
I ran Debug.Print Len(Str) while tweaking the set size and macro and found that it appears Range() can only accept a maximum of 240 characters. I still don't understand why this is or the reason for the specific error message I received, but the macro will work if Len(Str) < 240.
I'll have to loop backwards through my array to delete these rows if I want to use my present method...or I may just try something else.
Thanks to Andrew for his attention to this!
I am trying to loop through a table in excel using VBA and store the maximum value of each column in an array variable for later use in the program.
I have taken a number of approaches similar to the code snippet below without success. For reference: mainTable is a Public ListObject variable defined earlier in the script and mainCols is a Pubic Long variable, also previously defined, which stores the width of mainTable:
Dim maxVals() As Long
ReDim maxVals(mainCols)
For x = 0 To mainCols - 1
maxVals(x) = mainTable.ListColumns(x + 1).TotalsCalculation = xlTotalsCalculationMax
Next x
The code above executes without error, but always returns 0
It is important that I don't hard code the columns/table location so that users can copy/paste a dataset of varying dimensions and run the script without errors. Also, assume that the user could run this on a dataset with whatever column headers they want.
Your code simply changes the calculation used in the Totals row of the table - it doesn't actually return the max value. You could use:
Dim maxVals() As Long
ReDim maxVals(mainCols)
For x = 0 To mainCols - 1
maxVals(x) = WorksheetFunction.Max(mainTable.ListColumns(x + 1).Range)
Next x
I am trying to pass an array to a UDF to avoid massive duplication of code. As a simple example:
function USERFUNC1(inp as variant)
Dim array_size As Integer
dim i as integer
dim values as double
array_size = WorksheetFunction.CountA(inp)
for i = 1 to array_size
values = values + inp(i)
Next i
USERFUNC1 = values
End function
function USERFUNC2(input1 as variant, input2 as variant)
Dim array_size As Integer
dim i as integer
dim values as double
array_size = WorksheetFunction.CountA(input1)
redim nested_array(array_size)
for i = 1 to array_size
nested_array(i) = input1(i)+input2(i)
Next i
USERFUNC2= USERFUNC1(nested_array)
End function
In the example I have create I have the nested array that I am passing internally to the UDF. However when run this results in a by ref error. I am sure that this can be done but I appear to be missing something
EDIT
It seems what I wrote caused confusion, essentially I have a number of functions, the above is just to demonstrate the idea.
On some of the cells I am calculating a value using a function (call it fugacity) that picks up values into an array a range from the worksheet. In another function (phase equilibrium) I need to perform the same calculation (fugacity) within the second function (phase equilibrium) using values calculated within the second function. This requires me to pass the array from the second function into the first or write out the entire first function again within the second.
I could do that however it make the 2nd function much more difficult to debug as I can no longer be certain that the nested calculation is performing the right calculation, rather I need to check the whole thing. So far I have about 250 lines of code in the first and 300 line the second and within the second (phase equilibrium) I need to perform the first (fugacity) 4 times.
If you want USERFUNC1 to return an array of the values in the inp range, then merely:
function USERFUNC1(inp as Range) as Variant
USERFUNC1 = inp
End function
This will be a 1-based two dimensional array where the first dimension represents the rows, and the second dimension the columns in the original range inp.
I'm not sure what your end goal is, but you may not even need USERFUNC1