I have an unsorted column of numbers and each number has an associated probability. I need to sort the numbers and then average the n lowest values. n is determined by starting at the lowest number and then proceeding up the list until the sum of the associated probabilities reaches some desired threshhold (i.e. 25%). I’ve got a function that works and I’m just wanting to see if anyone can help make this more efficient since this function does quite a few loops and it is expected to be used many times in a workbook:
Option Explicit Option Base 1 Function CTE(Level, Values As Object, Optional Max0 = False, _ Optional Probabilities As Object, Optional Smallest = 1) ' Computes Conditional Tail Expectation from the specified ' percentage (i.e. 1-Level) of Values ' ' If the specified number of Values is non-integer, it will linearly interpolate ' between the CTEs given by the two integer number of Values ' ' If Max0=TRUE, any Values greater than 0 will be set to 0 ' If Smallest=1, it will compute the average of the smallest Values ' If Smallest1, it will compute the average of the largest Values ' ' Created by DC 9/23/2003 ' *7/15/2004 Modified to handle duplicate values. Prior version did not do this properly. ' Also modified to require explicit declaration of variable types. Also modified to ' normalize Probabilities so they sum to 1.00 ' If Level > 1 Or Level < 0 Then CTE = CVErr(xlValue) Exit Function End If Dim SortedValues(), SortedProbs(), SumProbs As Double Dim PriorProb, NewProb, PriorTotal, NewTotal, CTE1, CTE2 As Double Dim i, j, k, N, R As Long N = Values.Count ReDim SortedValues(1 To N), SortedProbs(1 To N) SumProbs = 0 For i = 1 To N R = Application.Rank(Values(i), Values) Do While Not (IsEmpty(SortedValues®)) R = R + 1 Loop If Max0 Then SortedValues® = Application.Min(0, Values(i)) Else SortedValues® = Values(i) End If If IsArray(Probabilities) Then SortedProbs® = Probabilities(i) Else SortedProbs® = 1 / N End If SumProbs = SumProbs + SortedProbs® Next i For i = 1 To N If IsEmpty(SortedProbs(i)) Then CTE = CVErr(xlValue) Exit Function End If SortedProbs(i) = SortedProbs(i) / SumProbs Next i If Smallest = 1 Then j = N + 1: k = -1 Else j = 0: k = 1 End If NewTotal = 0: NewProb = 0: CTE1 = 0: CTE2 = 0 Do While NewProb < (1 - Level) PriorTotal = NewTotal PriorProb = NewProb j = j + k NewTotal = NewTotal + SortedProbs(j) * SortedValues(j) NewProb = NewProb + SortedProbs(j) Loop CTE1 = PriorTotal / PriorProb CTE2 = NewTotal / NewProb CTE = CTE1 + (CTE2 - CTE1) * ((1 - Level) - PriorProb) / (NewProb - PriorProb) End Function