Looking at this again the formula I used (Angus Deaton, 1997) includes a
built-in bias correction factor of N/(N-1) that accounts for the different
results. Your original formula does indeed work for small amounts of data,
but excludes the bias correction factor.
For large datasets you really need a more efficient method: try this UDF
which calculates very fast on substantial data volumes.
Function GiniCoef(InputRange As Range, _
Optional Sorted As Long = 0, Optional BiasCorrect As
Boolean = True) As Variant
'
' Fast Calculation of Gini Coefficent
'
' Using formula by Angus Deaton (Princeton 1997):
' Gini=(N+1)/(N+2)-2/(N*(N-1)*Average(X))*SUM(P(i)*X(i))
' where:
' N= number of rows in the InputRange
' X= the set of values in the inputrange (must be >=0)
' X(i) is the i'th item in InputRange
' P(i) is the rank of X(i) (1=largest value)
'
' Data can be sorted Ascending (-1), Unsorted (0), or sorted Descending (1)
' the Default is unsorted
'
' The Deaton formula contains a Bias correction factor,
' which can be undone if BiasCorrect=False
'
' Charles Williams 2 Jan 2009
'
Dim InputValues As Variant
Dim j As Long
Dim jRank As Long
Dim dObs As Double
Dim dGini As Double
On Error GoTo Fail
InputValues = InputRange.Value2
dObs = UBound(InputValues)
If Sorted = 0 Then QSort InputValues, 1, CLng(dObs)
For j = 1 To dObs
If Sorted = 1 Then
jRank = j
Else
jRank = dObs - j + 1
End If
dGini = dGini + InputValues(j, 1) * jRank
Next j
GiniCoef = (dObs + 1) / (dObs - 1) - dGini * 2# / (dObs * (dObs - 1) * _
Application.WorksheetFunction.Average(InputRange))
If Not BiasCorrect Then GiniCoef = GiniCoef * (dObs - 1) / dObs
Exit Function
Fail:
GiniCoef = CVErr(xlErrValue)
End Function
Sub QSort(InputValues As Variant, jStart As Long, jEnd As Long)
Dim jStart2 As Long
Dim jEnd2 As Long
Dim v1 As Variant
Dim v2 As Variant
jStart2 = jStart
jEnd2 = jEnd
v1 = InputValues((jStart + jEnd) \ 2, 1)
While jStart2 < jEnd2
While InputValues(jStart2, 1) < v1 And jStart2 < jEnd
jStart2 = jStart2 + 1
Wend
While InputValues(jEnd2, 1) > v1 And jEnd2 > jStart
jEnd2 = jEnd2 - 1
Wend
If jStart2 < jEnd2 Then
v2 = InputValues(jStart2, 1)
InputValues(jStart2, 1) = InputValues(jEnd2, 1)
InputValues(jEnd2, 1) = v2
End If
If jStart2 <= jEnd2 Then
jStart2 = jStart2 + 1
jEnd2 = jEnd2 - 1
End If
Wend
If jEnd2 > jStart Then QSort InputValues, jStart, jEnd2
If jStart2 < jEnd Then QSort InputValues, jStart2, jEnd
End Sub