在数据框

时间:2017-03-09 15:56:52

标签: r for-loop subset apply linear-regression

我想创建一个函数(最好带有apply族函数,它在数据框中两个独立变量的数据子集上运行lm函数。作为参考,我的数据是目前的结构如下(这是一个虚拟数据框,通常代表我正在使用的实际数据框):

District = c(rep("A", times = 25),
             rep("B", times = 25),
             rep("C", times = 25),
             rep("D", times = 25))

Year = c(1971:1975, 1971:1975, 1971:1975, 1971:1975,
         1971:1975, 1971:1975, 1971:1975, 1971:1975,
         1971:1975, 1971:1975, 1971:1975, 1971:1975,
         1971:1975, 1971:1975, 1971:1975, 1971:1975,
         1971:1975, 1971:1975, 1971:1975, 1971:1975)

Crop = c(rep("Wheat",  times = 5),
         rep("Maize",  times = 5),
         rep("Rice",   times = 5),
         rep("Barley", times = 5))

set.seed(100)
Yield = rnorm(100, 2, 0.5)

df <- data.frame(District, Year, Crop, Yield)

我需要生成一个线性模型(lm),预测Yield作为Year的函数,每个Crop基于District。所以,我需要每个地区的小麦模型,每个地区的大麦,等等。我需要尽可能地自动化这个,因为我的真实数据将产生大约7000个线性模型。

this answer James Bond发现enter image description here作为出发点非常有帮助。它非常优雅并且使用lapply,如果可能的话我也想做(7000线性模型=非常慢)。但是,它只是在数据集中对SINGLE列进行子集化,而我需要为每个模型子集两个变量。这是我当前(非工作)代码修改为在上面的虚拟数据集上运行:

df$Dist <- as.factor(df$Dist)
df$Crop <- as.factor(df$Crop)

for (i in 1:length(levels(df$Crop))) {
  x <- levels(df$Crop)[i]
  dat <- df[df$Crop == x, ]
  out <- lapply(levels(dat$Dist), function(z) {
            data.frame(District = z, 
                       Slope = lm(Yield ~ Year, data = dat[dat$Dist == z, ])$coef[2], 
                       Crop = x,
                       row.names=NULL)
  })
}

do.call(rbind ,out)

不幸的是,运行上面的代码只会为数据集(Wheat)中的第一个Crop级别生成一个模型。请参阅以下输出:

  District       Slope  Crop
1        A  0.03125866 Wheat
2        B -0.08108222 Wheat
3        C  0.17172314 Wheat
4        D -0.11278486 Wheat

我们非常感谢能够遍历CropDistrict变量的任何帮助。看起来我很接近,但似乎错过了关于for循环的一些基本信息。

如果可以将2个参数传递给lapply函数并完全避免for循环,那将是惊人的。提前谢谢!

1 个答案:

答案 0 :(得分:2)

使用 dplyr 的一个选项:

df_lm <- df %>%
  group_by(District,Crop) %>%
  do(mod = lm(Yield ~ Year,data = .))

df_coef <- df_lm %>%
  do(data.frame(
    District = .$District,
    Crop = .$Crop,
    var = names(coef(.$mod)),
    coef(summary(.$mod)))
    )

> df_coef
Source: local data frame [32 x 7]
Groups: <by row>

# A tibble: 32 × 7
   District   Crop         var      Estimate   Std..Error    t.value   Pr...t..
*    <fctr> <fctr>      <fctr>         <dbl>        <dbl>      <dbl>      <dbl>
1         A Barley (Intercept) -407.66953514 378.49788671 -1.0770722 0.36034462
2         A Barley        Year    0.20771336   0.19183872  1.0827499 0.35818046
3         A  Maize (Intercept)  159.81133118 212.90233600  0.7506321 0.50738515
4         A  Maize        Year   -0.08002266   0.10790790 -0.7415830 0.51211787
5         A   Rice (Intercept)  -68.01125454 117.60578244 -0.5782986 0.60361684
6         A   Rice        Year    0.03552764   0.05960758  0.5960255 0.59313364
7         A  Wheat (Intercept)  -59.61828825 134.67806297 -0.4426726 0.66972726
8         A  Wheat        Year    0.03125866   0.06826053  0.4579317 0.65918309
9         B Barley (Intercept) -319.99755207  57.14553545 -5.5996947 0.01125215
10        B Barley        Year    0.16332436   0.02896377  5.6389189 0.01103509
# ... with 22 more rows

另一件需要注意的是 nlme 中的lmList功能。