dplyr 汇总用户定义函数的多个输入值
dplyr summarise for multiple input values for a user defined function
我有一个数据框 df
,我想确定 col1
中满足 col2
.
条件的唯一值的比例
set.seed(137)
df <- data.frame(col1 = sample(LETTERS, 100, TRUE),
col2 = sample(-75:75, 100, TRUE),
col3 = sample(-75:75, 100, TRUE))
df$col2[c(23, 48, 78)] <- NA
df$col3[c(37, 68, 81)] <- NA
例如,我想在 col1
中找到所有唯一值,这些值在 col2
中的值在 -10
到 10
范围内。
df %>%
mutate(unqCol1 = n_distinct(col1)) %>%
group_by(col1) %>%
mutate(freq = sum(between(col2, -10, 10), na.rm = TRUE)) %>%
filter(freq > 0) %>% distinct(col1, unqCol1) %>%
ungroup() %>%
summarise(nrow(.)/unqCol1) %>%
unique()
这导致:
# A tibble: 1 x 1
`nrow(.)/unqCol1`
<dbl>
1 0.423
虽然上面的代码片段不是一种有效的方法,但我尝试在单个管道命令中获得结果,它为我提供了正确的输出(重写上述代码的任何巧妙方法都非常值得赞赏)。我已经使用基本 R 方法重新确认了输出:
length(unique(df$col1[df$col2 >= -10 & df$col2 <= 10 & !is.na(df$col2)]))/length(unique(df$col1))
我想在一个函数中重写上面的 dplyr 代码,以便可以使用多个 n 值(此处:n=10
)复制该范围(也适用于多列)。这可能吗?或者我应该在代码本身(没有函数)中传递多个值,比如 apply-family idea?
如您所见,您的 (dplyr) 代码过于复杂。您可以在不对数据分组的情况下计算感兴趣的比例:
df %>%
tidyr::drop_na() %>%
filter(between(col2, -10, 10)) %>%
summarize(prop = n_distinct(col1) / n_distinct(df$col1))
一个计算比例的函数是:
my_summary <- function(df, ...) {
df %>%
tidyr::drop_na() %>%
filter(...) %>%
summarize(
prop = n_distinct(col1) / n_distinct(df$col1)
)
}
例如
> my_summary(df, between(col2, -10, 10))
prop
1 0.4230769
给出你问题中的比例。
编辑
您可以矢量化 my_summary()
并使用 outer()
获得 col
和 n
:
组合的比例矩阵
my_summary <- function(col, n) {
df %>%
tidyr::drop_na() %>%
filter(between(!!as.name(col), -n, n)) %>%
summarize(
prop = n_distinct(col1) / n_distinct(df$col1)
)
}
my_summary_v <- Vectorize(my_summary)
> outer(c("col2", "col3"), c(10, 20, 30), my_summary_v)
[,1] [,2] [,3]
[1,] 0.4230769 0.5384615 0.6538462
[2,] 0.4230769 0.6538462 0.6923077
我有一个数据框 df
,我想确定 col1
中满足 col2
.
set.seed(137)
df <- data.frame(col1 = sample(LETTERS, 100, TRUE),
col2 = sample(-75:75, 100, TRUE),
col3 = sample(-75:75, 100, TRUE))
df$col2[c(23, 48, 78)] <- NA
df$col3[c(37, 68, 81)] <- NA
例如,我想在 col1
中找到所有唯一值,这些值在 col2
中的值在 -10
到 10
范围内。
df %>%
mutate(unqCol1 = n_distinct(col1)) %>%
group_by(col1) %>%
mutate(freq = sum(between(col2, -10, 10), na.rm = TRUE)) %>%
filter(freq > 0) %>% distinct(col1, unqCol1) %>%
ungroup() %>%
summarise(nrow(.)/unqCol1) %>%
unique()
这导致:
# A tibble: 1 x 1
`nrow(.)/unqCol1`
<dbl>
1 0.423
虽然上面的代码片段不是一种有效的方法,但我尝试在单个管道命令中获得结果,它为我提供了正确的输出(重写上述代码的任何巧妙方法都非常值得赞赏)。我已经使用基本 R 方法重新确认了输出:
length(unique(df$col1[df$col2 >= -10 & df$col2 <= 10 & !is.na(df$col2)]))/length(unique(df$col1))
我想在一个函数中重写上面的 dplyr 代码,以便可以使用多个 n 值(此处:n=10
)复制该范围(也适用于多列)。这可能吗?或者我应该在代码本身(没有函数)中传递多个值,比如 apply-family idea?
如您所见,您的 (dplyr) 代码过于复杂。您可以在不对数据分组的情况下计算感兴趣的比例:
df %>%
tidyr::drop_na() %>%
filter(between(col2, -10, 10)) %>%
summarize(prop = n_distinct(col1) / n_distinct(df$col1))
一个计算比例的函数是:
my_summary <- function(df, ...) {
df %>%
tidyr::drop_na() %>%
filter(...) %>%
summarize(
prop = n_distinct(col1) / n_distinct(df$col1)
)
}
例如
> my_summary(df, between(col2, -10, 10))
prop
1 0.4230769
给出你问题中的比例。
编辑
您可以矢量化 my_summary()
并使用 outer()
获得 col
和 n
:
my_summary <- function(col, n) {
df %>%
tidyr::drop_na() %>%
filter(between(!!as.name(col), -n, n)) %>%
summarize(
prop = n_distinct(col1) / n_distinct(df$col1)
)
}
my_summary_v <- Vectorize(my_summary)
> outer(c("col2", "col3"), c(10, 20, 30), my_summary_v)
[,1] [,2] [,3]
[1,] 0.4230769 0.5384615 0.6538462
[2,] 0.4230769 0.6538462 0.6923077