# 4.1 文本分析

    # 清空工作空间
    rm(list = ls())

    # 环境设置
    # install.packages(stringr)
    library(stringr)
    # install.packages(dplyr)
    library(dplyr)
    # install.packages(showtext)
    library(showtext)
    # install.packages(pander)
    library(pander)

## 4.1.1 简单文本——词语

    # 一键读入
    dat = read.csv("novel.csv", fileEncoding = "UTF-8")

    # 探索分析--观察类别变量的分布
    table(dat$小说类型)
    ##
    ##    都市小说 二次元小说   军事小说   科幻小说   历史小说   灵异小说
    ##         298        193         12        227        176         21
    ##    奇幻小说   体育小说   武侠小说   仙侠小说   玄幻小说   游戏小说
    ##          39         29         31        137        184        127
    ##    职场小说
    ##          75

    mean.order = dat %>% group_by(小说类型) %>% summarise(me = median(评论数)) %>% as.data.frame()
    dat$小说类型 = factor(dat$小说类型, levels = levels(dat$小说类型)[order(mean.order$me, decreasing = T)])

    labels = levels(dat$小说类型)

    # 描述分析--观察某个定量变量在不同类别上的分布
    bp = boxplot(log(dat$评论数) ~ dat$小说类型, col = rainbow(7, alpha = 0.4), xlab = "小说类型", ylab = "log(评论数)", xaxt = "n")
    # axis(1, at = dat$小说类型, labels = FALSE)
    text(1:13, par("usr")[3] - 0.6, labels = labels, srt = 45, pos = 1, xpd = TRUE)

    # 建立基准组
    dat = within(dat, 小说类型 <- relevel(dat$小说类型, ref = "二次元小说"))

    # 将基准组定位“二次元小说”

    # 建模分析--作为回归变量
    lm1 = lm(评论数 ~ 小说类型 + 总字数 + 评分, data = dat)
    summary(lm1)
    ##
    ##  Call:
    ##  lm(formula = 评论数 ~ 小说类型 + 总字数 + 评分, data = dat)
    ##
    ##  Residuals:
    ##      Min      1Q  Median      3Q     Max
    ##  -129505  -13326   -3623    1088  541601
    ##
    ##  Coefficients:
    ##                     Estimate Std. Error t value Pr(>|t|)
    ##  (Intercept)      -3.229e+03  5.310e+03  -0.608    0.543
    ##  小说类型玄幻小说  2.437e+04  4.967e+03   4.907 1.02e-06 ***
    ##  小说类型历史小说  2.752e+03  4.913e+03   0.560    0.575
    ##  小说类型仙侠小说  2.258e+04  5.309e+03   4.253 2.24e-05 ***
    ##  小说类型军事小说 -6.914e+03  1.378e+04  -0.502    0.616
    ##  小说类型都市小说 -9.544e+02  4.376e+03  -0.218    0.827
    ##  小说类型游戏小说  1.249e+03  5.353e+03   0.233    0.816
    ##  小说类型灵异小说 -4.632e+03  1.058e+04  -0.438    0.662
    ##  小说类型奇幻小说  7.641e+03  8.107e+03   0.943    0.346
    ##  小说类型武侠小说  4.308e+03  8.894e+03   0.484    0.628
    ##  小说类型科幻小说  2.166e+03  4.551e+03   0.476    0.634
    ##  小说类型职场小说  3.062e+03  6.309e+03   0.485    0.628
    ##  小说类型体育小说 -6.967e+03  9.195e+03  -0.758    0.449
    ##  总字数            5.773e-03  5.821e-04   9.918  < 2e-16 ***
    ##  评分              5.306e+01  5.114e+02   0.104    0.917
    ##  ---
    ##  Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
    ##
    ##  Residual standard error: 45910 on 1532 degrees of freedom
    ##    (2 observations deleted due to missingness)
    ##  Multiple R-squared:  0.1229,    Adjusted R-squared:  0.1148
    ##  F-statistic: 15.33 on 14 and 1532 DF,  p-value: < 2.2e-16

