簡體   English   中英

在函數內部的select語句中使用dataframe列名與map()一起使用

[英]Using dataframe column names inside select statement inside function for use with map()

今天我開始使用purrr函數,所以我可以嘗試從更實用的方法中使用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

因此,我希望它在單個列上運行,但我希望它在任何列的給定向量上運行。 我現在的想法是創建一個我想要運行的列名的向量,並在map()中使用它。 我覺得我很接近這個權利,但我只是有點卡住了。

# 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)

但是,由於列名不在環境中,因此會出錯。 有沒有人有關於如何解決或改善它的建議?

謝謝!

這是一種有三種修正/改進的tidyverse方式:

  1. 在您的示例中調用shapiro(a) ,您將列作為符號提供,因此我們需要確保a被正確引用,然后再引用,以便遵循dplyr的非標准求值。
  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

如果你想用一個函數做這個,你可能需要進入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

reprex包創建於2019-03-05(v0.2.1)

您可以使用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"))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM