Как правильно использовать group_by () и sumrize () в цикле For в R - PullRequest
0 голосов
/ 20 октября 2018

Я пытаюсь вычислить некоторую сводную информацию, чтобы помочь мне проверить выбросы в разных группах в наборе данных.Я могу получить вид вывода, который я хочу, используя dplyr::group_by() и dplyr::summarise() - фрейм данных со сводной информацией для каждой группы для данной переменной.Примерно так:

Sepal.Length_outlier_check <- iris %>%
  dplyr::group_by(Species) %>% 
  dplyr::summarise(min = min(Sepal.Length, na.rm = TRUE),
                   max = max(Sepal.Length, na.rm = TRUE),
                   median = median(Sepal.Length, na.rm = TRUE),
                   MAD = mad(Sepal.Length, na.rm = TRUE),
                   MAD_lowlim = median - (3 * MAD),
                   MAD_highlim = median + (3 * MAD),
                   Outliers_low = any(Sepal.Length < MAD_lowlim, na.rm = TRUE),
                   Outliers_high = any(Sepal.Length > MAD_highlim, na.rm = TRUE)
                   )

Sepal.Length_outlier_check

Однако я хотел бы иметь возможность поместить это в цикл For, чтобы иметь возможность создавать аналогичные итоговые кадры данных для каждой из различных переменных в наборе данных.Я новичок в использовании циклов, но я подумал, что это может выглядеть примерно так:

vars <- list(colnames(iris))

for (i in vars) {

x <- iris %>%
  dplyr::group_by(Species) %>% 
  dplyr::summarise(min = min(i, na.rm = TRUE),
                   max = max(i, na.rm = TRUE),
                   median = median(i, na.rm = TRUE),
                   MAD = mad(i, na.rm = TRUE),
                   MAD_lowlim = median - (3 * MAD),
                   MAD_highlim = median + (3 * MAD),
                   Outliers_low = any(i < MAD_lowlim, na.rm = TRUE),
                   Outliers_high = any(i > MAD_highlim, na.rm = TRUE)
                   )

assign(paste(i, "Outlier_check", sep = "_"), x)

}

Я знаю, что это не сработает, потому что в сводных функциях i на самом деле нессылаясь на любые данные.Я не уверен, что мне нужно сделать, чтобы это работало!Я был бы очень признателен за вашу помощь, или любые предложения о том, как сделать все это более элегантно.

Я не хочу использовать dplyr :: summarise_all (), потому что он выводит одну сводную таблицу для всехпеременных, и поскольку в реальном наборе данных, над которым я работаю, много переменных, эта сводная таблица станет слишком большой, чтобы ее можно было легко просмотреть.

Спасибо.

Ответы [ 4 ]

0 голосов
/ 20 октября 2018

Вы также можете создавать эти сводные данные по переменным / видам без циклов или отдельных функций, просто gather, используя столбцы без видов, группируя и суммируя:

library(tidyverse)

iris.summary <- iris %>% 
  gather(variable, value, -Species) %>% 
  group_by(variable, Species) %>% 
  summarize(
    min = min(value, na.rm = TRUE),
    max = max(value, na.rm = TRUE),
    median = median(value, na.rm = TRUE),
    MAD = mad(value, na.rm = TRUE),
    MAD_lowlim = median - (3 * MAD),
    MAD_highlim = median + (3 * MAD),
    Outliers_low = any(value < MAD_lowlim, na.rm = TRUE),
    Outliers_high = any(value > MAD_highlim, na.rm = TRUE)
  )

   variable     Species      min   max median   MAD MAD_lowlim MAD_highlim Outliers_low Outliers_high
   <chr>        <fct>      <dbl> <dbl>  <dbl> <dbl>      <dbl>       <dbl> <lgl>        <lgl>        
 1 Petal.Length setosa       1     1.9   1.5  0.148      1.06         1.94 TRUE         FALSE        
 2 Petal.Length versicolor   3     5.1   4.35 0.519      2.79         5.91 FALSE        FALSE        
 3 Petal.Length virginica    4.5   6.9   5.55 0.667      3.55         7.55 FALSE        FALSE        
 4 Petal.Width  setosa       0.1   0.6   0.2  0          0.2          0.2  TRUE         TRUE         
 5 Petal.Width  versicolor   1     1.8   1.3  0.222      0.633        1.97 FALSE        FALSE        
 6 Petal.Width  virginica    1.4   2.5   2    0.297      1.11         2.89 FALSE        FALSE        
 7 Sepal.Length setosa       4.3   5.8   5    0.297      4.11         5.89 FALSE        FALSE        
 8 Sepal.Length versicolor   4.9   7     5.9  0.519      4.34         7.46 FALSE        FALSE        
 9 Sepal.Length virginica    4.9   7.9   6.5  0.593      4.72         8.28 FALSE        FALSE        
