具有多个变量的用户定义函数? / 对一系列命名列进行操作的函数(而不是按数字索引)?

Posted

技术标签:

【中文标题】具有多个变量的用户定义函数? / 对一系列命名列进行操作的函数(而不是按数字索引)?【英文标题】:User-defined functions with multiple variables? / Function to operate on a range of named columns (instead of indexed by number)? 【发布时间】:2021-07-13 20:35:42 【问题描述】:

我经常想对数据框中的一组或一系列列执行函数。最常见的是,我想取共享一个公共前缀的一系列列的平均值(在这个玩具示例中,VarA.VarB.VarC.

ID<-c(1:300) #participant ID column, N=300
VarA.1<-sample(x = 0:50,size = 300, replace = TRUE)
VarA.2<-sample(x = 0:50,size = 300, replace = TRUE)
VarA.3<-sample(x = 0:50,size = 300, replace = TRUE)
VarB.1<-sample(x = 0:30,size = 300, replace = TRUE)
VarB.2<-sample(x = 0:30,size = 300, replace = TRUE)
VarB.3<-sample(x = 0:30,size = 300, replace = TRUE)
VarC.1<-sample(x = 0:10,size = 300, replace = TRUE)
VarC.2<-sample(x = 0:10,size = 300, replace = TRUE)
VarC.3<-sample(x = 0:10,size = 300, replace = TRUE)


df<-data.frame(ID,VarA.1,VarA.2,VarA.3,
               VarB.1,VarB.2,VarB.3,
               VarC.1,VarC.2,VarC.3) 
rm(ID,VarA.1,VarA.2,VarA.3,
   VarB.1,VarB.2,VarB.3,
   VarC.1,VarC.2,VarC.3)

我通常有一个 ton 变量,所以我无法记住列号。假设我想取以VarA. 开头的所有列的平均值,并将其放入一个名为VarA 的新列中。这是我通常的做法:

x<-which(colnames(df)=="VarA.1")
y<-which(colnames(df)=="VarA.3")
df$VarA<-rowMeans(df[, c(x:y)])

也许我太挑剔了,但考虑到我必须在某些脚本中这样做(或非常类似的事情)超过 20 次,它看起来真的很混乱和笨重,而且很难记住:我必须挖掘以前的文件,然后复制并粘贴并仔细更改所有值以适合我当前的数据集。我真的很想把它变成一个函数,但是我对用户定义的函数不是很熟悉,而且我很难弄清楚如何处理多个变量。

我尝试的方法是:

colmeans <- function(x,y,df,meancol) 
  first<-which(colnames(df)==x)
  last<-which(colnames(df)==y)
  df$meancol<-rowMeans(df[, c(first:last)])

colmeans("VarA.1","VarA.3",df,"VarA")

我本可以发誓它在某一时刻有效,但我失去了它,我不记得我改变了什么。我错过了什么?

我也愿意接受其他关于如何使这个过程更有效率的想法。

【问题讨论】:

【参考方案1】:

我们可以使用split.default

lst1 <- lapply(split.default(df[-1], sub("\\.\\d+$", "", names(df)[-1])),
         rowMeans, na.rm = TRUE)
df[paste0(names(lst1), "_Mean")] <- lst1

-输出

head(df, 3)
  ID VarA.1 VarA.2 VarA.3 VarB.1 VarB.2 VarB.3 VarC.1 VarC.2 VarC.3 VarA_Mean VarB_Mean VarC_Mean
1  1     25     40     27      6      9      2      3      1      0  30.66667  5.666667  1.333333
2  2     43     16     26     27      7      5      2     10      5  28.33333 13.000000  5.666667
3  3     14     34     38      9     10      7      3      9      9  28.66667  8.666667  7.000000

或使用tidyverse

library(dplyr)
library(tidyr)
df %>%
    pivot_longer(cols = -ID, names_to = ".value",
        names_pattern = "^([^.]+)\\.\\d+") %>% 
    group_by(ID) %>%
    summarise(across(everything(), mean, na.rm = TRUE, 
          .names = ".col_Mean"), .groups = 'drop') %>%
  left_join(df)

【讨论】:

【参考方案2】:

您是否正在寻找这样的解决方案?

library(dplyr)
df %>% 
  mutate(across(starts_with("VarA"), mean, .names = "mean_.col"))

输出:

+   head()
  ID VarA.1 VarA.2 VarA.3 VarB.1 VarB.2 VarB.3 VarC.1 VarC.2 VarC.3 mean_VarA.1 mean_VarA.2
1  1     41     37      7      0     14      1     10      7      0    23.97667    24.73667
2  2     50     36     20     16     29      7      0     10      9    23.97667    24.73667
3  3      2      5     43     20     24      9      5      8      8    23.97667    24.73667
4  4      9     39     41     15     21      5      9      6      3    23.97667    24.73667
5  5     38     25     37     20     19     24      6      5      4    23.97667    24.73667
6  6     12     27     47     28     14     14     10      5      2    23.97667    24.73667
  mean_VarA.3
1    26.16667
2    26.16667
3    26.16667
4    26.16667
5    26.16667
6    26.16667

【讨论】:

以上是关于具有多个变量的用户定义函数? / 对一系列命名列进行操作的函数(而不是按数字索引)?的主要内容,如果未能解决你的问题,请参考以下文章

转换为具有水平显示和重命名列的多索引数据框

如何从多个 .csv 文件中的命名列中选择唯一值?

在 sklearn 和命名列中对多个列进行 One-hot-encoding

PostgreSQL - 使用函数在选择查询中命名列

R数据框用随机样本数据填充命名列

如何使用dplyr重命名列,其中新列名和原始列名都是变量[duplicate]