【问题标题】:lm in R: Workaround for 'contrasts' errorR中的lm:“对比度”错误的解决方法
【发布时间】:2015-05-23 05:08:07
【问题描述】:

我正在使用大量数据(5000 万行)和 biglm 包创建一个线性模型。这是通过首先基于数据块创建线性模型,然后通过读取更多数据块(100 万行)并使用“biglm”中的“更新”函数来更新模型来完成的。我的模型使用年份(具有 20 个级别的因子)、温度和一个名为 is_paid 的 1 或 0 因子变量。代码如下所示:

model = biglm(output~year:is_paid+temp,data = df) #creates my original model from a starting data frame, df
newdata = file[i] #This is just an example of me getting a new chunk of data in; don't worry about it
model = update(model,data = newdata) #this is where the update to the new model with the new data happens

问题是is_paid因子变量几乎总是0。所以有时候我读入一大块数据时,is_paid列中的每个值都是0,我显然得到以下错误:

Error in `contrasts<-`(`*tmp*`, value = contr.funs[1 + isOF[nn]]) : 
contrasts can be applied only to factors with 2 or more levels

所以基本上,我需要一种方法让模型接受更新,而不会因为新数据块中没有两个不同的因素而生气。

我正在考虑这样做的一种方法是始终将一行真实数据的 is_paid 值为“1”,并将其添加到新块中。这样,有不止一种因素,我还在添加真实数据。代码看起来像这样:

#the variable 'line' is a single line of data that has a '1' for is_paid
newdata = file[i] #again, an example of me reading in a new chunk of data. I know that this doesn't make sense by itself
newdata = rbind(line,newdata) #add in the sample line with '1' in is_paid to newdata
model = update(model,newdata) #update the data

这是我的数据示例:

output  year    temp is_paid
1100518     12     40   0
2104518     12     29   0   
1100200     15     17   0   
1245110     16     18   0 
5103128     14     30   0 

这是我的示例行的示例,它是 is_paid 为 1 的真实记录:

output  year temp is_paid
31200599 12  49     1

在同一行中一遍又一遍地添加会扭曲我为变量获得的系数吗?我在一些虚拟代码上进行了测试,它看起来并不像一遍又一遍地更新具有相同记录的模型会影响它,但我很怀疑。

我觉得有一种更优雅、更智能的方法可以做到这一点。我一直在阅读 R 教程,似乎有一种方法可以为 lm 模型设置对比度。我查看了“lm”中的“对比”论点,但什么也想不通。我不认为你可以在 biglm 中设置对比度,这是我需要使用的。我非常感谢你们能想到的任何见解或解决方案。

*is_paid 的数值变量与因子变量的比较:

df.num = data.frame(a = c(1:10),b = as.factor(rep(c(1,2,3,4,5),each = 2)),c = c(rep(0,each = 5),rep(1,each = 5)))
df.factor = data.frame(a = c(1:10),b = as.factor(rep(c(1,2,3,4,5),each = 2)),c = as.factor(c(rep(0,each = 5),rep(1,each = 5))))

mod.factor = lm(a~b:c,data = df.factor)
mod.num = lm(a~b:c,data = df.num)

> mod.factor

Call:
lm(formula = a ~ b:c, data = df.factor)
Coefficients:
(Intercept)        b1:c0        b2:c0        b3:c0        b4:c0        b5:c0        b1:c1  
    9.5         -8.0         -6.0         -4.5           NA           NA           NA  
  b2:c1        b3:c1        b4:c1        b5:c1  
     NA         -3.5         -2.0           NA  


 Call:
 lm(formula = a ~ b:c, data = df.num)

Coefficients:
(Intercept)         b1:c         b2:c         b3:c         b4:c         b5:c  
    3.0           NA           NA          3.0          4.5          6.5  

这里的结论是,如果 is_paid 是数字,模型就改变了。

****我还稍微编辑了我的模型,以查看两个因素的相互作用,而不仅仅是三个变量。这意味着我不能将 is_paid 视为数字(我认为)

【问题讨论】:

  • 你为什么不能把两级因子变量变成一个数字(例如as.numeric(f)-1)?拟合的模型将是相同的。
  • 我将编辑一个我写的小例子来证明你是正确的。在这种情况下你是正确的事实让我感到困惑。我认为您应该将因子用于这样的指标变量。这仅适用于我只使用 1 和 0 吗?
  • 对不起,我第一次没有写正确的模型公式。当公式为 output~year+temp+is_paid 时,您的解决方案有效,但在像我的模型那样查看两个因子变量之间的交互时则无效。
  • 在您的 mod.factor 中,您有 10 个数据点,一个因子有 5 个水平,一个因子有 2 个水平。 2*5 = 10,所以它是单数。这就是您收到NAs 的原因。但本·博尔克是完全正确的。
  • 另外,通过在两个因子中使用each 模拟您的数据,对于b = 1b = 2,您没有观察到c = 1。一切都太有序了。

标签: r regression lm coefficients


【解决方案1】:

将 Ben Bolker 的评论转化为答案,并提供一些更好模拟数据的证据。

只需将您的两水平因素视为连续因素。这与将其视为一个因素相同。

例子:

df.num = data.frame(a = rnorm(12),
                    b = as.factor(rep(1:4,each = 3)),
                    c = rep(0:1, 6))
df.factor = df.num
df.factor$c = factor(df.factor$c)

mod.factor = lm(a~b*c - 1,data = df.factor)
mod.num = lm(a~b*c - 1,data = df.num)

all(coef(mod.factor) == coef(mod.num))
# [1] TRUE

【讨论】:

  • 太好了,谢谢。你能稍微扩展一下你的公式,特别是为什么你在 b*c 之后加上一个“-1”吗?
  • R 公式中的-1(相当于+0)表示“不适合截距”。在仅包含分类变量的回归中,省略截距会使系数与 0 相当,而不是与参考水平相当。您可以从两个模型公式中删除-1,模型之间的结果仍然相同(以及拟合质量),只有参数的标签和解释会改变。
  • 我明白了。非常感谢您的帖子。如果我添加了非分类变量,我还能使用“-1”吗?
猜你喜欢
  • 1970-01-01
  • 2010-10-11
  • 2018-10-29
  • 1970-01-01
  • 2011-10-07
  • 1970-01-01
  • 1970-01-01
  • 2016-02-16
  • 2010-10-21
相关资源
最近更新 更多