【问题标题】:Error in contrasts when defining a linear model in R在 R 中定义线性模型时的对比错误
【发布时间】:2013-08-12 20:02:42
【问题描述】:

当我尝试在 R 中定义我的线性模型时:

lm1 <- lm(predictorvariable ~ x1+x2+x3, data=dataframe.df)

我收到以下错误消息:

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

有什么方法可以忽略或修复它?有些变量是因子,有些不是。

【问题讨论】:

  • 当年份是分类而非数字时,我在尝试为(价格〜年份)构建线性模型时遇到此错误。

标签: database r statistics


【解决方案1】:

如果您的自变量(RHS 变量)是一个因子或一个字符,它只取一个值,那么就会发生这种类型的错误。

示例:R中的虹膜数据

(model1 <- lm(Sepal.Length ~ Sepal.Width + Species, data=iris))

# Call:
# lm(formula = Sepal.Length ~ Sepal.Width + Species, data = iris)

# Coefficients:
#       (Intercept)        Sepal.Width  Speciesversicolor   Speciesvirginica  
#            2.2514             0.8036             1.4587             1.9468  

现在,如果您的数据仅包含一个物种:

(model1 <- lm(Sepal.Length ~ Sepal.Width + Species,
              data=iris[iris$Species == "setosa", ]))
# Error in `contrasts<-`(`*tmp*`, value = contr.funs[1 + isOF[nn]]) : 
#   contrasts can be applied only to factors with 2 or more levels

如果变量是数字 (Sepal.Width) 但仅取单个值(例如 3),则模型会运行,但您将得到 NA 作为该变量的系数,如下所示:

(model2 <-lm(Sepal.Length ~ Sepal.Width + Species,
             data=iris[iris$Sepal.Width == 3, ]))

# Call:
# lm(formula = Sepal.Length ~ Sepal.Width + Species, 
#    data = iris[iris$Sepal.Width == 3, ])

# Coefficients:
#       (Intercept)        Sepal.Width  Speciesversicolor   Speciesvirginica  
#             4.700                 NA              1.250              2.017

解决方案:因变量只有一个值的变化不够。因此,您需要删除该变量,无论它是数字变量还是字符变量还是因子变量。

根据 cmets 更新:由于您知道错误只会发生在因子/字符上,因此您可以只关注那些并查看这些因子变量的级别长度是否为 1(DROP ) 或大于 1 (NODROP)。

要查看变量是否为因子,请使用以下代码:

(l <- sapply(iris, function(x) is.factor(x)))
# Sepal.Length  Sepal.Width Petal.Length  Petal.Width      Species 
#        FALSE        FALSE        FALSE        FALSE         TRUE 

那么就可以只获取因子变量的数据框了

m <- iris[, l]

现在,找到因子变量的级别数,如果这是一个你需要删除它

ifelse(n <- sapply(m, function(x) length(levels(x))) == 1, "DROP", "NODROP")

注意:如果因子变量的级别只有一个,那就是变量,你必须放弃。

【讨论】:

  • 好的,谢谢。有什么方法可以在 R 中解决这个问题,或者它是需要编辑的原始数据。另外,查看数据后,所有变量都取多个值吗?有什么方法可以查看他们指的是哪些特定变量?
  • 另外 - 如果您的变量包含“外来”字符,则会出现相同的错误。我猜这是一个错误。当我更改错误消失时,我的变量 CustomerType 有一个包含“ö”的值
  • 您最后的ifelse 无效。一个变量可以有 2 个级别,但如果其中一个为空,则会出现错误,但您的代码不会检测到它。使用数据框df,更好的公式是:which(sapply(df, function(x) length(unique(x))&lt;2)),它列出了有问题的变量。
【解决方案2】:

您的预测变量x1x2x3 中的至少一个似乎只有一个因子水平,因此是一个常数。

看看

lapply(dataframe.df[c("x1", "x2", "x3")], unique)

找到不同的值。