10 Sepal.Width  setosa       2.3   4.4   3.4  0.371      2.29         4.51 FALSE        FALSE        
11 Sepal.Width  versicolor   2     3.4   2.8  0.297      1.91         3.69 FALSE        FALSE        
12 Sepal.Width  virginica    2.2   3.8   3    0.297      2.11         3.89 FALSE        FALSE   
0 голосов
/ 20 октября 2018

Основная проблема может быть решена с помощью get(i).
Что касается результатов, лучше сохранить их в списке, а не иметь несколько (в данном случае 4) несвязанных объектов в глобальной среде.

library(dplyr)

vars <- colnames(iris)
vars <- vars[-which(vars == "Species")]

Outlier_check <- vector("list", length(vars))

for (i in vars) {

  Outlier_check[[i]] <- iris %>%
    group_by(Species) %>% 
    summarise(min = min(get(i), na.rm = TRUE),
              max = max(get(i), na.rm = TRUE),
              median = median(get(i), na.rm = TRUE),
              MAD = mad(get(i), na.rm = TRUE),
              MAD_lowlim = median - (3 * MAD),
              MAD_highlim = median + (3 * MAD),
              Outliers_low = any(get(i) < MAD_lowlim, na.rm = TRUE),
              Outliers_high = any(get(i) > MAD_highlim, na.rm = TRUE)
    )
}

Outlier_check$Sepal.Length
## A tibble: 3 x 9
#  Species   min   max median   MAD MAD_lowlim
#  <fct>   <dbl> <dbl>  <dbl> <dbl>      <dbl>
#1 setosa    4.3   5.8    5   0.297       4.11
#2 versic…   4.9   7      5.9 0.519       4.34
#3 virgin…   4.9   7.9    6.5 0.593       4.72
## ... with 3 more variables: MAD_highlim <dbl>,
##   Outliers_low <lgl>, Outliers_high <lgl>
0 голосов
/ 20 октября 2018

Вы также можете написать функцию, чтобы сделать ее проще и гибче.Используя метод аккуратной оценки, вы должны использовать rlang::sym() для преобразования строки в переменную, а затем заключать ее в кавычки внутри summarise() с помощью !! (bang bang).

library(dplyr)

check_outlier <- function(df, .groupvar, .checkvar) {

  .groupvar <- sym(.groupvar)
  .checkvar <- sym(.checkvar)

  df_outlier_check <- df %>%
    dplyr::group_by(!! .groupvar) %>% 
    dplyr::summarise(min = min(!! .checkvar, na.rm = TRUE),
                     max = max(!! .checkvar, na.rm = TRUE),
                     median = median(!! .checkvar, na.rm = TRUE),
                     MAD = mad(!! .checkvar, na.rm = TRUE),
                     MAD_lowlim = median - (3 * MAD),
                     MAD_highlim = median + (3 * MAD),
                     Outliers_low = any(!! .checkvar < MAD_lowlim, na.rm = TRUE),
                     Outliers_high = any(!! .checkvar > MAD_highlim, na.rm = TRUE)
    )

  return(df_outlier_check)

}

# test function
check_outlier(iris, "Species", "Sepal.Length")