## 4.1.2 难度升级——处理长难句

    df = read.csv("BearTrip_RawData.csv", fileEncoding = "UTF-8", stringsAsFactors = F)  # 读入数据
    names(df) = c("threemonth", "info", "satisfactory", "name", "title", "price", "storerating",
                  "promise", "combo", "creditLevel", "unique", "destination", "type", "tripschedule", "num_spot")  # 重命名为英文

    ## 1.提取固定长度文本--提取旅游类型 ##
    head(df$title)
    ##  [1] "【自由行】<深圳湾口岸>港澳通行证团队旅游L签过关名单<口岸取单，随到随走>"
    ##  [2] "【自由行】直飞香港!真纯玩！香港住四星级酒店!香港观光+迪士尼+澳门观光5天游！"
    ##  [3] "【跟团游】【圣诞】【春节】北京直飞—香港+澳门4晚5日游 1晚黄金海岸+1天free"
    ##  [4] "【自由行】港澳通行证L签送关！深圳湾口岸、文锦渡口岸L签过关，团签送关，香港过关"
    ##  [5] "【半自助游】纯玩亲子游 不进珠宝手表 港澳观光7天 迪士尼 蜡像馆 自由行 维港 赌场"
    ##  [6] "【半自助游】春节热卖！纯玩港澳5天游 <U+25B6>香港观光+自由行+澳门观光+威尼斯，赠送维港游船"
    df$title.type = str_sub(df$title, 2, 4)
    head(df$title.type)
    ##  [1] "自由行" "自由行" "跟团游" "自由行" "半自助" "半自助"

    ## 2.提取固定关键词--生成“交通方式”新变量 ##
    head(df$combo)
    ##  [1] "香港、澳门:1天:签证:特别提示"
    ##  [2] "北京-|                                                        香港、澳门:5天4晚:飞机往返:高档型酒店"
    ##  [3] "北京-|                                                        香港、澳门:5天4晚:飞机直飞往返:五星/四星酒店:约5个景点"
    ##  [4] "香港:1天:签证"
    ##  [5] "北京-|                                                        香港、澳门:7天6晚:飞机直飞往返:舒适型/经济型酒店:约2个景点"
    ##  [6] "北京-|                                                        香港、澳门:5天4晚:飞机直飞往返:舒适型/经济型酒店:约10个景点"
    df$plane = grepl('飞机', df$combo)
    df$CRH = grepl('高铁', df$combo)
    head(df$plane)
    ##  [1] FALSE  TRUE  TRUE FALSE  TRUE  TRUE
    head(df$CRH)
    ##  [1] FALSE FALSE FALSE FALSE FALSE FALSE

    ## 3.提取词类并打标签--生成项目档次 ##
    df$title[100:110]
    ##   [1] "【半自助游】炫.香港四天五晚高端奢华品质之旅，一天自由行，三晚五星，一晚澳四星"
    ##   [2] "【跟团游】【北京出发】真纯玩！不进店！港澳四天纯玩团！海洋公园+澳门观光！"
    ##   [3] "【跟团游】精选无强制购物！亲子游！北京至港澳双飞5天游 迪士尼/维多利亚港，澳门赌场"
    ##   [4] "【自由行】【珠海】澳门环岛游夜游单人票2张+立洲酒店拱北口岸店标准双床房1晚"
    ##   [5] "【自由行】珠海来魅力假日酒店-豪华城景房两天游！含2人澳门环岛游门票"
    ##   [6] "【自由行】直飞香港!真纯玩！香港住四星级酒店!  海洋公园+迪士尼+澳门观光7天游！"
    ##   [7] "【跟团游】【北京出发】住四星！高端不进店！港澳七天纯玩团！海洋公园+迪士尼+澳门观光！"
    ##   [8] "【自由行】直飞香港!真纯玩！香港住四星级酒店!海洋公园+迪士尼+澳门观光6天游！"
    ##   [9] "【半自助游】深圳+香港+澳门6天5晚：海洋公园+维多利亚港+自由行+澳门 一趟旅程三座城"
    ##  [10] "【跟团游】港澳5天4晚 纯玩定制亲子蜜月无购物观光游+蜡像馆+迪士尼 可升级4星酒店"
    ##  [11] "【半自助游】品质纯玩！香港澳门3天半自助游！海洋公园+自由行+观光，澳门威尼斯！"
    high_end = "五星|豪华|奢华|VIP|商务|奢享|铂金|至尊|尊享|顶级|高端|高档|定制"  # 豪华关键词
    middle_end = "品质|四星|精品|精致|精华|经典|精选|升级|舒适"  # 轻奢关键词
    df$title.level = ifelse(grepl(middle_end, df$title), "轻奢", "普通")
    df$title.level = ifelse(grepl(high_end, df$title), "豪华", df$title.level)
    cbind(head(df$title), head(df$title.level))
    ##       [,1]
    ##  [1,] "【自由行】<深圳湾口岸>港澳通行证团队旅游L签过关名单<口岸取单，随到随走>"
    ##  [2,] "【自由行】直飞香港!真纯玩！香港住四星级酒店!香港观光+迪士尼+澳门观光5天游！"
    ##  [3,] "【跟团游】【圣诞】【春节】北京直飞—香港+澳门4晚5日游 1晚黄金海岸+1天free"
    ##  [4,] "【自由行】港澳通行证L签送关！深圳湾口岸、文锦渡口岸L签过关，团签送关，香港过关"
    ##  [5,] "【半自助游】纯玩亲子游 不进珠宝手表 港澳观光7天 迪士尼 蜡像馆 自由行 维港 赌场"
    ##  [6,] "【半自助游】春节热卖！纯玩港澳5天游 <U+25B6>香港观光+自由行+澳门观光+威尼斯，赠送维港游船"
    ##       [,2]
    ##  [1,] "普通"
    ##  [2,] "轻奢"
    ##  [3,] "普通"
    ##  [4,] "普通"
    ##  [5,] "普通"
    ##  [6,] "普通"

