GLM 拟合(逻辑回归)到 SQL
GLM fit (logistic regression) to SQL
我们经常直接在数据库中为线性或逻辑回归等简单模型对数据进行评分。将所有系数从 R 正确传输到 SQL 总是有点棘手。我想我可以为 glm 结果做一些 R 到 SQL 的翻译。对于数字变量,这非常简单:
library(rpart)
fit <- glm(Kyphosis ~ ., data = kyphosis, family = binomial())
coefs <- fit$coef[2:length(fit$coef)]
expr <- paste0('1/(1 + exp(-(',fit$coef[1], '+', paste0('(',
coefs, '*', names(coefs), ')', collapse = '+'),')))')
print(expr)
a <- with(kyphosis, eval(parse(text = expr)))
b <- predict(fit, kyphosis, type = 'response')
names(b) <- NULL
all.equal(a, b)
生成的expr
为:1/(1 + exp(-(-2.03693352129613+(0.0109304821420485*Age)+(0.410601186932733*Number)+(-0.206510049753697*Start))))
.
有没有办法让 factor
变量起作用?我想在 case ... when ... then ... end
子句中加入因素。假设我们有以下模型:
kyphosis$factor_variable <- rep(LETTERS[1:5],20)[1:81]
fit <- glm(Kyphosis ~ ., data = kyphosis, family = binomial())
我正在浏览 fit
的结构,但没有看到任何有用的信息。解析的唯一选项是names(fit$coef)
?
希望此功能对您有所帮助。今天写的,还没有测试所有角落-所以小心使用:)
glm_to_sql <- function(glmmodel) {
xlev <- data.frame(unlist(glmmodel$xlevels))
xlev$xlevrowname <- rownames(xlev)
rownames(xlev) <- NULL
colnames(xlev)[1] <- "xlevel"
if (nrow(xlev)==0){xlev <- data.frame(xlevrowname=character(0), xlevel=character(0), stringsAsFactors=F)}
modcoeffs <- data.frame(unlist(glmmodel$coefficients))
modcoeffs$coeffname <- rownames(modcoeffs)
rownames(modcoeffs) <- NULL
colnames(modcoeffs)[1] <- "coeffvalue"
coeffmatrix <- sqldf("select a.*,b.*,'' as sqlstr,
substr(coeffname,1,instr(coeffname, xlevel)-1) as varname
from modcoeffs a left join xlev b on coeffname like '%' || xlevel and xlevrowname like substr(coeffname,1,instr(coeffname, xlevel)-1) || '%'")
for (i in 1:nrow(coeffmatrix)) {
if(coeffmatrix$coeffname[i] == "(Intercept)")
{
coeffmatrix$sqlstr[i] <- coeffmatrix$coeffvalue[i]
} else if (is.na(coeffmatrix$xlevel[i]) ) {
coeffmatrix$sqlstr[i] <- paste("(",coeffmatrix$coeffvalue[i],"*",coeffmatrix$coeffname[i],")")
} else {
coeffmatrix$sqlstr[i] <- paste("(case when ",coeffmatrix$varname[i],"='",coeffmatrix$xlevel[i], "' THEN ",coeffmatrix$coeffvalue[i]," ELSE 0 END)",sep="")
}
if (i==1){x.sql0 <- coeffmatrix$sqlstr[i]} else {x.sql0 <- paste(x.sql0,"+",coeffmatrix$sqlstr[i])}
}
if (glmmodel$family$link == "logit") {
x.sql <- paste("1/(1 + exp(-(",x.sql0,")))")
} else if (glmmodel$family$link == "identity") {
x.sql <- x.sql0
}
return(x.sql)
}
我们经常直接在数据库中为线性或逻辑回归等简单模型对数据进行评分。将所有系数从 R 正确传输到 SQL 总是有点棘手。我想我可以为 glm 结果做一些 R 到 SQL 的翻译。对于数字变量,这非常简单:
library(rpart)
fit <- glm(Kyphosis ~ ., data = kyphosis, family = binomial())
coefs <- fit$coef[2:length(fit$coef)]
expr <- paste0('1/(1 + exp(-(',fit$coef[1], '+', paste0('(',
coefs, '*', names(coefs), ')', collapse = '+'),')))')
print(expr)
a <- with(kyphosis, eval(parse(text = expr)))
b <- predict(fit, kyphosis, type = 'response')
names(b) <- NULL
all.equal(a, b)
生成的expr
为:1/(1 + exp(-(-2.03693352129613+(0.0109304821420485*Age)+(0.410601186932733*Number)+(-0.206510049753697*Start))))
.
有没有办法让 factor
变量起作用?我想在 case ... when ... then ... end
子句中加入因素。假设我们有以下模型:
kyphosis$factor_variable <- rep(LETTERS[1:5],20)[1:81]
fit <- glm(Kyphosis ~ ., data = kyphosis, family = binomial())
我正在浏览 fit
的结构,但没有看到任何有用的信息。解析的唯一选项是names(fit$coef)
?
希望此功能对您有所帮助。今天写的,还没有测试所有角落-所以小心使用:)
glm_to_sql <- function(glmmodel) {
xlev <- data.frame(unlist(glmmodel$xlevels))
xlev$xlevrowname <- rownames(xlev)
rownames(xlev) <- NULL
colnames(xlev)[1] <- "xlevel"
if (nrow(xlev)==0){xlev <- data.frame(xlevrowname=character(0), xlevel=character(0), stringsAsFactors=F)}
modcoeffs <- data.frame(unlist(glmmodel$coefficients))
modcoeffs$coeffname <- rownames(modcoeffs)
rownames(modcoeffs) <- NULL
colnames(modcoeffs)[1] <- "coeffvalue"
coeffmatrix <- sqldf("select a.*,b.*,'' as sqlstr,
substr(coeffname,1,instr(coeffname, xlevel)-1) as varname
from modcoeffs a left join xlev b on coeffname like '%' || xlevel and xlevrowname like substr(coeffname,1,instr(coeffname, xlevel)-1) || '%'")
for (i in 1:nrow(coeffmatrix)) {
if(coeffmatrix$coeffname[i] == "(Intercept)")
{
coeffmatrix$sqlstr[i] <- coeffmatrix$coeffvalue[i]
} else if (is.na(coeffmatrix$xlevel[i]) ) {
coeffmatrix$sqlstr[i] <- paste("(",coeffmatrix$coeffvalue[i],"*",coeffmatrix$coeffname[i],")")
} else {
coeffmatrix$sqlstr[i] <- paste("(case when ",coeffmatrix$varname[i],"='",coeffmatrix$xlevel[i], "' THEN ",coeffmatrix$coeffvalue[i]," ELSE 0 END)",sep="")
}
if (i==1){x.sql0 <- coeffmatrix$sqlstr[i]} else {x.sql0 <- paste(x.sql0,"+",coeffmatrix$sqlstr[i])}
}
if (glmmodel$family$link == "logit") {
x.sql <- paste("1/(1 + exp(-(",x.sql0,")))")
} else if (glmmodel$family$link == "identity") {
x.sql <- x.sql0
}
return(x.sql)
}