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