当前位置:   article > 正文

简答题文本自动评分_国开大学简答题怎么得分

国开大学简答题怎么得分

要求是这样的:

给定一段中文答案, 和标准的中文文字的答案做比对,最终得到完整的分数.

 

因为用户的答案中涉及到中文, 所以就必须使用中文分词器, 最终选定的是HanLP ,非常的方便, 资源链接如下:

https://github.com/hankcs/HanLP/tree/1.x  可以自行学习使用.

首先项目中引入HanLP的maven坐标:

  1. <dependency>
  2. <groupId>com.hankcs</groupId>
  3. <artifactId>hanlp</artifactId>
  4. <version>portable-1.7.7</version>
  5. </dependency>

 

我们使用HanLP分词之后, 使用 向量余弦算法计算两个文本的相似性 ,下面就是写了一个分词的工具类:

  1. package com.taohan.online.exam.util;
  2. import com.hankcs.hanlp.HanLP;
  3. import com.hankcs.hanlp.seg.common.Term;
  4. import java.math.BigDecimal;
  5. import java.util.ArrayList;
  6. import java.util.HashMap;
  7. import java.util.List;
  8. import java.util.Map;
  9. import java.util.regex.Pattern;
  10. /**
  11. * 分词工具类
  12. */
  13. public class HanlpUtil {
  14. /**
  15. * 判断标点符号正则表达式, 去掉标点符号
  16. */
  17. private static Pattern PATTERN = Pattern.compile("\\pP");
  18. public static void main(String[] args) {
  19. System.out.println(cosine("天气预报说,明天会下雨,你明天早上去上班的时候记得带上伞。"
  20. ,"你明天早上去上班的时候记得带上伞,天气预报说的可能会下雨。"));
  21. }
  22. /**
  23. * 0.5543
  24. *
  25. * 词向量余弦算法计算文本相似度
  26. *
  27. * @return
  28. */
  29. public static double cosine(String userAnswer, String standAnswer) {
  30. List<String> originWord = getWords(standAnswer);
  31. List<String> targetWord = getWords(userAnswer);
  32. Map<String, int[]> wordDict = new HashMap<>();
  33. for (String word : originWord) {
  34. if (!wordDict.containsKey(word)) {
  35. int[] value = new int[2];
  36. value[0] = 1;
  37. wordDict.put(word, value);
  38. } else {
  39. wordDict.get(word)[0] += 1;
  40. }
  41. }
  42. for (String word : targetWord) {
  43. if (!wordDict.containsKey(word)) {
  44. int[] value = new int[2];
  45. value[1] = 1;
  46. wordDict.put(word, value);
  47. } else {
  48. wordDict.get(word)[1] += 1;
  49. }
  50. }
  51. int dictNum = 0, originNum = 0, targetNum = 0;
  52. for (Map.Entry<String, int[]> entry : wordDict.entrySet()) {
  53. int origin = entry.getValue()[0];
  54. int des = entry.getValue()[1];
  55. originNum += origin * origin;
  56. targetNum += des * des;
  57. dictNum += origin * des;
  58. }
  59. double sqrt = Math.sqrt(originNum * targetNum);
  60. BigDecimal scale = new BigDecimal(dictNum).divide(new BigDecimal(sqrt), 4, BigDecimal.ROUND_HALF_UP)
  61. .setScale(4, BigDecimal.ROUND_HALF_UP);
  62. return scale.doubleValue();
  63. }
  64. /**
  65. * 分词
  66. *
  67. * @param str
  68. * @return
  69. */
  70. public static List<String> getWords(String str) {
  71. List<String> list = new ArrayList<>();
  72. if (StringUtils.isBlank(str)) {
  73. return list;
  74. }
  75. List<Term> segment = HanLP.segment(str);
  76. for (Term term : segment) {
  77. //https://github.com/hankcs/HanLP/tree/1.x
  78. if (!PATTERN.matcher(term.word).matches()) {
  79. list.add(term.word);
  80. }
  81. }
  82. return list;
  83. }
  84. }

中文分词就解决了, 还有向量余弦算法计算文本相似度 的问题也解决了,

 

下面是一个用户答案的评分的工具类, 以及其使用的示例, 

