2017-02-22 8 views
1

これは私のデータのスクリーンショットです。 data screenshot上記マクロを参照AverageIf関数の結果は「#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

この原因は何?この式をコーディングする正しい方法は何ですか?ライン

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

+0

あなたのライン 'DBT(K)= Application.AverageIf(D(R、COL_FT)、(D(R、COL_AOI)= "AOIエントリ"))'セルの値の平均値を取っています(行「r + 6」、列Iの値が「AOI Entry」である場合)、または「False」(値が「True」であれば、行「r + 6」列Rに位置する)列 'r + 6'、列Iは' 'AOI Entry ''ではありません)。それは常にゼロ誤差による除算を生成することになります( 'True'または' False'値がないので)、間違いなくあなたの '#VALUE'エラーを生成します。通常、平均は複数の値にわたって実行されます。どちらの値を平均化しようとしていますか? – YowE3K

+0

あなたは '= AVERAGEIFS($ R:$ R、$ I:$ I、" AOI Entry "、$ B:$ B、$ B7)という数式(例えば、セルT7内)に相当するVBAを生成しようとしていますか? 、$ C:$ C、$ C7) '? – YowE3K

+0

@ YowE3K列Iに「AOI Entry」を持つ行にある値の平均値が必要です。問題は包含基準をどのように定義したかということですか? – shecodes

答えて

1

あなたの現在の問題は、単一の値の平均を取るしようとしているという事実によるものであり、その値はTrueまたはFalseの場合のみ。例えば。 rが1である場合、平均範囲(すなわち、値-2484)の値がいずれも基準(すなわちFalse)、関数の試みと一致しないように、コードは

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

又は

dbt("Block 1|Trial, 8") = Application.AverageIf(-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) 

に相当再び、31Trueに等しくない、あなたは0

によって0を分割しようとして終わります

回答があるあなたは

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の組み込み関数を使用して合計と数を計算するのが簡単になるように設定されていないので、合計を計算して自分で計算する必要があります。

次のコードでは、2つの辞書(Sumsと呼ばれ、もう1つは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

偉大な答えとコードが動作します。 AOIエントリがない場合は0を出力したいので、変更しました 'd(r、COL_AOI)=" AOI Entry "の場合 dBT(k(r))= dBT(k(r) (k(r))+ d(r、COL_FT)+ 1 'はカウントを取得する Cnts(k(r))= Cnts(k(r))+1カウントを得る 'sum column R' 〜 'd(r、COL_AOI)=" AOI Entry "の場合 dBT(k(r))= dBT(k(r))+1カウントを取得 Elses dBT(k r))= dBT(k(r))+ 0 'カウントを得る' そして多くの平均は負の数である。理由は分かりません。 – shecodes

+0

nvm私はそれを修正したと思います。 (k(r))+ 0 'の合計を計算します。 ' Sums(k(r))= Sums(k(r) )+ d(r、COL_FT) 'sum column R' 私はその原因だと思っています。それはそれなしで大丈夫です。 – shecodes