9

在 R 中,如何设置特定变量的权重而不是函数中的观察lm()值?

上下文如下。我正在尝试为特定产品(例如手机)建立个人排名系统。我可以基于价格作为因变量和其他特征(如屏幕尺寸、内存、操作系统等)作为自变量来构建线性模型。然后我可以用它来预测手机的实际成本(而不是声明的价格),从而找到最佳的价格/质量系数。这是我已经做过的。

现在我想“突出”一些只对我很重要的功能。例如,我可能需要一个大内存的手机,因此我想给它更高的权重,以便线性模型针对内存变量进行优化。

lm()R中的函数有weights参数,但这些是观察的权重而不是变量(如果这是错误的,请纠正我)。我也尝试过使用公式,但只得到解释器错误。有没有办法将变量的权重合并到 中lm()

当然,lm()功能并不是唯一的选择。如果您知道如何使用其他类似的解决方案(例如glm()),这也很好。

UPD。经过几次评论后,我明白我思考问题的方式是错误的。通过调用获得的线性模型lm()为训练示例提供了最佳系数,并且没有办法(也不需要)改变变量的权重,很抱歉我造成了混淆。我实际上正在寻找的是更改现有线性模型中的系数以手动使某些参数比其他参数更重要的方法。继续前面的例子,假设我们有以下价格公式:

price = 300 + 30 * memory + 56 * screen_size + 12 * os_android + 9 * os_win8

该公式描述了价格和电话参数之间相关性的最佳可能线性模型。但是,现在我想手动将memory变量前面的数字 30 更改为 60,所以它变成:

price = 300 + 60 * memory + 56 * screen_size + 12 * os_android + 9 * os_win8

当然,这个公式不再反映价格和手机参数之间的最佳关系。此外,因变量没有显示实际价格,只是一些善值,考虑到记忆对我来说比普通人重要两倍(基于第一个公式的系数)。但是这种善良的价值(或者,更准确地说,分数的价值goodness/price)正是我所需要的——拥有这个我可以找到最好的(在我看来)价格最优惠的手机。

希望所有这些都有意义。现在我有一个(可能非常简单)的问题。如何在现有的线性模型中手动设置系数,获得的lm()?也就是说,我正在寻找类似的东西:

coef(model)[2] <- 60

这段代码当然不起作用,但你应该明白。注意:显然可以将memory数据框中的列中的值加倍,但我正在寻找更优雅的解决方案,影响模型,而不是数据。

4

2 回答 2

4

看起来您正在进行优化,而不是模型拟合(尽管模型拟合中可以进行优化)。您可能想要类似optim函数的东西,或者研究线性或二次规划(linprogquadprog包)。

如果您坚持使用建模工具,lm那么请使用offset公式中的参数来指定您自己的乘法器,而不是计算一个。

于 2012-09-07T19:36:49.603 回答
4

下面的代码有点复杂,因为lm() 最小化了残差平方和,并且使用固定的非最优系数,它不再是最小的,所以这将与lm()试图做的事情背道而驰,唯一的方法是也修复所有剩余的系数。

为此,我们必须首先知道无限制模型的系数。所有的调整都必须通过更改模型的公式来完成,例如我们有 price ~ memory + screen_size,当然还有隐藏的截距。现在,直接更改数据或使用数据都不I(c*memory)是好主意。I(c*memory)也像数据的临时更改,但是通过转换变量仅更改一个系数会困难得多。

所以首先我们更改price ~ memory + screen_sizeprice ~ offset(c1*memory) + offset(c2*screen_size). 但是我们没有修改截距,它现在将尝试最小化残差平方和,并可能与原始模型不同。最后一步是删除截距并添加一个新的假变量,即与其他变量具有相同数量的观察值:

price ~ offset(c1*memory) + offset(c2*screen_size) + rep(c0, length(memory)) - 1

# Function to fix coefficients
setCoeffs <- function(frml, weights, len){
  el <- paste0("offset(", weights[-1], "*", 
               unlist(strsplit(as.character(frml)[-(1:2)], " +\\+ +")), ")")
  el <- c(paste0("offset(rep(", weights[1], ",", len, "))"), el)                                 
  as.formula(paste(as.character(frml)[2], "~", 
                   paste(el, collapse = " + "), " + -1"))
}
# Example data
df <- data.frame(x1 = rnorm(10), x2 = rnorm(10, sd = 5), 
                 y = rnorm(10, mean = 3, sd = 10))
# Writing formula explicitly 
frml <- y ~ x1 + x2
# Basic model
mod <- lm(frml, data = df)
# Prime coefficients and any modifications. Note that "weights" contains 
# intercept value too
weights <- mod$coef
# Setting coefficient of x1. All the rest remain the same
weights[2] <- 3
# Final model
mod2 <- update(mod, setCoeffs(frml, weights, nrow(df)))
# It is fine that mod2 returns "No coefficients"

此外,您可能mod2只会将其用于预测(实际上我不知道现在还能在哪里使用它),因此可以以更简单的方式进行,而无需setCoeffs

# Data for forecasting with e.g. price unknown
df2 <- data.frame(x1 = rpois(10, 10), x2 = rpois(5, 5), y = NA)
mat <- model.matrix(frml, model.frame(frml, df2, na.action = NULL))
# Forecasts
rowSums(t(t(mat) * weights))
于 2012-09-07T23:15:34.717 回答