Bedingte Auswertung von Datenreihen

  • Excel

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von petaod.

    Bedingte Auswertung von Datenreihen

    Liebes Forum,

    momentan arbeite ich an einem Code, der mir für mehrere Messwerte aus unterschiedlichen Datenreihen den Mittelwert und die Standardabweichung berechnen soll. Dazu speichere ich die jeweiligen Werte in Variablen. Allerdings soll er das nicht immer für alle machen, sondern nur für die Datenreihen, die entsprechend markiert sind, in meinem Fall mit einer 1 (diese Markierung bezeichne ich mal als Counter). Die restlichen Werte soll der Code, auch wenn sie vielleicht vorliegen, nicht mit einbeziehen. Momentan trickse ich und missbrauche Zellen als Variablen, um die Funktionen

    {=MITTELWERT(WENN(E9:E13>0;F9:F13))} bzw.

    {=STABWN(WENN(E9:E13>0;F9:F13))}

    benutzen zu können. Allerdings macht das die Auswertung meiner recht großen Datenmengen sehr langsam und ich würde diesen Schritt gerne direkt im Code durchführen.

    Für die Berechnung des Mittelwertes habe ich bereits die AverageIf-Funktion gefunden. Gibt es zur Berechnung der Standardabweichung eine entsprechende Gleichung im VBA-Code?

    Daneben ergibt sich für mich aber noch ein zweites Problem. Da die Counter der Datenreihen sich auch während der Auswertung verändern können, also zum Beispiel Reihe 2 mal mit ausgewertet wird (Counter = 1) und mal nicht (Counter = 0) - was sich für jeden Schritt neu aus dem Code ergibt - muss ich die Counter als Variablen irgendwie in diese Averageif-Funktion bekommen und kann sie nicht einfach festsetzen. Die Funktion will allerdings eine Range für die Abfrage haben.

    Meine Frage wäre nun, ob es eine Möglichkeit gibt die Counter in einer Range, bzw. einem Array zu verpacken und dann in die Funktion einzubinden und die gesamte Berechnung im Code ablaufen zu lassen. Bei meinen bisherigen Nachforschungen konnte ich leider nichts Hilfreiches dazu finden.

    Ich bedanke mich schonmal im Voraus für alle hilfreichen Bemühungen.

    Olaf schrieb:

    sehr langsam
    Arrayformeln sind für schlechte Performance prädestiniert.

    Olaf schrieb:

    Gibt es zur Berechnung der Standardabweichung eine entsprechende Gleichung im VBA-Code?
    Du kannst alle Excel-Worksheet-Funktionen auch in VBA verwenden, allerdings mit deren englischen Namen.
    StdAbw = Application.Worksheetfunction.STDEVP(Range("F9:F13"))
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Das mit der Worksheet-Funktion habe ich auch schon gefunden, gut zu wissen, dass es auch für die Standardabweichung funktioniert.
    Allerdings stehe ich dann immer noch vor dem Problem, dass die bedingte Auswertung eine Range habe will, um zu prüfen welche Werte mit in die Berechnung einbezogen werden. Ich habe diese Werte allerdings als Variablen im Code. Gibt es eine Möglichkeit die Variablen in die bedingte Auswertung zu stecken anstatt einer Range?

    Olaf schrieb:

    Gibt es eine Möglichkeit die Variablen in die bedingte Auswertung zu stecken anstatt einer Range?
    Das ist sogar Standard. Einzelne Werte (ParamArray) oder Array.
    Der Sonderfall ist, dass du auch einen Range mitgeben kannst, weil dessen Standard-Property .Value ein Array bildet.
    msdn.microsoft.com/en-us/vba/e…ction-stdevp-method-excel
    ​You can also use a single array or a reference to an array instead of arguments separated by commas.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Ok, dann versuche ich das mal zusammenzusetzen.

    Mein Code ist so geplant:
    Ob ein Wert in die Berechnung mit einfließt wird jeweils an einer Variable überprüft, sprich:

    Wert1 wird einbezogen, wenn a>0
    Wert2 wird einbezogen, wenn b>0
    Wert3 wird einbezogen, wenn c>0
    Wert4 wird einbezogen, wenn d>0
    Wert5 wird einbezogen, wenn e>0

    Nun definiere ich die berechnete Standardabweichung als:

    Abweichung=Application.WorksheetFunction.STDEVP(IF(a>0;Wert1),IF(b>0;Wert2),IF(c>0;Wert3),IF(d>0;Wert4),IF(e>0;Wert5))

    Bei dieser Schreibweise bekomme ich allerdings eine Fehlermeldung, weil er die If-Funktion nicht als Wert annimmt.
    Wenn du das schon innerhalb des Aufrufs auswählen willst, verwende IIF.
    Und was machst du im Else-Fall? Da wird dann ein leerer Wert übergeben.
    Keine Ahnung, was STDEVP daraus macht.

    Stelle dir doch ein Array zusammen, das alle gewünschten Werte beinhaltet und übergib dieses.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Hallo petaod,

    herzlichen Dank für alle deine Versuche zu helfen, allerdings kann die Worksheetfunktion STDEVP keine leeren Werte in der IIF-Funktion verarbeiten, weswegen sie leider als Möglichkeit rausfliegt. Ich fürchte, dass ich um das Mogeln nicht herum komme und weiterhin im Sheet selbst arbeiten muss. Solltest du nicht noch einen weiteren Einfall haben, würde ich das Thema ansonsten hier schließen.
    Stimmt, hatte ich irgendwie überlesen.

    Die ersten Versuche sehen vielversprechend aus. Ich setze das jetzt mal vollständig um.
    Wenn noch Fragen aufkommen sollten melde ich mich nochmal. Außerdem werde ich zum Schluss noch eine Kurzfassung der Lösung hochladen.

    Vielen Dank bereits an dieser Stelle petaod.
    Ich habe die Änderungen nun umgesetzt und die Resultate mehr als zufriedenstellend. Der Code ist durch das wegfallende Zurückgreifen auf Sheetdaten mehr als doppelt so schnell geworden.
    Da WorksheetFunction.Average und .StDevP leere Werte automatisch ausschließen, kann das Problem insgesamt relativ simpel gelöst werden, wie im Code dargestellt.

    Quellcode

    1. Private Sub CommandButton1_Click()
    2. Dim Abweichung As Double
    3. Dim Mittelwert As Double
    4. Dim a As Integer
    5. Dim b As Integer
    6. Dim c As Integer
    7. Dim d As Integer
    8. Dim e As Integer
    9. Dim wert1 As Double
    10. Dim wert2 As Double
    11. Dim wert3 As Double
    12. Dim wert4 As Double
    13. Dim wert5 As Double
    14. Dim ArrayWert(1 To 5) As Variant
    15. a = Worksheets(1).Range("E9").Value
    16. b = Worksheets(1).Range("E10").Value
    17. c = Worksheets(1).Range("E11").Value
    18. d = Worksheets(1).Range("E12").Value
    19. e = Worksheets(1).Range("E13").Value
    20. If a > 0 Then
    21. ArrayWert(1) = Worksheets(1).Range("F9").Value
    22. Else
    23. ArrayWert(1) = ""
    24. End If
    25. If b > 0 Then
    26. ArrayWert(2) = Worksheets(1).Range("F10").Value
    27. Else
    28. ArrayWert(2) = ""
    29. End If
    30. If c > 0 Then
    31. ArrayWert(3) = Worksheets(1).Range("F11").Value
    32. Else
    33. ArrayWert(3) = ""
    34. End If
    35. If d > 0 Then
    36. ArrayWert(4) = Worksheets(1).Range("F12").Value
    37. Else
    38. ArrayWert(4) = ""
    39. End If
    40. If e > 0 Then
    41. ArrayWert(5) = Worksheets(1).Range("F13").Value
    42. Else
    43. ArrayWert(5) = ""
    44. End If
    45. Mittelwert = Application.WorksheetFunction.Average(ArrayWert)
    46. Abweichung = Application.WorksheetFunction.StDevP(ArrayWert)
    47. Worksheets(1).Range("H9").Value = Mittelwert
    48. Worksheets(1).Range("H10").Value = Abweichung
    49. End Sub


    Danke nochmal an petaod für die gute und geduldige Hilfe.
    Ich nehme an, der Button ist auf dem Worksheet platziert.
    Dann steht auch der Eventhandler im Codebereich des Worksheets.
    Damit kannst du dir die Adressierung des Worksheets sparen.

    Und wenn du schon 5 mal dasselbe machst, kannst du das auch in einer Schleife tun:

    Visual Basic-Quellcode

    1. Private Sub CommandButton1_Click()
    2. Const Count = 5 'array size
    3. Dim i As Integer, c As Range, Arr(Count) As Variant
    4. Set c = Range("E9") 'ArrayStart
    5. For i = 0 To Count - 1
    6. Arr(i) = IIf(c.Value > 0, c.Value, "")
    7. Set c = c.Offset(1)
    8. Next
    9. Range("H9").Value = Application.WorksheetFunction.Average(Arr) 'Mittelwert
    10. Range("H10").Value = Application.WorksheetFunction.StDevP(Arr) 'Abweichung
    11. End Sub
    Sieht kompakter aus.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --