删除函数内因子的 NA 值
Dropping NA values of factors within a function
玩具资料:
假设我有这个 df
df <- structure(list(x = structure(c(NA, 7L, NA, NA, 4L, 6L, 6L, 2L,
3L, 5L, 8L, 4L, 7L, 3L, 5L, 1L, 5L, 5L, 5L, NA), .Label = c("1",
"2", "3", "4", "5", "6", "7", "8"), class = "factor"), y = structure(c(NA,
2L, 3L, 2L, 2L, 2L, 2L, 1L, 3L, NA, 2L, 3L, 1L, 1L, 3L, 2L, 2L,
3L, 2L, 2L), .Label = c("1", "2", "3"), class = "factor"), z = structure(c(NA,
4L, 4L, 4L, 5L, 4L, 5L, 5L, 2L, NA, 4L, 1L, 1L, 3L, 2L, 5L, 2L,
2L, 4L, NA), .Label = c("1", "2", "3", "4", "5"), class = "factor"),
a = c(-32L, -51L, -22L, 44L, 55L, -24L, -50L, 67L, 1L, -47L,
66L, -98L, -91L, -42L, -89L, -31L, -8L, -33L, 38L, 61L),
b = c(46L, -19L, -37L, 47L, -28L, -48L, 14L, -10L, -13L,
-31L, 32L, 21L, -21L, 25L, -8L, 42L, -26L, -24L, 36L, -39L
)), row.names = c(NA, -20L), class = c("tbl_df", "tbl", "data.frame"
))
df
# A tibble: 20 × 5
x y z a b
<fct> <fct> <fct> <int> <int>
1 NA NA NA -32 46
2 7 2 4 -51 -19
3 NA 3 4 -22 -37
4 NA 2 4 44 47
5 4 2 5 55 -28
6 6 2 4 -24 -48
7 6 2 5 -50 14
8 2 1 5 67 -10
9 3 3 2 1 -13
10 5 NA NA -47 -31
11 8 2 4 66 32
12 4 3 1 -98 21
13 7 1 1 -91 -21
14 3 1 3 -42 25
15 5 3 2 -89 -8
16 1 2 5 -31 42
17 5 2 2 -8 -26
18 5 3 2 -33 -24
19 5 2 4 38 36
20 NA 2 NA 61 -39
我想在 0-1 范围内对变量 x
、y
和 z
进行标准化,然后生成一些关于它们的摘要统计信息。我可以使用下面的代码生成摘要统计数据
有效代码:
library(tidyverse)
vars <- c('x', 'y', 'z')
names(vars) <- vars
summary_stats <- function(data){
tibble(
n = sum(!is.na(data)),
mean = round(mean(as.numeric(data), na.rm = T), digits = 3),
sd = round(sd(as.numeric(data), na.rm = T), digits = 3),
se = round(sd/sqrt(n), digits = 3)
)
}
table <- map_df(
df %>%
dplyr::select(vars),
summary_stats,
.id = "covariate")
table
# A tibble: 3 × 5
covariate n mean sd se
<chr> <int> <dbl> <dbl> <dbl>
1 x 16 4.75 1.88 0.47
2 y 18 2.11 0.676 0.159
3 z 17 3.35 1.41 0.342
无效的代码:
但我正在努力弄清楚如何规范化变量。我最近的尝试是试试这个
summary_stats <- function(data){
data_norm <- drop_na(data) %>% dplyr::summarize(
(as.numeric(data) - min(as.numeric(data))) /
(max(as.numeric(data)) - min(as.numeric(data)))
)
tibble(
n = sum(!is.na(data_norm)),
mean = round(mean(as.numeric(data_norm), na.rm = T), digits = 3),
sd = round(sd(as.numeric(data_norm), na.rm = T), digits = 3),
se = round(sd/sqrt(n), digits = 3)
)
}
table <- map_df(
df %>%
dplyr::select(vars),
summary_stats,
.id = "covariate")
错误:
但是这个returns错误
Error in UseMethod("drop_na_") : no applicable method for 'drop_na_' applied to an object of class "factor"
如果我即时将它转换为数字,所以我有 data_norm <- drop_na(as.numeric(data))
等,然后我得到一个非常相似的错误说
Error in UseMethod("drop_na_") : no applicable method for 'drop_na_' applied to an object of class "c('double', 'numeric')"
但是,如果我在函数之外执行此操作,它会正常工作
df %>% drop_na(x) %>% summarise(std_mean = (as.numeric(x) - min(as.numeric(x))) / (max(as.numeric(x)) - min(as.numeric(x))))
# A tibble: 16 × 1
std_mean
<dbl>
1 0.857
2 0.429
3 0.714
4 0.714
5 0.143
6 0.286
7 0.571
....
我需要删除 NA 值,或者当我尝试规范化返回的变量时,如果该列中至少有 1 个 NA,则返回的变量将全部为 NA。如果我在函数外应用 drop_na()
(我输入到 map_dfr
函数的主标题),它将删除 df 的任何变量中至少有 1 个 NA 值的任何行,而不是不仅仅是该列中的 NA 值。
有人可以帮忙吗?
更新:
如果我从函数中删除 drop_na()
调用,我会收到以下错误
Error in UseMethod("summarise") :
no applicable method for 'summarise' applied to an object of class "c('double', 'numeric')"
这对我来说毫无意义(我可能不理解)因为总结绝对适用于数字变量...
看起来你正在尝试编写一个函数来将整个数据框作为参数,但是当你去映射它时,你实际上只传递了一个向量(例如 df$x
) 作为函数的参数。这对于您的函数的第一个版本工作正常,但在第二个版本中 drop_na
无法工作,因为它需要一个 entire data frame for an argument。 summarize
也是如此,这就是您遇到类似错误的原因。它也可以在您的函数之外工作,因为您可以指定单个向量。
所以,我所做的是将 drop_na
换成 na_omit
,并且稍微重新组织了您的代码。
首先,让我们定义一个单独的 std_mean
函数,这样我们就不必处理 summarize
:
std_mean <- function(x){
x <- na.omit(x)
(as.numeric(x) - min(as.numeric(x)))/(max(as.numeric(x)) - min(as.numeric(x)))
}
现在我们可以返回并修复您的原始功能:
summary_stats <- function(vec){
data_norm <- std_mean(vec)
n = length(data_norm)
sd = round(sd(as.numeric(data_norm), na.rm = T), digits = 3)
data.frame(
n = n,
mean = round(mean(as.numeric(data_norm), na.rm = T), digits = 3),
sd = sd,
se = round(sd/sqrt(n), digits = 3)
)
}
我们必须事先定义 n
和 sd
,因为它们被用作数据框其他列的参数。虽然 data.frame
计算第一列然后允许您输入后面的列会很酷,但事实并非如此。
现在我们准备好映射了:
map(df[vars],summary_stats)
$x
n mean sd se
1 16 0.536 0.269 0.067
$y
n mean sd se
1 18 0.556 0.338 0.08
$z
n mean sd se
1 17 0.588 0.353 0.086
玩具资料:
假设我有这个 df
df <- structure(list(x = structure(c(NA, 7L, NA, NA, 4L, 6L, 6L, 2L,
3L, 5L, 8L, 4L, 7L, 3L, 5L, 1L, 5L, 5L, 5L, NA), .Label = c("1",
"2", "3", "4", "5", "6", "7", "8"), class = "factor"), y = structure(c(NA,
2L, 3L, 2L, 2L, 2L, 2L, 1L, 3L, NA, 2L, 3L, 1L, 1L, 3L, 2L, 2L,
3L, 2L, 2L), .Label = c("1", "2", "3"), class = "factor"), z = structure(c(NA,
4L, 4L, 4L, 5L, 4L, 5L, 5L, 2L, NA, 4L, 1L, 1L, 3L, 2L, 5L, 2L,
2L, 4L, NA), .Label = c("1", "2", "3", "4", "5"), class = "factor"),
a = c(-32L, -51L, -22L, 44L, 55L, -24L, -50L, 67L, 1L, -47L,
66L, -98L, -91L, -42L, -89L, -31L, -8L, -33L, 38L, 61L),
b = c(46L, -19L, -37L, 47L, -28L, -48L, 14L, -10L, -13L,
-31L, 32L, 21L, -21L, 25L, -8L, 42L, -26L, -24L, 36L, -39L
)), row.names = c(NA, -20L), class = c("tbl_df", "tbl", "data.frame"
))
df
# A tibble: 20 × 5
x y z a b
<fct> <fct> <fct> <int> <int>
1 NA NA NA -32 46
2 7 2 4 -51 -19
3 NA 3 4 -22 -37
4 NA 2 4 44 47
5 4 2 5 55 -28
6 6 2 4 -24 -48
7 6 2 5 -50 14
8 2 1 5 67 -10
9 3 3 2 1 -13
10 5 NA NA -47 -31
11 8 2 4 66 32
12 4 3 1 -98 21
13 7 1 1 -91 -21
14 3 1 3 -42 25
15 5 3 2 -89 -8
16 1 2 5 -31 42
17 5 2 2 -8 -26
18 5 3 2 -33 -24
19 5 2 4 38 36
20 NA 2 NA 61 -39
我想在 0-1 范围内对变量 x
、y
和 z
进行标准化,然后生成一些关于它们的摘要统计信息。我可以使用下面的代码生成摘要统计数据
有效代码:
library(tidyverse)
vars <- c('x', 'y', 'z')
names(vars) <- vars
summary_stats <- function(data){
tibble(
n = sum(!is.na(data)),
mean = round(mean(as.numeric(data), na.rm = T), digits = 3),
sd = round(sd(as.numeric(data), na.rm = T), digits = 3),
se = round(sd/sqrt(n), digits = 3)
)
}
table <- map_df(
df %>%
dplyr::select(vars),
summary_stats,
.id = "covariate")
table
# A tibble: 3 × 5
covariate n mean sd se
<chr> <int> <dbl> <dbl> <dbl>
1 x 16 4.75 1.88 0.47
2 y 18 2.11 0.676 0.159
3 z 17 3.35 1.41 0.342
无效的代码:
但我正在努力弄清楚如何规范化变量。我最近的尝试是试试这个
summary_stats <- function(data){
data_norm <- drop_na(data) %>% dplyr::summarize(
(as.numeric(data) - min(as.numeric(data))) /
(max(as.numeric(data)) - min(as.numeric(data)))
)
tibble(
n = sum(!is.na(data_norm)),
mean = round(mean(as.numeric(data_norm), na.rm = T), digits = 3),
sd = round(sd(as.numeric(data_norm), na.rm = T), digits = 3),
se = round(sd/sqrt(n), digits = 3)
)
}
table <- map_df(
df %>%
dplyr::select(vars),
summary_stats,
.id = "covariate")
错误:
但是这个returns错误
Error in UseMethod("drop_na_") : no applicable method for 'drop_na_' applied to an object of class "factor"
如果我即时将它转换为数字,所以我有 data_norm <- drop_na(as.numeric(data))
等,然后我得到一个非常相似的错误说
Error in UseMethod("drop_na_") : no applicable method for 'drop_na_' applied to an object of class "c('double', 'numeric')"
但是,如果我在函数之外执行此操作,它会正常工作
df %>% drop_na(x) %>% summarise(std_mean = (as.numeric(x) - min(as.numeric(x))) / (max(as.numeric(x)) - min(as.numeric(x))))
# A tibble: 16 × 1
std_mean
<dbl>
1 0.857
2 0.429
3 0.714
4 0.714
5 0.143
6 0.286
7 0.571
....
我需要删除 NA 值,或者当我尝试规范化返回的变量时,如果该列中至少有 1 个 NA,则返回的变量将全部为 NA。如果我在函数外应用 drop_na()
(我输入到 map_dfr
函数的主标题),它将删除 df 的任何变量中至少有 1 个 NA 值的任何行,而不是不仅仅是该列中的 NA 值。
有人可以帮忙吗?
更新:
如果我从函数中删除 drop_na()
调用,我会收到以下错误
Error in UseMethod("summarise") :
no applicable method for 'summarise' applied to an object of class "c('double', 'numeric')"
这对我来说毫无意义(我可能不理解)因为总结绝对适用于数字变量...
看起来你正在尝试编写一个函数来将整个数据框作为参数,但是当你去映射它时,你实际上只传递了一个向量(例如 df$x
) 作为函数的参数。这对于您的函数的第一个版本工作正常,但在第二个版本中 drop_na
无法工作,因为它需要一个 entire data frame for an argument。 summarize
也是如此,这就是您遇到类似错误的原因。它也可以在您的函数之外工作,因为您可以指定单个向量。
所以,我所做的是将 drop_na
换成 na_omit
,并且稍微重新组织了您的代码。
首先,让我们定义一个单独的 std_mean
函数,这样我们就不必处理 summarize
:
std_mean <- function(x){
x <- na.omit(x)
(as.numeric(x) - min(as.numeric(x)))/(max(as.numeric(x)) - min(as.numeric(x)))
}
现在我们可以返回并修复您的原始功能:
summary_stats <- function(vec){
data_norm <- std_mean(vec)
n = length(data_norm)
sd = round(sd(as.numeric(data_norm), na.rm = T), digits = 3)
data.frame(
n = n,
mean = round(mean(as.numeric(data_norm), na.rm = T), digits = 3),
sd = sd,
se = round(sd/sqrt(n), digits = 3)
)
}
我们必须事先定义 n
和 sd
,因为它们被用作数据框其他列的参数。虽然 data.frame
计算第一列然后允许您输入后面的列会很酷,但事实并非如此。
现在我们准备好映射了:
map(df[vars],summary_stats)
$x
n mean sd se
1 16 0.536 0.269 0.067
$y
n mean sd se
1 18 0.556 0.338 0.08
$z
n mean sd se
1 17 0.588 0.353 0.086