如何根据类别组内的统计数据评估一个条件?
首先,我将展示一下我的数据和我到目前为止的代码的一个简单例子,所以解释我的问题会更容易一些。
考虑以下数据:
ID Esp DBH Cod 55 E_grandis 9.00 55 E_grandis 9.71 7 55 E_grandis 10.00 55 E_grandis 1.00 7 55 E_grandis 7.00 7 55 E_grandis 1
我试图validation如果行与Cod = 7具有大于以下值:
average of DBH - 1 * standard deviation of DBH.
在上面的例子中,DBH的平均值是7.34,标准偏差是3.73。 因此,标记Cod 7时,DBH值不应大于3.61(7.34 – 3.73)。
细胞D3和D6不通过标准,因为它们的DBH(C3和C6)大于3.61。 在所有具有Cod 7的行中,只有C5小于3.61。
我写下面的代码显示一个消息框,当这样的标准不符合:
Sub Cod7() Dim msg As String 'msg box Dim ID As Range Dim dbh_stdev As Double 'standard deviation of dbh Dim dbh_avg As Double 'average of dbh Dim not_dominated As Double 'criteria threshold (upper bound) Dim cell_i As Range 'initial of array to compute average and standard deviation Dim cell_e As Range 'end of array to compute average and standard deviation msg = "" Set cell_i = Range("C2") Set cell_e = Range("C7") dbh_stdev = WorksheetFunction.StDev(Range(cell_i, cell_e)) 'dbh standard deviation dbh_avg = WorksheetFunction.Average(Range(cell_i, cell_e)) 'dbh average not_dominated = dbh_avg - dbh_stdev 'upper bound 'searches cells with cod 7 on column Cod, and it displays a message box if 'DBH is greater than the 'not_dominated' variable value For Each ID In Range("A2", Range("A2").End(xlDown)) If ID.Offset(0, 3) = 7 And _ ID.Offset(0, 2) <> 0 And _ ID.Offset(0, 2) > not_dominated Then msg = msg & "Cod 7 on " & ID.Offset(0, 3).Address() & " is incorrect" & vbLf End If Next ID If Len(msg) > 0 Then MsgBox msg End Sub
现在的问题是,在我的真实数据中,我在Esp(specie)列下有多个类别,我需要评估标准,计算每组实体内DBH的平均值和标准偏差。
物种群集群,即一个物种通过相邻的行发生。
例如,这是在Esp列下的两个类别的最小数据:E_grandis和E_citriodora。
ID Esp DBH Cod 55 E_grandis 9.00 55 E_grandis 9.71 7 55 E_grandis 10.00 55 E_grandis 1.00 7 55 E_grandis 7.00 7 55 E_grandis 1 55 E_citriodora 3.00 55 E_citriodora 2.00 7 55 E_citriodora 2.00 7 55 E_citriodora 1 55 E_citriodora 1 55 E_citriodora 0.50 7
E_citriodora的平均胸径为1.88,标准偏差为1.03。 Cod = 7的行的DBH不能大于0.85(1.88-1.03)。 在这种情况下,单元C9和C10不通过标准,单元C13通过。
我如何调整代码以在“Esp”组中应用这样的标准?
我相信下面的代码是你想要的。 请注意, 只有将所有物种“分组”在一起才能起作用 。
我已经添加了一个外部循环,允许代码遍历所有有数据的行(具体来说,在ID中有一个值)。
起始单元( cell_i
)的初始值与原始代码中的C2
一样,但是我改变了它计算结束单元格( cell_e
)的方式:它现在基于列B
中具有与cell_i
相同的值的行数(这就是CountIf
正在做的事情,这就是为什么只有所有物种聚集在一起才能起作用)。
这与Set cell_i = cell_e.Offset(1)
使得循环从物种的第一行跳到下一个等等。
例如,第一次对您的样本数据运行时, cell_i
将是C2
, cell_e
将是C7
因为列B
中具有E_grandis
的行数是6,从cell_i
的当前行减去1并且偏移意味着它会从当前select一个5行的单元格。
第二次从C8
开始,经过C12
。 等等。
在循环体内,我已经把你的原始代码(主要是“不受伤害”)。 我刚刚调整了For
循环,以便遍历范围( cell_i
到cell_e
如groupRange
variables中捕获的)中的单元格,而不是在列A
中具有值的所有行之间进行迭代。
我已经添加了几个Select
调用,以便您可以在逐步执行代码时遵循ccell
和groupRange
的值。
Option Explicit Public Sub Cod7() Dim msg As String 'msg box Dim dbh_stdev As Double 'standard deviation of dbh Dim dbh_avg As Double 'average of dbh Dim not_dominated As Double 'criteria threshold (upper bound) Dim cell_i As Range 'initial of array to compute average and standard deviation Dim cell_e As Range 'end of array to compute average and standard deviation Dim ccell As Range 'current cell Dim groupRange As Range msg = "" Set cell_i = Range("C2") Do While cell_i.Offset(, -2) <> "" Set cell_e = cell_i.Offset(WorksheetFunction.CountIf(Range("B:B"), cell_i.Offset(, -1).Value) - 1) Set groupRange = Range(cell_i, cell_e) groupRange.Select dbh_stdev = WorksheetFunction.StDev(groupRange) 'dbh standard deviation dbh_avg = WorksheetFunction.Average(groupRange) 'dbh average not_dominated = dbh_avg - dbh_stdev 'upper bound 'searches cells with cod 7 on column Cod, and it displays a message box if 'DBH is greater than the 'not_dominated' variable value For Each ccell In groupRange ccell.Select If ccell.Offset(, 1).Value = 7 And _ ccell.Value <> 0 And _ ccell.Value > not_dominated Then msg = msg & "Cod 7 on " & ccell.Offset(, 1).Address() & " is incorrect" & vbLf End If Next Set cell_i = cell_e.Offset(1) Loop If Len(msg) > 0 Then MsgBox msg End Sub
或者你可以将整个脚本全部删除,并在单元格E2中使用此公式(然后复制,粘贴):
{=IF(AND(D2=7,C2>AVERAGEIF($B$2:$B$13,B2,$C$2:$C$13)-1* STDEV(IF($B$2:$B$13=B2,$C$2:$C$13))),"warning","")}
注意数组公式 – 记得用ctrl-shift-enter
在你的鞋子里,我会写代码来列出每个可能的ESP值。 我将每个数据点与这个列表进行比较,并保持运行总数来开发平均DBH,再次将DBH与列表进行比较以产生标准差,编制列表中每个ESP的最小/最大可接受DBH,然后制作一个最终通过检查实际DBH与最小/最大DBH的特定ESP值并应用编码程序。