如何编写一个 R 函数,让我使用 dplyr 的 %>% 管道操作多个 R 变量?



我正试图创建一个函数来处理不同的数据集,但在执行此任务时遇到了一些问题。我在下面的dput((输出中提供了我试图操作的数据的简化版本:

structure(list(id = structure(c(2, 4, 6, 8, 10), label = "iid", format.spss = "F4.0", display_width = 0L), A = c(13, 9, 14, 14, 13), B = c(12, 0, 9, 3, 10), C = c(13, 8, 14, 13, 11)), row.names = c(NA, -5L), class = c("tbl_df", "tbl", "data.frame"))

我正在尝试做几件事,但由于数据的格式化方式,我在不同的时刻遇到了困难。首先,我需要将每行的列A:D中的值相加为一个名为total的变量。接下来,我需要通过将每个列A:D除以total来计算概率。

这是我面临的一些问题。我写了一个函数来执行上述操作:

functa <- function(x, id, vars) {

x %>%
mutate(total = rowSums(.[vars])) %>%
mutate(prob = .[vars]/total)
}

当我使用以下行调用函数时:

test <- functa(df_ED, "pid", c("A", "B", "C", "D"))

我得到一个有5个观测值的物体,但只有7个变量(而不是10个(。当我检查对象时,我会看到4个新变量(即prob.A、prob.B、prob.C、prob.D(,但它们是作为单个变量读取的。

因此,我想在此数据集上执行的任何后续操作都无法按预期进行。在过去的两天里,我一直在研究这一问题,但找不到任何关于这一现象的信息,我猜我有点不知所措。

我这个功能的最终目标是:

  1. 计算total变量(a:D之和(
  2. 计算一个prob变量,该变量应输出4个变量(即a/total、B/total等(
  3. 重新编码prob变量,使得所有无穷大的值(即"Inf"(被重新编码为0
  4. 将所有4个prob变量相加为一个totalprob变量

如有任何见解,不胜感激!

当您想将函数应用于多列时,请使用across:

library(dplyr)
functa <- function(x, id, vars) {

x %>%
#sum all vars column
mutate(total = rowSums(.[vars]),
#Divide vars column with total and create new columns with prob
across(all_of(vars), ~./total, .names = '{col}_prob'), 
#Replace infinite value in prob column with 0
across(ends_with('_prob'), ~replace(., is.infinite(.), 0))) %>%
#Sum all prob columns. 
mutate(totalprob = rowSums(select(., ends_with('prob'))))      

}
functa(df_ED, "pid", c("A", "B", "C"))
#     id     A     B     C total A_prob B_prob C_prob totalprob
#  <dbl> <dbl> <dbl> <dbl> <dbl>  <dbl>  <dbl>  <dbl>     <dbl>
#1     2    13    12    13    38  0.342  0.316  0.342         1
#2     4     9     0     8    17  0.529  0      0.471         1
#3     6    14     9    14    37  0.378  0.243  0.378         1
#4     8    14     3    13    30  0.467  0.1    0.433         1
#5    10    13    10    11    34  0.382  0.294  0.324         1

另一种解决方案是更改表的布局,在第一步中使用pivot_longer计算概率,在下一步使用pivot_wider获得所需的最终布局。

> df %>% 
+   pivot_longer(-id, names_to = "key", values_to = "value") %>%
+   group_by(id) %>%
+   mutate(prob = value / sum(value)) %>%
+   pivot_wider(names_from = key, values_from = c(value, prob))
# A tibble: 5 x 7
# Groups:   id [5]
id value_A value_B value_C prob_A prob_B prob_C
<dbl>   <dbl>   <dbl>   <dbl>  <dbl>  <dbl>  <dbl>
1     2      13      12      13  0.342  0.316  0.342
2     4       9       0       8  0.529  0      0.471
3     6      14       9      14  0.378  0.243  0.378
4     8      14       3      13  0.467  0.1    0.433
5    10      13      10      11  0.382  0.294  0.324

最新更新