2017-02-22 23 views
1

Это скриншот моих данных. data screenshotСредняя функция возвращает значение "#VALUE!"

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 

Ссылаясь на выше макрокоманды, следующие строки кода предназначены для выработки в среднем значений в колонке 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

Что является причиной этого? Каков правильный способ кодирования этой формулы?

+0

Ваша линия 'DBT (к) = Application.AverageIf (д (г, COL_FT), (д (г, COL_AOI) = "AOI запись"))' принимает среднее значение величины в ячейке расположенный в строке «r + 6», столбец R, если это значение «True» (если значение в строке «r + 6», столбец I, является «AOI Entry» или «False» (если значение в строке 'r + 6', столбец I, не является' 'AOI Entry ''). Это всегда приведет к генерации деления на нулевую ошибку (поскольку у вас нет значений «True» или «False»), поэтому это, несомненно, создает ошибку '# VALUE'. Обычно среднее значение выполняется более чем за одно значение - какие значения вы пытаетесь усреднить? – YowE3K

+0

Вы просто пытаетесь сгенерировать эквивалент VBA формулы (например, в ячейке T7): '= AVERAGEIFS ($ R: $ R, $ I: $ I," AOI Entry ", $ B: $ B, $ B7 , $ C: $ C, $ C7) '? – YowE3K

+0

@ YowE3K Я хочу, чтобы среднее значение было в столбце R, но только те, которые находятся в строках, которые имеют «запись AOI» в столбце I. Вы говорите, что проблема связана с тем, как я определил критерий включения? – shecodes

ответ

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), попытки функции для деления суммы совпадающих значений (т. е. 0) на количество совпадающих значений (т. е. 0) и ошибок.

Точно так же, когда r является 2, код приравнивает к

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

или

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

Опять же, 31 не равна True, и вы в конечном итоге пытается разделить 0 на 0.


Вы бы получили ответ (alt поджилки не содержательный ответ), если бы вы использовали формулу

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) не был "AOI Entry", и дал бы бессмысленный ответ в тех случаях, когда он действительно работал ,


Чтобы получить осмысленное среднее значение, вам нужно разделить сумму значений на количество значений. Ваш код не настроен таким образом, чтобы упростить использование встроенных функций Excel для вычисления суммы и подсчета, поэтому вам нужно будет рассчитать сумму и подсчитать себя.

В следующем коде я добавил два словаря (один из которых называется Sums, а другой - Cnts), чтобы отслеживать эти числа. Затем среднее значение можно легко получить, разделив Sums(k) на Cnts(k).

Я также взял на себя смелость изменить вашу переменную k как массив. Ваш текущий код вычислял ключ не менее чем в 8 позициях, поэтому я изменил его, чтобы вычислить его один раз, а затем использовать одно и то же значение в каждой другой позиции.

Dim dBT As Object 'global dictionary 

Sub buttonpresscount() 
    Dim Sums As Object 
    Dim Cnts As Object 

    '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, resBT() 
    Dim k() As String 

    Set sht = Worksheets("full test") 
    lastrow = sht.Cells(Rows.Count, 3).End(xlUp).Row 
    Set dBT = CreateObject("scripting.dictionary") 
    Set Sums = CreateObject("scripting.dictionary") 
    Set Cnts = 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 
    ReDim k(1 To UBound(d, 1)) As String 

    'get unique combinations of Block and Trial and pressedcounts for each 
    For r = 1 To UBound(d, 1) 
     'Calculate the key once, then it can be used in every other loop 
     k(r) = d(r, COL_BLOCK) & "|" & d(r, COL_TRIAL) 'create key 
     dBT(k(r)) = dBT(k(r)) + IIf(d(r, COL_ACT) <> "", 1, 0) 
    Next r 

    'populate array with appropriate counts for each row 
    For r = 1 To UBound(d, 1) 
     resBT(r, 1) = dBT(k(r))  '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) 
     If resBT(r, 1) = 1 Then 'only proceed with trials with 1 button press 
      If d(r, COL_AOI) = "AOI Entry" Then 
       dBT(k(r)) = dBT(k(r)) + 1  'get count 
       Cnts(k(r)) = Cnts(k(r)) + 1 'get count 
       Sums(k(r)) = Sums(k(r)) + d(r, COL_FT) 'sum column R 
      End If 
     Else 
      dBT(k(r)) = "" 
     End If 
    Next r 

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

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

    createsummarytable 
    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 
      dBT(k(r)) = 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) 
     resBT(r, 1) = dBT(k(r))   'get the count 
    Next r 

    PopSummaryRT dBT 

    dBT.RemoveAll 

    'work out avg fixation time per trial 
    For r = 1 To UBound(d, 1) 
     If resBT(r, 1) <> "" Then 
      If Cnts(k(r)) < 1 Then 
       'Error if no results 
       dBT(k(r)) = CVErr(xlErrDiv0) 
      Else 
       'Determine average 
       dBT(k(r)) = Sums(k(r))/Cnts(k(r)) 
      End If 
     End If 
    Next r 

    'populate array 
    For r = 1 To UBound(d, 1) 
     resBT(r, 1) = dBT(k(r))   'get the count 
    Next r 

    PopSummaryFT dBT 

End Sub 
+0

Отличный ответ, и код работает. За исключением того, что я хочу, чтобы он все еще печатал 0, если нет записей AOI, поэтому я изменил 'Если d (r, COL_AOI) =" AOI Entry "Затем dBT (k (r)) = dBT (k (r)) + 1 'получить счет Cnts (k (r)) = Cnts (k (r)) + 1' получить счет Суммы (k (r)) = Суммы (k (r)) + d (r, COL_FT) «сумма столбца R» до 'Если d (r, COL_AOI) =« AOI Entry »Затем dBT (k (r)) = dBT (k (r)) + 1 'получить счет Else dBT (k (r)) = dBT (k (r)) + 0 'получить count' , и теперь многие средние значения являются отрицательными числами. Не знаю, почему. – shecodes

+0

nvm Думаю, я исправил это. Я положил выражение else для среднего значения '' Else 'Cnts (k (r)) = Cnts (k (r)) + 0' получить счет 'Суммы (k (r)) = Суммы (k (r)) + d (r, COL_FT) 'сумма столбца R' , который, я думаю, был причиной. Без него все работает. – shecodes

Смежные вопросы