我想拟合模型并提取由分组因子(下面的fac1和fac2)或子集分割的特定参数。我的问题是,当sapply输出正确的参数时,我会遇到一个列表,其中元素被命名为组合。我想得到的是一个data.frame,其中每个因子都有一个列,并带有相应的标签。我想在基础R 中执行此操作。
请注意,答案必须是一般,而不是本案例中使用的特定名称。如果因素名称包括“期间”,则答案不应受到阻碍。'我最终会使用任何数据制作一些东西,所以这个答案需要这样做,并且还有许多因素。我实际上是在一个更大的数据集上使用自定义函数,但这个例子代表了我的问题。
以下是可重现的代码:
#create data
fac1 <- c(rep("A", 10), rep("B",10))
fac2 <- rep(c(rep("X", 5), rep("Y",5)),2)
x <- rep(1:5,4)
set.seed(1337)
y <- rep(seq(2, 10, 2), 4) * runif(20, .8, 1.2)
xy <- data.frame(x,y) #bind parameters for regression
factors <- list(fac1, fac2) #split by 2 factors
sapply(split(xy, factors), function(c) coef(lm(c$y~c$x))[2])
#run regression by these 4 groups, pull out slope
输出结果为:
A.X.c$x B.X.c$x A.Y.c$x B.Y.c$x
1.861290 2.131431 1.590733 1.746169
我想要的是:
fac1 fac2 slope
A X 1.861290
B X 2.131431
A Y 1.590733
B Y 1.746169
以下代码可能会更加通用以实现此目的,但我担心expand.grid会进行所有可能的组合但用户在数据中缺少组合的情况,以及订单是否会保持原样。 expand.grid是否使用类似的方法,但是拆分子集确定返回值的顺序的数据?
slopes <- sapply(split(xy, factors), function(c) coef(lm(c$y~c$x))[2])
dataframeplz <- as.data.frame(expand.grid(unique(fac1), unique(fac2)))
dataframeplz$slope <- slopes
dataframeplz
如果有帮助,这是 plyr 解决方案。它很容易,但不是基础R.任何人都知道哈德利的代码在哪里发生这种魔力? Githubbers?
library("plyr")
neatdata <- data.frame(fac1,fac2,x,y)
ddply(neatdata, c("fac1", "fac2"), function(c) coef(lm(c$y~c$x))[2])
答案 0 :(得分:1)
对于基数R,aggregate
是用于此类情况的用户友好函数。
aggregate(cbind(slope=1:nrow(xy))~fac1+fac2,FUN=function(r) coef(lm(y~x,data=xy[r,]))[2])
fac1 fac2 slope 1 A X 1.861290 2 B X 2.131431 3 A Y 1.590733 4 B Y 1.746169
这也可以通过by
以与原作相似的方式完成。
setNames(as.data.frame.table(
by(xy,list(fac1,fac2),FUN=function(c) coef(lm(c$y~c$x))[2])),
c("fac1","fac2","slope"))
答案 1 :(得分:1)
一个。 Webb的答案更优雅,但这种lapply/arbitrary function/do.call/rbind
工作流程多年来一直是我这种事情的最后手段:
# Move the factors inside your data frame, so they'll be available after the split()
xy <- data.frame(x, y, fac1, fac2)
# Iterate over the split
reglist <- lapply(split(xy, factors), FUN = function(group) {
# Get the current factor levels
group_levels <- unique(group[c("fac1", "fac2")])
# Mash it all into a data.frame
data.frame(group_levels, slope = coef(lm(y ~ x, data = group))[2])
})
# Collapse the list into a data.frame
do.call("rbind", reglist)