[英]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
方式:
shapiro(a)
,您將列作為符號提供,因此我們需要確保a
被正確引用,然后再引用,以便遵循dplyr
的非標准求值。 split
,更多的tidyverse
一致方法是使用nest
。 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.