## 4.1.3 小说文本

### （1）统计各个角色出场次数

    ## 1.统计各个角色出场次数 ##
    library(ggplot2)
    library(data.table)
    library(reshape2)

    # 载入数据
    roles = readLines("主角名单.txt", encoding = "UTF-8")
    yitian = readLines("倚天屠龙记.Txt", encoding = "UTF-8")

    # 将原小说进行分段
    para_head = grep("\\s+", yitian, perl = T)
    cut_para1 = cbind(para_head[1:(length(para_head)-1)], para_head[-1] - 1)
    yitian_para = sapply(1:nrow(cut_para1), function(i) paste(yitian[cut_para1[i, 1]:cut_para1[i, 2]], collapse = ""))
    yitian_para[1:2]
    ##  [1] "                         一　  天涯思君不可忘"
    ##  [2] "    “春游浩荡，是年年寒食，梨花时节。白锦无纹香烂漫，玉树琼苞堆雪。静夜沉沉，浮光霭霭，冷浸溶溶月。人间天上，烂银霞照通彻。浑似姑射真人，天姿灵秀，意气殊高洁。万蕊参差谁信道，不与群芳同列。浩气清英，仙才卓荦，下土难分别。瑶台归去，洞天方看清绝。”"
    # 对角色进行统计
    roles1 = paste0("(", gsub(" ", ")|(", roles), ")")
    roles_l = strsplit(roles, " ")  # 总结每个人的不同称呼

    # 计算每个人物名称的出现次数count
    role_para = sapply(roles1, grepl, yitian_para)
    colnames(role_para) = sapply(roles_l, function(x) x[1])
    # 将角色出现次数赋值到一个数据框中以便作图
    role_count = data.frame(role = factor(colnames(role_para), levels = colnames(role_para)[order(colSums(role_para), decreasing = T)]), count = colSums(role_para))
    head(role_count)
    ##           role count
    ##  殷离     殷离   248
    ##  周芷若 周芷若   446
    ##  赵敏     赵敏   606
    ##  小昭     小昭   198
    ##  张无忌 张无忌  2346
    ##  杨逍     杨逍   318

    # 根据出现次数绘图
    ggplot(role_count[1:5, ], aes(x = role, y = count, fill = role)) +
      geom_bar(stat = "identity", width = 0.75) +
      xlab("Role") +
      ylab("Count") +
      theme_grey(base_family = "STKaiti") +
      theme(axis.text = element_text(size = 24, angle = 90),
            axis.title = element_text(size = 24, face = "bold"),
            axis.title.x = element_text(vjust = -2),
            legend.position = "none")

