将模型拟合到多个分组或子集,并提取数据框输出的原始因子列

时间:2015-08-20 13:10:47

标签: r apply

我想拟合模型并提取由分组因子(下面的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])

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)