logistics regression + LDA + QDA + MARS

# 20230620
# 逻辑斯蒂回归就是以对数发生比为响应变量进行线性拟合,即log(P(Y)/1 + P(Y)) =B0+B1x。
# 这里的系数是通过极大似然估计得到的,而不是通过OLS。
# Start ========================================================================
rm(list = ls())
# ================================================================================
# 工作环境配置部分
options(digits = 4)


# 加载依赖包
library(MASS)
library(reshape2)
library(ggplot2)

data(biopsy)
# str(biopsy)
# summary(biopsy)   变量V6包含16个NA值
# contrasts(biopsy$class)
biopsy$ID <- NULL
names(biopsy) <- c("thick", "u.size", "u.shape", "adhsn", "s.size",
                   "nucl", "chrom", "n.nuc","mit", "class")
# names(biopsy)
biopsy.v2 <- na.omit(biopsy)
# 制造一个变量储存数据框的分类变量,使得分类变量成为数值型变量
# as.numeric(biopsy$class)
y <- ifelse(biopsy.v2$class == "malignant",1,0)

# 探索一下各个变量
biop.m <- melt(biopsy.v2, id.var = "class")
ggplot(data = biop.m, aes(x = class, y = value))+
  geom_boxplot() + 
  facet_wrap(~ variable, ncol = 3)


# 将数据恰当地划分成训练集和测试集
set.seed(123) #random number generator
ind <- sample(2, nrow(biopsy.v2), replace = TRUE,prob = c(0.7, 0.3))
# table(ind)
train <- biopsy.v2[ind==1, ] #the training dataset
test <- biopsy.v2[ind==2, ] #the test data set

# logist regression
full.fit <- glm(class ~ ., family = binomial, data = train)
summary(full.fit)
confint(full.fit)

# 逻辑斯蒂回归中的共线性也会使估计发生偏离
# 作为逻辑斯蒂回归建模过程的一部分, VIF分析是必不可少的
library(car)
vif(full.fit)
# 没有一个VIF值大于5,根据VIF经验法则,共线性看来不成为一个问题

# 查看训练集的准确率
# install.packages("caret")
library(caret)
train.probs <- predict(full.fit, type ="response")
train.probs <- as.factor(ifelse(train.probs > 0.5,1,0))
# 这里根据上面的抽样结果进行提取对应的肿瘤分类
trainY <- as.factor(y[ind==1])
testY <- as.factor(y[ind==2])

# 生成混淆矩阵
# 矩阵的行表示预测值,列表示实际值。对角线上的元素是预测正确的分类
confusionMatrix(trainY, train.probs)

# 在测试数据集上进行验证
test.probs <- predict(full.fit, newdata = test, type = "response")
test.probs <- as.factor(ifelse(test.probs > 0.5,1,0))

confusionMatrix(testY, test.probs)


# 还应该进行变量的选择
# 最后应该进行交叉验证,方便泛化模型
# 交叉验证的目的是提高测试集上的预测正确率,以及尽可能避免过拟合
# install.packages("bestglm")
library(bestglm)
# 加载程序包之后,需要将结果编码成0或1。如果结果仍为因子,程序将不起作用。
# 使用这个程序包的另外一个要求是结果变量(或y)必须是最后一列,而且要删除所有没有用的列
X <- train[, 1:9]
y <- ifelse(trainY == "0",0,1)

Xy <- data.frame(cbind(X,y))
bestglm(Xy = Xy, IC="CV",
        CVArgs=list(Method="HTF", K=10,REP=1), family=binomial)

# 结果认为Best Model有三个特征,它们是thick、 u.size和nucl
# 我们可以把这些特征放到glm()函数中,看看模型在测试集上表现如何。 
# 因为predict()函数不能用于bestglm生成的模型
reduce.fit <- glm(class ~ thick + u.size + nucl,
                  family = binomial, data = train)

test.cv.probs <- predict(reduce.fit, newdata =
                           test, type = "response")

test.cv.probs <- as.factor(ifelse(test.cv.probs >0.5,1,0))
confusionMatrix(testY, test.cv.probs)

# ==============================================================================

# 判别分析:LDA(线性判别分析),QDA(二次判别分析)
# 判别分析使用贝叶斯定理确定每个观测属于某个类别的概率

# lda 以及 qda 函数也在MASS包中
lda.fit <- lda(class ~ ., data = train)
lda.fit
# 简单诊断
plot(lda.fit, type = "both")
# LDA模型可以用predict()函数得到3种元素( class、 posterior和x)的列表
# class元素是对良性或恶性的预测
# posterior是值为x的评分可能属于某个类别的概率
# x是线性判别评分
train.lda.probs <- predict(lda.fit)$class
train.lda.probs <- as.factor(ifelse(train.lda.probs == "benign",0,1))
confusionMatrix(trainY, train.lda.probs)

# 使用模型进行预测
test.lda.probs <- predict(lda.fit, newdata = test)$class
test.lda.probs <- as.factor(ifelse(test.lda.probs == "benign",0,1))
confusionMatrix(testY, test.lda.probs)

# 试试二次判别分析
qda.fit = qda(class ~ ., data = train)
qda.fit

train.qda.probs <- predict(qda.fit)$class
train.qda.probs <- as.factor(ifelse(train.qda.probs == "benign",0,1))
confusionMatrix(trainY, train.qda.probs)

# 使用模型进行预测
test.qda.probs <- predict(qda.fit, newdata = test)$class
test.qda.probs <- as.factor(ifelse(test.qda.probs == "benign",0,1))
confusionMatrix(testY, test.qda.probs)

# ==============================================================================
# 多元自适应回归样条方法:MARS
# install.packages("earth")
library(earth)

set.seed(1)
earth.fit <- earth(class ~ ., data = train,
                   pmethod = "cv",
                   nfold = 5, # 使用5折交叉验证来选择模型
                   ncross = 3, # 重复3次交叉验证法
                   degree = 1, # 使用没有交互项的加法模型
                   minspan = -1, # 每个输入特征只使用一个铰链函数
                   glm=list(family=binomial))

test.earth.probs <- predict(earth.fit, newdata = test, type = "response")
confusionMatrix(testY, test.earth.probs

你可能感兴趣的:(R,机器学习,机器学习,R)