### （2）三大主角出场顺序

    # 计算各人物的出场顺序
    # 将出场顺序放入数据框中以便作图
    main_roles = c("殷离", "周芷若", "赵敏", "小昭", "张无忌")
    role_para_df = data.frame(role = factor(rep(main_roles, colSums(role_para)[1:5])),
                              para = which(role_para[, (1:5)], arr.ind = T)[, 1])

    # 提取出三个主角的出场顺序
    role_para_df1 = role_para_df[is.element(role_para_df$role, c("赵敏", "周芷若", "张无忌")),]

    # 作出三个主角的出场顺序密度图
    (p = ggplot(role_para_df1, aes(para, fill = role)) +
        geom_density(aes(y = ..density..), alpha = I(0.3), color = "white", size = 0) +
        labs(x = "\n出场顺序", y = "密 度\n") +
        scale_fill_manual("角 色", values = terrain.colors(7)[3:1]) +
        theme_grey(base_family = "STKaiti") +
        theme(plot.margin = unit(c(0, 1, 1, 0), "cm"),
              axis.text = element_text(size = 24),
              axis.title.x = element_text(vjust = -2),
              axis.title = element_text(size = 24, face = "bold"),
              panel.background = element_rect(fill = "white"),
              panel.grid.major = element_line(color = "white"),
              panel.grid.minor = element_line(color = "white"),
              axis.line = element_line(color = "grey40"),
              legend.key.size = unit(0.8, "cm"),
              legend.text = element_text(size = 24),
              legend.title = element_text(size = 24)))

### （3）社交网络

    # 计算亲密度逻辑值
    co_para = crossprod(role_para)

    # 将无意义的矩阵对角线元素化为0
    diag(co_para) = 0

    # 构建前5个人物亲密度矩阵
    intimacy_main = co_para[1:5, 1:5]

    # 调整数据组织形式以便画图
    intimacy_main = melt(intimacy_main)

    # 绘制亲密度矩阵图
    (p = ggplot(intimacy_main, aes(Var1, Var2, fill = value)) +
        geom_tile(color = "#32CD32") +
        geom_text(data = intimacy_main, aes(Var2, Var1, label = value), size = 13, color = "black") +
        scale_fill_gradient(low = "white", high = "#32CD32") +
        xlab("") + ylab("") +
        scale_x_discrete(expand = c(0, 0), limits = c('张无忌', '赵敏', '周芷若', '殷离', '小昭')) +
        scale_y_discrete(expand = c(0, 0), limits = c('张无忌', '赵敏', '周芷若', '殷离', '小昭')[5:1]) +
        theme_grey(base_family = "STKaiti") +
        theme(axis.text = element_text(size = 24, angle = 90),
              axis.title = element_text(size = 24,face = "bold"),
              axis.title.x = element_text(vjust = -2),
              legend.position = "none"))