【讨论】:

    【解决方案3】:

    Metrics and Svens 的答案处理的是通常情况,但对于在非英语环境中工作的我们来说,如果您的字符变量中有外来字符 (å,ä,ö),即使您有多个字符,您也会得到相同的结果因素水平。

    Levels &lt;- c("Pri", "För") 给出对比度错误,而 Levels &lt;- c("Pri", "For") 没有

    这可能是一个错误。

    【讨论】:

    • 感谢您的建议。尽管已经彻底检查了不止一个级别被传递给模型,但我的两个因子变量出现了这个错误,我想知道这是否是由于我的数据来自非英语环境。然而,关卡不包含外来字符,重新编码并不能解决问题。
    【解决方案4】:

    这是@Metrics 提供并由@Max Ghenis 编辑的答案的变体......

    l <- sapply(iris, function(x) is.factor(x))
    m <- iris[,l]
    
    n <- sapply( m, function(x) { y <- summary(x)/length(x)
    len <- length(y[y<0.005 | y>0.995])
    cbind(len,t(y))} )
    
    drop_cols_df <- data.frame(var = names(l[l]), 
                               status = ifelse(as.vector(t(n[1,]))==0,"NODROP","DROP" ),
                               level1 = as.vector(t(n[2,])),
                               level2 = as.vector(t(n[3,])))
    

    在这里,在识别因子变量之后,第二个sapply 计算记录的百分比属于变量的每个级别/类别。然后它确定发生率超过 99.5% 或低于 0.5% 的水平数(我的任意阈值)。

    然后它继续返回每个分类变量中有效级别的数量和每个级别的发生率。

    不应删除超过阈值的零级变量,而应从线性模型中删除另一个变量。

    最后一个数据框使查看结果变得容易。由于所有因子变量都是二项式的,因此对该数据集进行了硬编码。这个数据框可以很容易地被通用化。

    【讨论】:

      【解决方案5】:

      当数据包含NAs 时也可能出现此错误消息。

      在这种情况下,行为取决于默认值(请参阅文档),并且变量中提到的列中带有NA 的所有情况可能都会被静默删除。所以可能一个因素确实有几个结果,但是当限制在没有NA的情况下,这个因素只有一个结果。

      在这种情况下,要修复错误,要么更改模型(从公式中删除问题因素),要么更改数据(即完成案例)。

      【讨论】:

        【解决方案6】:

        如果错误恰好是因为您的数据有 NA,那么您需要设置 glm() 函数选项,以了解您希望如何处理 NA 案例。有关这方面的更多信息,请参阅此处的相关帖子:https://stats.stackexchange.com/questions/46692/how-the-na-values-are-treated-in-glm-in-r

        【讨论】:

          【解决方案7】:

          根据我十分钟前的经验,这种情况可能发生在有多个类别但有很多 NA 的情况下。以Kaggle Houseprice Dataset 为例, 如果你加载数据并运行一个简单的回归,

          train.df = read.csv('train.csv')
          lm1 = lm(SalePrice ~ ., data = train.df)
          

          你会得到同样的错误。我也试过测试每个因素的水平数,但没有一个说它少于 2 个水平。

          cols = colnames(train.df)
          for (col in cols){
            if(is.factor(train.df[[col]])){
              cat(col, ' has ', length(levels(train.df[[col]])), '\n')
            }
          }
          

          于是我用summary(train.df)查看了各个col的详细信息,并删除了一些,终于奏效了:

          train.df = subset(train.df, select=-c(Id, PoolQC,Fence, MiscFeature, Alley, Utilities))
          lm1 = lm(SalePrice ~ ., data = train.df)
          

          并删除其中任何一个,回归无法再次运行并出现相同的错误(我自己测试过)。

          以上属性一般有 1400+ NAs 和 10 个有用值,所以你可能想删除这些垃圾属性,即使它们有 3 或 4 个级别。我猜想计算每列中有多少 NA 的函数会有所帮助。

          【讨论】:

            【解决方案8】:

            其他作者的答案已经解决了只有一个水平或NA的因素的问题。

            今天,我在使用 rstatix::anova_test() 函数时偶然发现了同样的错误,但我的因素没问题(超过一个级别,没有 NA,没有字符向量,...)。相反,我可以通过删除数据框中未包含在模型中的所有变量来修复错误。我不知道这种行为的原因是什么,但在遇到此错误时了解这一点也可能会有所帮助。

            【讨论】:

            • 你刚刚解决了我的问题。这一定是某种错误,您认为该函数应该能够忽略其他列
            • 谢谢! rstatix::anova_test() 确实存在这个问题,尽管错误消息指向其他地方,但这确实是原因。
            • 这个问题似乎在最新的 rstatix 包 (0.7.0) 中得到修复
            【解决方案9】:

            当某些值列是整数而其他列是数字时,我遇到了同样的问题。将所有数字更改为整数解决了这个问题(但不知道它是否会影响分析)。

            【讨论】:

            • 这并不能真正回答问题。如果您有其他问题,可以点击 提问。要在此问题有新答案时收到通知,您可以follow this question。一旦你有足够的reputation,你也可以add a bounty 来引起对这个问题的更多关注。 - From Review
            猜你喜欢
            • 2018-10-29
            • 1970-01-01
            • 1970-01-01
            • 2015-04-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-11-25
            • 1970-01-01
            相关资源
            最近更新 更多