Выполнить функцию по группам

В настоящее время я работаю над удалением выбросов и использую функцию Клодиана Дханы на тему выбросов ( https://datascienceplus.com/identify-describe-plot-and-removing-the-outliers-from-the-dataset/).

Мой набор данных состоит из 95000 наблюдений, разделенных на 1050 групп, и мне интересно, есть ли способ проверить выбросы по группе, а не перейти к формуле 1050 раз.

Data(DF)

Group   Height 
 Gr1    2
 Gr1    5
 Gr1    5
 Gr2    75
 Gr2    72
 Gr2    44
 Gr3    4
 Gr3    25
 Gr3    42
 …      …
 Gr1050 43

Поэтому я хотел бы проверить формулу выбросов по группе, но иметь ее в одном DF.

Я не очень эксперт, поэтому я сделал свое исследование и обнаружил, что by(), ddply(), а также tapply() функции могут быть использованы в этом случае. Я думаю также, что петли могут быть полезны.

2 ответа

Посмотрите на следующий пример. Я генерирую некоторые выборочные данные путем выборки из распределения Коши, чтобы получить достаточно широкий хвост, который дает нам выбросы согласно критерию выбросов IQR Тьюки.

# Sample data
set.seed(2017);
df <- cbind.data.frame(
    Group = rep(c("Gr1", "Gr2", "Gr3"), each = 20),
    Height = unlist(lapply(c(10, 20, 30), function(x) rcauchy(20, x))));
head(df);
#  Group    Height
#1   Gr1  9.757403
#2   Gr1  1.476820
#3   Gr1 20.300998
#4   Gr1 11.277766
#5   Gr1  9.118874
#6   Gr1  9.133723

# Split based on Group
ll <- split(df, df$Group);

# Flag entries based on 1.5 IQR
ll <- lapply(ll, function(x) {
    x$outlier <- ifelse(
        x$Height < quantile(x$Height, 0.25) - 1.5 * IQR(x$Height) |
        x$Height > quantile(x$Height, 0.75) + 1.5 * IQR(x$Height),
        TRUE,
        FALSE);
    return(x);
})

# Optionally replace outiers with NA
ll <- lapply(ll, function(x) {
    x$Height[x$outlier] <- NA;
    return(x);
});

# Optionally combine into single dataframe
df.filtered <- do.call(rbind.data.frame, ll);
head(df.filtered);
#      Group    Height outlier
#Gr1.1   Gr1  9.757403   FALSE
#Gr1.2   Gr1        NA    TRUE
#Gr1.3   Gr1        NA    TRUE
#Gr1.4   Gr1 11.277766   FALSE
#Gr1.5   Gr1  9.118874   FALSE
#Gr1.6   Gr1  9.133723   FALSE

Визуализируйте распределения до и после анализа обнаружения выбросов.

# Show a comparative plot
library(ggplot2);
df.all <- rbind.data.frame(
    cbind.data.frame(df, src = "pre-outlier analysis"),
    cbind.data.frame(df.filtered[, -3], src = "post-outlier analysis"));
gg <- ggplot(df.all, aes(x = Group, y = Height));
gg <- gg + geom_boxplot() + facet_wrap(~ src, scale = "free_y");

Вот мой подход, который использует пакет tidyverse dplyr:

        #--create dataframe

    Group = c("Gr1", "Gr1", "Gr1","Gr1",
              "Gr1", "Gr1", "Gr1","Gr1", 
              "Gr2", "Gr2", "Gr2","Gr2",
              "Gr2", "Gr2", "Gr2","Gr2",
              "Gr3", "Gr3", "Gr3","Gr3",
              "Gr3", "Gr3", "Gr3","Gr3")

    Height = c(1,21,22,23,
              241,24,29,30,
               2,50,49,50,
               51,50,4900,50,
               10,10,3000,10,
               10,10,2,10) 

    grp_df = data.frame(Group, Height)

    library(dplyr) #--for group_by and summarise functions

    library(outliers) #--for outlier function

    new_df <- grp_df %>%
      group_by(Group) %>%
      summarise(lower_outlier = outlier(Height, opposite=TRUE),
                higher_outlier = outlier(Height, opposite=FALSE))
Другие вопросы по тегам