Использование имен столбцов данных внутри оператора select внутри функции для использования с map () - PullRequest
1 голос
/ 06 марта 2019

Сегодня я начал работать с функциями мурлыкания, поэтому я могу попробовать использовать R из более функционального подхода.В настоящее время у меня есть фрейм данных, который содержит переменную ответа с множеством других переменных.Моя цель - разделить фрейм данных по уровням в столбце ответа, а затем запустить shapiro.test () на всех фреймах разделения.

Например, этот код работает:

# fake data 
df = data.frame(y = c(rep(1,10), rep(2, 10)), 
                a = rnorm(20),
                b = runif(20), 
                c = rnorm(20))

df$y <- factor(df$y)    

df %>% 
    select(y, a) %>% 
    split(.$y) %>% 
    map(~shapiro.test(.x$a))

И это возвращает:

$`1`

    Shapiro-Wilk normality test

data:  .x$a
W = 0.93455, p-value = 0.4941


$`2`

    Shapiro-Wilk normality test

data:  .x$a
W = 0.7861, p-value = 0.009822

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

# Function that splits the df into two groups based on y levels and run shapiro test on the split dfs
shapiro <- function(var) {
  df_list = df %>% 
    select(y, var) %>% 
    split(.$y) %>% 
    map(~shapiro.test(.x$var))
  return(df_list)
}

Это терпит неудачу:

> shapiro(a)
Error in .f(.x[[i]], ...) : object 'a' not found

Что имеет смысл, поскольку a не сохраняетсяв окружающей среде.Это своего рода направление, которое я себе представляю, но я не знаю, есть ли лучший способ сделать это.

# the column names I want the function to take
columns = c(a, b, c)

# map it
map(columns, shapiro)

Однако, это дает ошибку, так как имена столбцов не находятся вокружающая среда.У кого-нибудь есть предложения как это исправить или улучшить?

Спасибо!

Ответы [ 3 ]

2 голосов
/ 06 марта 2019

Вот способ tidyverse с тремя исправлениями / улучшениями:

  1. В вашем примере вызова shapiro(a), вы предоставляете столбец как символ, поэтому мы должны убедиться, что a правильно цитируется, а затем не цитируется, чтобы придерживаться dplyr s нестандартной оценки.
  2. Вместо split более tidyverse -согласованный подход заключается в использовании nest.
  3. Наконец, я бы рекомендовал сделать df аргументом функции shapiro, чтобы избежать зависимости от глобальной переменной.

Это улучшенная версия

shapiro <- function(df, var) {
  var <- enquo(var)
  df_list <- df %>%
      select(y, !!var) %>%
      group_by(y) %>%
      nest() %>%
      mutate(test = map(setNames(data, y), ~shapiro.test(.x[[1]]))) %>%
      pull(test)
  return(df_list)
}

То же для столбца df$a

shapiro(df, a)
#$`1`
#
#   Shapiro-Wilk normality test
#
#data:  .x[[1]]
#W = 0.93049, p-value = 0.4527
#
#
#$`2`
#
#   Shapiro-Wilk normality test
#
#data:  .x[[1]]
#W = 0.9268, p-value = 0.4171

и для столбца df$b

shapiro(df, b)
#$`1`
#
#   Shapiro-Wilk normality test
#
#data:  .x[[1]]
#W = 0.90313, p-value = 0.237
#
#
#$`2`
#
#   Shapiro-Wilk normality test
#
#data:  .x[[1]]
#W = 0.88552, p-value = 0.1509
1 голос
/ 06 марта 2019

Если вы хотите сделать это с помощью функции, вам, вероятно, нужно войти в tidyeval , как ответ @MauritsEvers. Для относительно небольшой задачи, подобной этой, вы могли бы вместо этого выполнить пару map вызовов. Сопоставьте список фреймов данных, созданных путем деления на y, затем используйте map_at, чтобы применить тест к выбранным вами столбцам.

В первом методе вы получаете некоторое превышение - все столбцы , а не в map_at просто висят там. Более чистый способ - выбрать нужные столбцы, а затем map по всем столбцам, чтобы применить тест.

library(tidyverse)

test_list1 <- df %>%
  split(.$y) %>%
  map(function(split_by_y) {
    split_by_y %>%
      map_at(vars(a, b, c), shapiro.test)
  })

test_list2 <- df %>%
  split(.$y) %>%
  map(function(split_by_y) {
    split_by_y %>%
      select(a, b, c) %>%
      map(shapiro.test)
  })

test_list2[[2]]$a
#> 
#>  Shapiro-Wilk normality test
#> 
#> data:  .x[[i]]
#> W = 0.95281, p-value = 0.7018

Создано в 2019-03-05 пакетом Представление (v0.2.1)

0 голосов
/ 06 марта 2019

Вы можете добавить результаты в список, используя цикл for:

shapiro <- function(var) {
   myList = list()
   for (i in 1:length(var)) {
     myList[[i]] = df %>% 
     select(y, var = var[i]) %>% 
     split(.$y) %>% 
     map(~shapiro.test(.x$var))
   }
   return(myList)
}

Просто используйте символьный вектор для столбцов:

shapiro(c("a", "b"))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...