#> # A tibble: 3 x 9
#>   Species   min   max median   MAD MAD_lowlim MAD_highlim Outliers_low
#>   <fct>   <dbl> <dbl>  <dbl> <dbl>      <dbl>       <dbl> <lgl>       
#> 1 setosa    4.3   5.8    5   0.297       4.11        5.89 FALSE       
#> 2 versic~   4.9   7      5.9 0.519       4.34        7.46 FALSE       
#> 3 virgin~   4.9   7.9    6.5 0.593       4.72        8.28 FALSE       
#> # ... with 1 more variable: Outliers_high <lgl>

Перебрать все переменные и объединить результаты в один фрейм данных, используя purrr::map_df()

library(purrr)
vars <- c("Sepal.Length", "Sepal.Width",  "Petal.Length", "Petal.Width")
vars %>% 
  set_names() %>% 
  map_df(~ check_outlier(iris, "Species", .x), .id = 'Variable')

#> # A tibble: 12 x 10
#>    Variable Species   min   max median   MAD MAD_lowlim MAD_highlim
#>    <chr>    <fct>   <dbl> <dbl>  <dbl> <dbl>      <dbl>       <dbl>
#>  1 Sepal.L~ setosa    4.3   5.8   5    0.297      4.11         5.89
#>  2 Sepal.L~ versic~   4.9   7     5.9  0.519      4.34         7.46
#>  3 Sepal.L~ virgin~   4.9   7.9   6.5  0.593      4.72         8.28
#>  4 Sepal.W~ setosa    2.3   4.4   3.4  0.371      2.29         4.51
#>  5 Sepal.W~ versic~   2     3.4   2.8  0.297      1.91         3.69
#>  6 Sepal.W~ virgin~   2.2   3.8   3    0.297      2.11         3.89
#>  7 Petal.L~ setosa    1     1.9   1.5  0.148      1.06         1.94
#>  8 Petal.L~ versic~   3     5.1   4.35 0.519      2.79         5.91
#>  9 Petal.L~ virgin~   4.5   6.9   5.55 0.667      3.55         7.55
#> 10 Petal.W~ setosa    0.1   0.6   0.2  0          0.2          0.2 
#> 11 Petal.W~ versic~   1     1.8   1.3  0.222      0.633        1.97
#> 12 Petal.W~ virgin~   1.4   2.5   2    0.297      1.11         2.89
#> # ... with 2 more variables: Outliers_low <lgl>, Outliers_high <lgl>

Создано в 2018-10-20 представпакет (v0.2.1.9000)

0 голосов
/ 20 октября 2018

Это на самом деле довольно сложно, и я сам удивился, когда я задал этот вопрос .

Вот один из способов сделать это

for(i in colnames(iris)[1:4]) {
iris$artificialcolumn <- iris[,which(colnames(iris)==i)]
print(i)
x <- iris %>%
  dplyr::group_by(Species) %>% 
  dplyr::summarise(min = min(artificialcolumn , na.rm = TRUE),
                   max = max(artificialcolumn, na.rm = TRUE),
                   median = median(artificialcolumn, na.rm = TRUE),
                   MAD = mad(artificialcolumn, na.rm = TRUE),
                   MAD_lowlim = median - (3 * MAD),
                   MAD_highlim = median + (3 * MAD),
                   Outliers_low = any(artificialcolumn < MAD_lowlim, na.rm = TRUE),
                   Outliers_high = any(artificialcolumn > MAD_highlim, na.rm = TRUE)
  )
}
x

ирезультат:

> x
# A tibble: 3 x 9
  Species      min   max median   MAD MAD_lowlim MAD_highlim Outliers_low Outliers_high
  <fct>      <dbl> <dbl>  <dbl> <dbl>      <dbl>       <dbl> <lgl>        <lgl>        
1 setosa       0.1   0.6    0.2 0          0.2          0.2  TRUE         TRUE         
2 versicolor   1     1.8    1.3 0.222      0.633        1.97 FALSE        FALSE        
3 virginica    1.4   2.5    2   0.297      1.11         2.89 FALSE        FALSE        

Пятый столбец - это коэффициент, поэтому возвращается ошибка.

...