AverageIf函数导致" #VALUE!"

时间:2017-02-22 06:38:10

标签: excel vba average

这是我的数据的屏幕截图。data screenshot

Dim dBT As Object 'global dictionary

Sub buttonpresscount()

    'constants for column positions
    Const COL_BLOCK As Long = 1
    Const COL_TRIAL As Long = 2
    Const COL_ACT As Long = 7
    Const COL_AOI As Long = 8
    Const COL_RT As Long = 16
    Const COL_FT As Long = 17

    Dim rng As Range, lastrow As Long, sht As Worksheet
    Dim d, r As Long, k, resBT()

    Set sht = Worksheets("full test")
    lastrow = sht.Cells(Rows.Count, 3).End(xlUp).Row
    Set dBT = CreateObject("scripting.dictionary")

    Set rng = sht.Range("B7:T" & lastrow)

    d = rng.Value  'get the data into an array

    ReDim resBT(1 To UBound(d), 1 To 1) 'resize the array which will
                                        '  be placed in ColT

    'get unique combinations of Block and Trial and pressedcounts for each
    For r = 1 To UBound(d, 1)
        k = d(r, COL_BLOCK) & "|" & d(r, COL_TRIAL) 'create key
        dBT(k) = dBT(k) + IIf(d(r, COL_ACT) <> "", 1, 0)
    Next r

    'populate array with appropriate counts for each row
    For r = 1 To UBound(d, 1)
        k = d(r, 1) & "|" & d(r, 2)   'create key
        resBT(r, 1) = dBT(k)         'get the count
    Next r

    'place array to sheet
    sht.Range("T7").Resize(UBound(resBT, 1), 1) = resBT

    'clear dictionary
    dBT.RemoveAll

'count AOI entries
 For r = 1 To UBound(d, 1)
        k = d(r, COL_BLOCK) & "|" & d(r, COL_TRIAL) 'create key
        If resBT(r, 1) = 1 Then    'only proceed with trials with 1 button press
        dBT(k) = dBT(k) + IIf(d(r, COL_AOI) = "AOI Entry", 1, 0)    'get count
        Else: dBT(k) = ""
        End If
    Next r

    'populate array with appropriate counts for each row
    For r = 1 To UBound(d, 1)
        k = d(r, 1) & "|" & d(r, 2)   'create key
        resBT(r, 1) = dBT(k)          'get the count
    Next r

    'place array to sheet
    sht.Range("U7").Resize(UBound(resBT, 1), 1) = resBT

Call createsummarytable
Call PopSummaryAOI(dBT)

dBT.RemoveAll

'retrieve and print reaction times to data summary sheet
   For r = 1 To UBound(d, 1)
        If resBT(r, 1) <> "" Then 'if buttonpresscount = 1 and AOI count exists
        k = d(r, COL_BLOCK) & "|" & d(r, COL_TRIAL) 'create key
        dBT(k) = d(r, COL_RT)
        End If
    Next r

 'Populate array with last row reaction time for each trial
    For r = 1 To UBound(d, 1)
        k = d(r, 1) & "|" & d(r, 2)   'create key
        resBT(r, 1) = dBT(k)          'get the count
    Next r

Call PopSummaryRT(dBT)

dBT.RemoveAll

'work out avg fixation time per trial
For r = 1 To UBound(d, 1)
    If resBT(r, 1) <> "" Then
    k = d(r, COL_BLOCK) & "|" & d(r, COL_TRIAL) 'create key
    dBT(k) = Application.AverageIf(d(r, COL_FT), (d(r, COL_AOI) = "AOI Entry"))
    End If
Next r

'populate array
For r = 1 To UBound(d, 1)
        k = d(r, 1) & "|" & d(r, 2)   'create key
        resBT(r, 1) = dBT(k)          'get the count
Next r

Call PopSummaryFT(dBT)

End Sub

参考上面的宏,下面的代码行用于计算每个dict(键)R列中的平均值(读取:每次试验):

For r = 1 To UBound(d, 1)
    If resBT(r, 1) <> "" Then
    k = d(r, COL_BLOCK) & "|" & d(r, COL_TRIAL) 'create key
    dBT(k) = Application.AverageIf(d(r, COL_FT), (d(r, COL_AOI) = "AOI Entry"))
    End If
Next r

这导致#VALUE!被打印在相关单元格中,而不是预期的数字。

截图: enter image description here

造成这种情况的原因是什么?编码这个公式的正确方法是什么?

1 个答案:

答案 0 :(得分:1)

您当前的问题

dBT(k) = Application.AverageIf(d(r, COL_FT), (d(r, COL_AOI) = "AOI Entry"))

是因为您尝试获取单个值的平均值,并且仅当该值为TrueFalse时。例如。当r为1时,您的代码等同于

dbt("Block 1|Trial, 8") = Application.AverageIf(-2484, ("" = "AOI Entry"))

dbt("Block 1|Trial, 8") = Application.AverageIf(-2484, False)

由于平均范围内的值(即值-2484)都不符合条件(即False),因此函数会尝试除以匹配值的总和(即{{1} })匹配值的计数(即0)和错误输出。

同样,当0为2时,代码等于

r

dbt("Block 1|Trial, 1") = Application.AverageIf(31, ("AOI Entry" = "AOI Entry"))

同样,dbt("Block 1|Trial, 1") = Application.AverageIf(31, True) 不等于31,您最终会尝试将0除以0。

如果你使用了公式

,你会得到答案(虽然不是一个有意义的答案)
True

如果dBT(k) = Application.AverageIf(d(r, COL_AOI), "AOI Entry", d(r, COL_FT)) (根据标准测试的范围)与d(r, COL_FT)(标准)匹配,则会将d(r, COL_AOI)(平均范围)相加。 (总结一个数字有点无意义,但它仍然会完成它。)但是,当AOI Entry"不是d(r, COL_AOI)时,这仍然会给出零除错误,并且会给出一个无意义的在它确实有效的情况下回答。

要获得有意义的平均值,您需要将值的总和除以值的计数。您的代码设置方式不容易使用Excel的内置函数来计算总和和计数,因此您需要自己计算总和和计数。

在下面的代码中,我添加了两个词典(一个名为"AOI Entry",另一个名为Sums)以跟踪这些数字。然后,可以通过将Cnts除以Sums(k)来轻松获得平均值。

我也冒昧地将变量Cnts(k)更改为数组。您当前的代码是在至少8个位置计算密钥,因此我将其更改为计算一次,然后在每个其他位置使用相同的值。

k