2017-02-22 3 views
1

이것은 내 데이터의 스크린 샷입니다. 위의 매크로를 참조 data screenshotAverageIf 함수 결과가 "# 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 

는 다음 코드 줄이 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

? 이 수식을 코딩하는 올바른 방법은 무엇입니까? 라인

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''이면 값이 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 열 R에 값의 평균을 원하지만 열 I에 "AOI Entry"가있는 행에있는 값만 원합니다. 포함 기준을 정의한 방법에 문제가 있다는 말입니까? – shecodes

답변

1

현재 문제로 인해 단일 값의 평균을 취하려고하는 것으로, 그 값이 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 때

마찬가지로, 코드는 31이 같지 True 않습니다,

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

다시

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

또는

에 을 동일시 , 당신은 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의 기본 제공 함수를 쉽게 사용할 수 있도록 설정되어 있지 않으므로 합계를 계산하고 계산해야합니다.

다음 코드에서는 두 개의 사전 (하나는 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

훌륭한 답변과 코드가 작동합니다. 나는 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 카운트를 얻는다 '합계 열 R' ~ 만약 d (r, COL_AOI) = "AOI 엔트리"이면, dBT (k (r)) = dBT (k (r)) +1 카운트를 얻는다 Else dBT (k r)) = dBT (k (r)) + 0 '카운트 받기' 그리고 이제는 많은 평균이 음수입니다. 이유를 모르겠다. – shecodes

+0

nvm 문제가 해결 된 것 같습니다. 나는 평균을위한 else 문을 넣는다. 'Else 'Cnts (k (r)) = Cnts (k (r)) + 0 '카운트 받기 'Sums (k (r)) = Sums (k (r)) + d (r, COL_FT) '합계 열 R' 원인이라고 생각합니다. 그것 없이는 괜찮습니다. – shecodes