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!
被打印在相关单元格中,而不是预期的数字。
造成这种情况的原因是什么?编码这个公式的正确方法是什么?
答案 0 :(得分:1)
您当前的问题
dBT(k) = Application.AverageIf(d(r, COL_FT), (d(r, COL_AOI) = "AOI Entry"))
是因为您尝试获取单个值的平均值,并且仅当该值为True
或False
时。例如。当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