【问题标题】:Replacing outliers with zeroes in VBA在VBA中用零替换异常值
【发布时间】:2021-04-11 14:55:42
【问题描述】:

我想编写函数 outliers_std(table, std) 用零替换异常值。

让我们将异常值定义为满足以下不等式的变量:

所以我想遍历整个表格,如果有任何元素满足上面的不等式,我想用 0 替换它。

我目前的工作

Function outliers_std(table As Variant, std As Double)
    Dim row As Range
    For Each row In [table].Rows
        If Abs(table(row) - Application.WorksheetFunction.Average(table)) / Application.WorksheetFunction.StDev(table) > std Then
            table(row) = 0
        End If
    Next
    outliers_std = table
End Function

但是在尝试运行时

outliers_std(E10:E14,1)

E10:E14 是下面的数据

我收到错误#ARG!

你知道问题出在哪里吗?

编辑

我跑了代码

Function outliers_std(table As Variant, std As Double) As Variant
    Dim row As Range
    For Each row In [table].Rows
        If Abs(row - Application.WorksheetFunction.Average(table)) / Application.WorksheetFunction.StDev(table) > std Then
            table(row) = 0
        End If
    Next
    outliers_std = table
End Function

而且错误仍然保持不变。我是不是写错了什么?

【问题讨论】:

  • 哦,我改了。问题依旧
  • 更新了我的问题 ;))
  • row 现在本身就是一个范围。你可以用row 而不是table(row) 来调用它,表也应该是1 列引用。所以table As Range
  • 嗯,我不确定我是否理解。你能在回答中扩展这个吗?
  • ^^^^ 所以这里使用数组变量^^^。

标签: arrays excel vba function


【解决方案1】:

代码:

Function outliers_std(table As Range, std As Double)
    Dim temp() As Variant
    temp = table.Value
    
    Dim mean As Double
    mean = Application.WorksheetFunction.Average(temp)
    
    Dim stdv As Double
    stdv = Application.WorksheetFunction.StDev(temp)
    
    Dim i As Long
    
    For i = 1 To UBound(temp, 1)
        If Abs(temp(i, 1) - mean) / stdv > std Then
            temp(i, 1) = 0
        End If
    Next
    outliers_std = temp
End Function

现在根据您的版本,可以将其放在一个单元格中,它会溢出结果,或者他们需要突出显示与表格相同数量的单元格并使用 Ctrl-Shift-Enter 来返回所有值。


但是如果在工作表中这样做,则不会为此 vba:

=IF(ABS(E10:E14-AVERAGE(E10:E14))/STDEV(E10:E14)>1,0,E10:E14)

像上面一样,取决于一个人的版本,它会自动溢出,或者需要突出显示相同数量的单元格并使用 Ctrl-Shift-Enter

【讨论】:

  • 编辑很棒。我认为 VBA 在这里有点矫枉过正。
【解决方案2】:

我发现原始代码存在两个问题。一,表的值不能不更新。第二,我永远不会增加。我得到了这段代码。

Function outliers_std(table As Variant, std As Double)
Dim i As Integer
Dim row As Range
Dim newtable As Variant

i = 1
ReDim newtable(1 To [table].Rows.Count, 1 To 1) As Variant
For i = 1 To [table].Rows.Count
    If Abs(table(i, 1) - Application.WorksheetFunction.Average(table)) / Application.WorksheetFunction.StDev(table) > std Then
        newtable(i, 1) = 0
    Else
        newtable(i, 1) = table(i)
    End If
Next
outliers_std = newtable

结束函数

【讨论】:

  • 进入循环前需要计算mean/stdev...
  • 谢谢,这在计算上肯定会更有效。
  • 这不仅仅是为了提高效率 - 每次用零替换一个数字时,它都会改变平均值和标准差,因此截止值会发生变化并产生不需要的结果。
  • 它改变了newtable中的值并计算了table上的mean/stdev,所以这应该是一个问题,也就是说最好提前计算。
猜你喜欢
  • 2018-01-05
  • 2016-06-25
  • 1970-01-01
  • 2019-03-14
  • 1970-01-01
  • 2018-01-05
  • 1970-01-01
  • 2021-08-17
  • 1970-01-01
相关资源
最近更新 更多