R 将多个函数应用于数据帧的每一行
每次我想我理解了如何使用向量时,一个看似简单的问题就会让我头晕目眩。在这个场合,大量的阅读和尝试不同的例子并没有起到任何作用。请用勺子喂我 我想对数据帧的每一行应用两个自定义函数,并将结果添加为两个新列。以下是我的示例代码:R 将多个函数应用于数据帧的每一行,r,transform,rows,dataframe,apply,R,Transform,Rows,Dataframe,Apply,每次我想我理解了如何使用向量时,一个看似简单的问题就会让我头晕目眩。在这个场合,大量的阅读和尝试不同的例子并没有起到任何作用。请用勺子喂我 我想对数据帧的每一行应用两个自定义函数,并将结果添加为两个新列。以下是我的示例代码: # Required packages: library(plyr) FindMFE <- function(x) { MFE <- max(x, na.rm = TRUE) MFE <- ifelse(is.infinite(MFE
# Required packages:
library(plyr)
FindMFE <- function(x) {
MFE <- max(x, na.rm = TRUE)
MFE <- ifelse(is.infinite(MFE ) | (MFE < 0), 0, MFE)
return(MFE)
}
FindMAE <- function(x) {
MAE <- min(x, na.rm = TRUE)
MAE <- ifelse(is.infinite(MAE) | (MAE> 0), 0, MAE)
return(MAE)
}
FindMAEandMFE <- function(x){
# I know this next line is wrong...
z <- apply(x, 1, FindMFE, FindMFE)
return(z)
}
df1 <- data.frame(Bar1=c(1,2,3,-3,-2,-1),Bar2=c(3,1,3,-2,-3,-1))
df1 = transform(df1,
FindMAEandMFE(df1)
)
#DF1 should end up with the following data...
#Bar1 Bar2 MFE MAE
#1 3 3 0
#2 1 2 0
#3 3 3 0
#-3 -2 0 -3
#-2 -3 0 -3
#-1 -1 0 -1
#所需软件包:
图书馆(plyr)
FindMFE我认为你在这里的想法太复杂了。两个单独的apply()
调用有什么问题?但是,有一种更好的方法来完成您在这里所做的工作,它不涉及循环/应用调用。我将分别处理这些问题,但第二种解决方案更可取,因为它是真正矢量化的
两个应用调用版本
使用所有基本R函数的前两个单独的apply调用:
df1 <- data.frame(Bar1=c(1,2,3,-3,-2,-1),Bar2=c(3,1,3,-2,-3,-1))
df1 <- transform(df1, MFE = apply(df1, 1, FindMFE), MAE = apply(df1, 1, FindMAE))
df1
好的,在df1
行上循环两次可能有点低效,但即使对于大问题,您已经花了更多的时间考虑在一次过程中巧妙地完成这项工作,而不是通过这种方式节省时间
使用矢量化函数pmax()
和pmin()
因此,更好的方法是注意pmax()
和pmin()
函数,并意识到它们可以做应用的每一个调用(df1,1,FindFOO()
所做的事情。例如:
> (tmp <- with(df1, pmax(0, Bar1, Bar2, na.rm = TRUE)))
[1] 3 2 3 0 0 0
使用pmax()
和pmin()
获得通用解决方案的诀窍是使用do.call()
为我们安排对这两个函数的调用。更新您的函数以使用我们的想法:
FindMFE2 <- function(x) {
MFE <- do.call(pmax, c(as.list(x), 0, na.rm = TRUE))
MFE[is.infinite(MFE)] <- 0
MFE
}
FindMAE2 <- function(x) {
MAE <- do.call(pmin, c(as.list(x), 0, na.rm = TRUE))
MAE[is.infinite(MAE)] <- 0
MAE
}
而且看不到一个apply()
。如果您想在一个步骤中完成此操作,现在包装起来就容易多了:
FindMAEandMFE2 <- function(x){
cbind(MFE = FindMFE2(x), MAE = FindMAE2(x))
}
如果你真的非常想要它,你可以:
FindMAEandMFE <- function(x){
t(apply(x, 1, function(currow){c(MAE=FindMAE(currow), MFE=FindMFE(currow))}))
}
FindMAEandMFE我展示了三种可选的一行程序:
- 使用
plyr的each
功能
- 将
plyr
每个功能与基本R一起使用
- 使用向量化的
pmin
和pmax
功能
解决方案1:plyr和每个
plyr
软件包定义了满足您需要的每个功能。从?每个:将多个功能聚合为一个函数。这意味着您可以使用一个线性函数解决问题:
library(plyr)
adply(df1, 1, each(MAE=function(x)max(x, 0), MFE=function(x)min(x, 0)))
Bar1 Bar2 MAE MFE
1 1 3 3 0
2 2 1 2 0
3 3 3 3 0
4 -3 -2 0 -3
5 -2 -3 0 -3
6 -1 -1 0 -1
transform(df1, MFE=pmax(0, Bar1, Bar2), MAE=pmin(0, Bar1, Bar2))
Bar1 Bar2 MFE MAE
1 1 3 3 0
2 2 1 2 0
3 3 3 3 0
4 -3 -2 0 -3
5 -2 -3 0 -3
6 -1 -1 0 -1
解决方案2:每个和基本R
当然,您可以将每个
与基本函数一起使用。以下是如何将其与应用
一起使用-只需注意,在添加到原始data.frame之前,您必须转置结果
library(plyr)
data.frame(df1,
t(apply(df1, 1, each(MAE=function(x)max(x, 0), MFE=function(x)min(x, 0)))))
Bar1 Bar2 MAE MFE
1 1 3 3 0
2 2 1 2 0
3 3 3 3 0
4 -3 -2 0 -3
5 -2 -3 0 -3
6 -1 -1 0 -1
解决方案3:使用矢量化函数
使用矢量化函数pmin
和pmax
,您可以使用以下一个线性函数:
library(plyr)
adply(df1, 1, each(MAE=function(x)max(x, 0), MFE=function(x)min(x, 0)))
Bar1 Bar2 MAE MFE
1 1 3 3 0
2 2 1 2 0
3 3 3 3 0
4 -3 -2 0 -3
5 -2 -3 0 -3
6 -1 -1 0 -1
transform(df1, MFE=pmax(0, Bar1, Bar2), MAE=pmin(0, Bar1, Bar2))
Bar1 Bar2 MFE MAE
1 1 3 3 0
2 2 1 2 0
3 3 3 3 0
4 -3 -2 0 -3
5 -2 -3 0 -3
6 -1 -1 0 -1
这里有很多很好的答案。我是在Gavin Simpson编辑时开始的,所以我们讨论了一些类似的问题。平行的最小值和最大值(pmin和pmax)正是你编写函数的目的。0在pmax中的作用可能有点模糊(0,Bar1,Bar2)但本质上0被回收,所以这就像
pmax(c(0,0,0,0,0,0), Bar1, Bar2)
这将获取传递的三件事中的每一项,并找到它们的最大值。因此,如果它是负数,则最大值将为0,并完成ifelse语句所做的大部分工作。您可以重写,以便获得向量,并将其与您所做的类似的函数相结合,这可能会使它更透明。在本例中,我们将只需将数据帧传递给一个新的并行快速findMFE函数,该函数将处理任何数字数据帧并得到一个向量
findMFE <- function(dataf){
MFE <- do.call( pmax, c(dataf, 0, na.rm = TRUE))
}
MFE <- findMFE(df1)
findMFE只是展示了这一点。你在pmin/max colls中的0得到额外的加分。我在df1中允许任何数量的列得到额外的加分:P@GavinSimpson我修改后的答案显示了解决问题的三种可选(一行)方法,其中两种方法允许任意数量的列。现在你只是在炫耀!;-)美好的解决方案1和2会很慢(在大问题上会慢),我们可能不应该鼓励使用非矢量化的解决方案而不是矢量化的解决方案。但尚不清楚OP是想要一个多变量应用的通用解决方案还是这个特定问题的解决方案。所以我会让免费的plyr使用通过这一次;-)我想要多元解。哇,请原谅,我正在消化所有这些令人惊讶的帮助,我会尽快回复大家。+1完成plyr()方面的工作。谢谢你!我三个都试过了,加文很在行。使用我的实际数据(100c x 23000r)和一个稍微复杂一些的过程(通过增量添加列循环),每个过程的速度是:do.call(Gavin)是29秒,解决方案2是105秒,解决方案1…仍在等待。因此,在这种情况下,plyr()库不是最好的解决方案。我将继续测试。我接受了挑战,并在修改后的答案中提供了使用plyr
和正常min
和max
函数的一行解决方案。谢谢John。额外0列的描述很有用,解释ifelse()的最佳用法仍在研究中;循环Vs整体。我希望有一天能将这些优惠返还给所有人或“转发”。@LookLeft-关于您的编辑,我相当肯定Gavin的矢量化pmin
,pmax
解决方案将处理任何列数和名称的数据帧。但我只是在猜测你这里所说的“多元”是什么意思。使用do.call的循环问题和一般解决方案非常有见地。我开始更多地了解向量以及R函数处理向量的方式。我将继续玩每个例子。@joran。是的,编辑是对加文的评论和回答的回应。他发现了局限性并给出了一个很好的答案。谢谢,我将坚持加文的建议。
transform(df1, MFE=pmax(0, Bar1, Bar2), MAE=pmin(0, Bar1, Bar2))
Bar1 Bar2 MFE MAE
1 1 3 3 0
2 2 1 2 0
3 3 3 3 0
4 -3 -2 0 -3
5 -2 -3 0 -3
6 -1 -1 0 -1
pmax(c(0,0,0,0,0,0), Bar1, Bar2)
findMFE <- function(dataf){
MFE <- do.call( pmax, c(dataf, 0, na.rm = TRUE))
}
MFE <- findMFE(df1)
findMFE <- function(dataf){
MFE <- do.call( pmax, c(dataf, 0, na.rm = TRUE))
ifelse(is.infinite(MFE), 0, MFE)
}
findMAE <- function(dataf){
MAE <- do.call( pmin, c(dataf, 0, na.rm = TRUE))
ifelse(is.infinite(MAE), 0, MAE)
}
findMFEandMAE <- function(dataf){
MFE <- findMFE(dataf)
MAE <- findMAE(dataf)
return(data.frame(MFE, MAE))
}