# 5.1 机器学习概述

    ##### 5.1 机器学习概述 #####

    ### 载入数据和相应包 ###
    # 清空工作目录
    rm(list = ls())
    # 加载机器学习包
    # install.packages(caret)
    library(caret)
    # 加载数据
    dat0 = read.csv('相亲数据.csv', fileEncoding = "UTF-8")
    head(dat0)
    ##    决定 性别 吸引力 共同爱好 幽默 真诚 雄心 智力 好感 成功率自估
    ##  1    1    0      6        5    7    9    6    7    7          6
    ##  2    1    0      7        6    8    8    5    7    7          5
    ##  3    1    0      5        7    8    8    5    9    7         NA
    ##  4    1    0      7        8    7    6    6    8    7          6
    ##  5    1    0      5        6    7    6    6    7    6          6
    ##  6    0    0      4        4    4    9    6    7    6          5
    ##    日常出门频率 对宗教的看重程度 对种族的看重程度 年龄 种族 从事领域
    ##  1            1                4                2   21    4        1
    ##  2            1                4                2   21    4        1
    ##  3            1                4                2   21    4        1
    ##  4            1                4                2   21    4        1
    ##  5            1                4                2   21    4        1
    ##  6            1                4                2   21    4        1
    ##    对方决定 好感得分 对方评估成功率 吸引力得分 共同爱好得分 幽默得分
    ##  1        0        7              4          6            6        8
    ##  2        0        8              4          7            5        7
    ##  3        1       10             10         10           10       10
    ##  4        1        7              7          7            8        8
    ##  5        1        8              6          8            7        6
    ##  6        1        7              6          7            7        8
    ##    真诚得分 雄心得分 智力得分 对方年龄 对方种族 是否同一种族 日常约会频率
    ##  1        8        8        8       27        2            0            7
    ##  2        8        7       10       22        2            0            7
    ##  3       10       10       10       22        4            1            7
    ##  4        8        9        9       23        2            0            7
    ##  5        7        9        9       24        3            0            7
    ##  6        7        7        8       25        2            0            7

    ### 1.数据预处理及数据分割 ###
    ## (1) 缺失值处理 ##
    nrow(dat0)
    ##  [1] 8378
    dat = na.omit(dat0)
    nrow(dat)
    ##  [1] 5723

    ## (2) 将定性变量转换为因子性变量 ##
    # 转换数据类型
    dat$决定 = factor(dat$决定, levels = c(0, 1), labels = c("拒绝", "接收"))
    dat$性别 = factor(dat$性别, levels = c(0, 1), labels = c("女", "男"))
    dat$种族 = factor(dat$种族, levels = c(1, 2, 3, 4, 5, 6), labels = c("非洲裔", "欧洲裔", "拉丁裔", "亚裔", "印第安土著", "其他"))
    dat$从事领域 = factor(dat$从事领域, levels = 1:18,
                      labels = c("法律", "数学", "社会科学或心理学",
                                 "医学或药物学或生物技术", "工程学", "写作或新闻",
                                 "历史或宗教或哲学", "商业或经济或金融", "教育或学术",
                                 "生物科学或化学或物理", "社会工作", "大学在读或未择方向",
                                 "政治学或国际事务", "电影", "艺术管理",
                                 "语言", "建筑学", "其他"))
    dat$对方决定 = factor(dat$对方决定, levels = c(0, 1), labels = c("拒绝", "接收"))
    dat$对方种族 = factor(dat$对方种族, levels = c(1, 2, 3, 4, 5,6), labels = c("非洲裔", "欧洲裔", "拉丁裔", "亚裔", "印第安土著", "其他"))
    dat$是否同一种族 = factor(dat$是否同一种族, levels = c(0, 1), labels = c("非同一种族", "同一种族"))

    ## (3) 数据划分为训练集和测试集 ##
    # 设置随机种子
    set.seed(1234)
    # 将数据集的80%划分为训练集，20%划分为测试集
    trainIndex = createDataPartition(dat$决定, p = .8,
                                     list = FALSE,
                                     times = 1)
    # createDataPartition会自动从y的各个level随机取出等比例的数据来，组成训练集,可理解为分层抽样；
    datTrain = dat[trainIndex, ]
    # 训练集
    datTest = dat[-trainIndex, ]
    # 测试集
    table(dat$决定) / nrow(dat)  # 全集上因变量各个水平的比例
    ##
    ##      拒绝     接收
    ##  0.560021 0.439979
    table(datTrain$决定) / nrow(datTrain)  # 训练集上因变量各个水平的比例
    ##
    ##       拒绝      接收
    ##  0.5599476 0.4400524
    table(datTest$决定) / nrow(datTest)  # 测试集上因变量各个水平的比例
    ##
    ##       拒绝      接收
    ##  0.5603147 0.4396853

    ## (4) 标准化处理 ##
    preProcValues = preProcess(datTrain, method = c("center", "scale"))
    trainTransformed = predict(preProcValues, datTrain)
    testTransformed = predict(preProcValues, datTest)
    # 利用训练集的均值和方差对测试集进行标准化

    ### 2.变量选择 ###

    ## 封装法 rfe: Recursive feature selection ##
    subsets = c(2, 5, 10, 15, 20)
    # 要选择的变量个数
    ctrl = rfeControl(functions = rfFuncs, method = "cv")
    # 首先定义控制参数，functions是确定用什么样的模型进行自变量排序，本例选择的模型是随机森林
    # 根据目标函数（通常是预测效果评分），每次选择若干特征。
    # method是确定用什么样的抽样方法，本例使用cv，即交叉检验
    x = trainTransformed [, -which( colnames(trainTransformed ) %in% "决定")]
    y = trainTransformed [, "决定"]
    Profile = rfe(x, y, sizes = subsets, rfeControl = ctrl)
    Profile$optVariables  # 筛选出15个变量
    ##   [1] "好感"             "吸引力"           "共同爱好"
    ##   [4] "幽默"             "成功率自估"       "从事领域"
    ##   [7] "对种族的看重程度" "种族"             "对宗教的看重程度"
    ##  [10] "性别"             "年龄"             "日常出门频率"
    ##  [13] "吸引力得分"       "日常约会频率"     "真诚"

    ### 3.模型训练及调参 ###
    dat.train = trainTransformed[, c(Profile$optVariables, "决定")]
    dat.test = testTransformed[, c(Profile$optVariables, "决定")]

    ## 随机森林 ##
    set.seed(1234)
    gbmFit1 = train(决定 ~., data = dat.train, method = "rf")
    # 用于训练模型
    importance = varImp(gbmFit1, scale = FALSE)
    # 得到各个变量的重要性
    plot(importance, xlab = "重要性")

    ### 4.模型预测及评价 ###
    data.predict = predict(gbmFit1, newdata = dat.test)
    confusionMatrix(data.predict, dat.test$决定)
    ##  Confusion Matrix and Statistics
    ##
    ##            Reference
    ##  Prediction 拒绝 接收
    ##        拒绝  530  103
    ##        接收  111  400
    ##
    ##                 Accuracy : 0.8129
    ##                   95% CI : (0.7891, 0.8351)
    ##      No Information Rate : 0.5603
    ##      P-Value [Acc > NIR] : <2e-16
    ##
    ##                    Kappa : 0.621
    ##   Mcnemar's Test P-Value : 0.6323
    ##
    ##              Sensitivity : 0.8268
    ##              Specificity : 0.7952
    ##           Pos Pred Value : 0.8373
    ##           Neg Pred Value : 0.7828
    ##               Prevalence : 0.5603
    ##           Detection Rate : 0.4633
    ##     Detection Prevalence : 0.5533
    ##        Balanced Accuracy : 0.8110
    ##
    ##         'Positive' Class : 拒绝
    ##