用户输入用户的答案, 用户答案和标准答案的多个关键字进行比较, 得到关键词双向匹配得分, 再和标准答案进行两个答案的文本比较得到相似性得分, , 两个得分计算平均值, 得到最后的得分.

  1. package com.taohan.online.exam.util;
  2. import java.math.BigDecimal;
  3. import java.util.ArrayList;
  4. import java.util.List;
  5. import java.util.stream.Collectors;
  6. import java.util.stream.Stream;
  7. public class CompareUtil {
  8. public static void main(String[] args) {
  9. String userAnswer = "多态是在程序还没运行时不知道调用哪个函数,在程序执行中,根据情况动态确定,操作很灵活";
  10. String standAnswer = "多态是在程序还没运行时不知道调用函数,在程序执行,根据情况动态确定";
  11. List<String> keywords = Stream.of("多态", "程序", "函数名", "参数", "运行情况").collect(Collectors.toList());
  12. double score = getUserAnswerScore(userAnswer, standAnswer, keywords);
  13. System.out.println(score);
  14. }
  15. /**
  16. * 获取最后的得分
  17. *
  18. * @param userAnswer 用户答案
  19. * @param standAnswer 标准答案
  20. * @param keywords 关键词
  21. * @return
  22. */
  23. public static double getUserAnswerScore(String userAnswer, String standAnswer, List<String> keywords) {
  24. if (StringUtils.equals(userAnswer, standAnswer)) {
  25. return 1.0;
  26. }
  27. if (StringUtils.isBlank(userAnswer)) {
  28. return 0.0;
  29. }
  30. double textSameScore = HanlpUtil.cosine(userAnswer, standAnswer);
  31. double score = 0;
  32. if (keywords != null && keywords.size() > 0) {
  33. score = getCompareScore(keywords, userAnswer);
  34. } else {
  35. score = textSameScore;
  36. }
  37. //计算两者的平均数
  38. BigDecimal scale = new BigDecimal(textSameScore).add(new BigDecimal(score))
  39. .divide(new BigDecimal(2), 4, BigDecimal.ROUND_HALF_UP)
  40. .setScale(4, BigDecimal.ROUND_HALF_UP);
  41. return scale.doubleValue();
  42. }
  43. /**
  44. * 0.4254
  45. * 获得关键词双向匹配得分
  46. *
  47. * @param keywords
  48. * @param userAnswer
  49. * @return
  50. */
  51. public static double getCompareScore(List<String> keywords, String userAnswer) {
  52. List<BigDecimal> list = new ArrayList<>();
  53. for (String keyword : keywords) {
  54. BigDecimal precent = getPrecent(userAnswer, keyword);
  55. list.add(precent);
  56. }
  57. BigDecimal sum = new BigDecimal("0");
  58. for (BigDecimal bigDecimal : list) {
  59. sum = sum.add(bigDecimal);
  60. }
  61. BigDecimal scale = sum.divide(new BigDecimal(list.size()), 4, BigDecimal.ROUND_HALF_UP)
  62. .setScale(4, BigDecimal.ROUND_HALF_UP);
  63. return scale.doubleValue();
  64. }
  65. /**
  66. * 比较两个字符串的相似度
  67. *
  68. * @param answer
  69. * @param oneWord
  70. * @return
  71. */
  72. public static BigDecimal getPrecent(String answer, String oneWord) {
  73. int index = 0;
  74. if (oneWord == null || oneWord.length() < 1) {
  75. return new BigDecimal(0);
  76. }
  77. if (answer.indexOf(oneWord) != -1) {
  78. index = oneWord.length();
  79. } else {
  80. int length = oneWord.length();
  81. for (int i = 0; i < length; i++) {
  82. String a = oneWord.substring(i, length - 1);
  83. String b = oneWord.substring(i + 1, length);
  84. if (answer.indexOf(a) != -1) {
  85. index = a.length();
  86. break;
  87. }
  88. if (answer.indexOf(b) != -1) {
  89. index = b.length();
  90. break;
  91. }
  92. }
  93. }
  94. if (index == 0) {
  95. for (int i = 0; i < oneWord.length(); i++) {
  96. if (answer.contains(String.valueOf(oneWord.charAt(i)))) {
  97. index = 1;
  98. }
  99. }
  100. }
  101. BigDecimal decimal = new BigDecimal(index)
  102. .divide(new BigDecimal(oneWord.length()), 2, BigDecimal.ROUND_HALF_UP)
  103. .setScale(4, BigDecimal.ROUND_HALF_UP);
  104. return decimal;
  105. }
  106. }

其实就是两个工具类的事情, 很简单.

这个是别人花钱雇我写的, 为了保证原创性, 暂时不会公开出来(大概4个月后会公开). 仅供大家参考

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/880566
推荐阅读
相关标签
  

闽ICP备14008679号