Расширить функцию до многомерной ситуации

#arrays #excel #vba #function

#массивы #excel #vba #функция

Вопрос:

Давайте определим большие выбросы как наблюдения, которые соответствуют неравенству :

введите описание изображения здесь

И небольшие выбросы в качестве наблюдений, которые соответствуют неравенству :

введите описание изображения здесь

Я хочу написать функцию replace_outliers(table, std) , которая будет проходить через все переменные (все столбцы) и заменит большие выбросы на верхнюю границу, т.е.

введите описание изображения здесь

и небольшие выбросы с нижней границей, т.е.

введите описание изображения здесь

Моя работа до сих пор

Что я сделал, так это написал функцию для одномерной ситуации (работает только тогда, когда у меня есть только один столбец).

 Function replace_outliers(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 upper_bound As Double
    Dim lower_bound As Double
    upper_bound = std * stdv   mean
    lower_bound = mean - stdv * std
    
    Dim i As Long
    
    For i = 1 To UBound(temp, 1)
        If (temp(i, 1) - mean) / stdv > std Then
            temp(i, 1) = upper_bound
        ElseIf (temp(i, 1) - mean) / stdv < -std Then
            temp(i, 1) = lower_bound
        End If
    Next
    replace_outliers = temp
End Function
 

Пример :

введите описание изображения здесь

Однако я не уверен, что мне следует сделать, чтобы расширить это для многовариантной ситуации (т. Е. Применить replace_outliers(table, std) для каждого столбца в предоставленной таблице ввода. Есть ли у вас какие — нибудь идеи , как это можно выполнить ?

Редактировать

Я попытался перебрать ее по столбцам. Это моя работа :

 Function outliers_std_1(table As Range, std As Double)
    Dim temp() As Variant
    temp = table.Value
    Dim j As Long
    For j = 1 To UBound(temp, 2)
        Dim mean As Double
        mean = Application.WorksheetFunction.Average(table.Columns(j))
    
        Dim stdv As Double
        stdv = Application.WorksheetFunction.StDev(table.Columns(j))
        Dim upper_bound As Double
        Dim lower_bound As Double
        upper_bound = std * stdv   mean
        lower_bound = mean - stdv * std
    
        Dim i As Long
    
        For i = 1 To UBound(temp, j)
            If (temp(i, j) - mean) / stdv > std Then
                temp(i, j) = upper_bound
         ElseIf (temp(i, j) - mean) / stdv < -std Then
                temp(i, j) = lower_bound
         End If
         Next
    Next
    outliers_std_1 = temp
End Function
 

Однако я получаю #ARG ! ошибка при попытке запустить ее с данными ниже :

введите описание изображения здесь

Комментарии:

1. temp это 2D-массив, поэтому вы можете легко добавить внутренний (или, возможно, внешний) цикл по столбцам вместо жестко запрограммированного 1 . См. Раздел Массивы и диапазоны .

2. Внутренний цикл: Dim j as Long а For j = 1 to Ubound(temp,2) затем замените все temp(i,1) на temp(i,j)

3. Хм, я пытался использовать ваши советы, чтобы зациклить его после столбца, но мне не удалось сделать это правильно. Я обновил свой вопрос. Я что-то пропустил?

4. mean = Application.WorksheetFunction.Average(table.Columns(j)) и т. д

5. Хммм, я скорректировал свой код со средним значением вычисления и стандартным отклонением, но я все еще вижу #ARG!. Пожалуйста, взгляните на мой код

Ответ №1:

Проверено:

 Function outliers_std_1(table As Range, std As Double)
    Dim temp As Variant, j As Long, i As Long
    Dim mean As Double, stdv As Double
    Dim upper_bound As Double
    Dim lower_bound As Double
    
    temp = table.Value
    
    For j = 1 To UBound(temp, 2)
        
        mean = Application.WorksheetFunction.Average(table.Columns(j))
        stdv = Application.WorksheetFunction.StDev(table.Columns(j))
        upper_bound = mean   (std * stdv)
        lower_bound = mean - (stdv * std)
        
        For i = 1 To UBound(temp, 1)
            If temp(i, j) < lower_bound Then
                   temp(i, j) = lower_bound
            ElseIf temp(i, j) > upper_bound Then
                   temp(i, j) = upper_bound
            End If
        Next
    Next
    outliers_std_1 = temp
End Function