• OnlineJudge难度与正确度的相关性检验


      本着做题的心态,上了东莞理工学院的 oj 网;在选择难度的时候发现有些题目通过率和难度可能存在着某些关系,于是决定爬下这些数据简单查看一下是否存在关系。

    一、新建项目

      我是用 Scrapy 框架爬取的(因为刚学没多久,顺便练练手)。首先,先新建 project (下载 Scarpy 部分已省略),在控制台输入 scrapy startproject onlineJudge(其中, onlineJudge为项目名称),敲击回车键新建项目完成。

    二、明确目的

      在动手写代码之前,先分析一下网页结构。网站是通过动态加载的,数据通过 json 文件加载。

      1、明确要爬取的目标: http://oj.dgut.edu.cn/problems 网站里的题目,难度,提交量,通过率。在查找 json 的时候发现只有通过数,那么通过率就要自己计算。

      2、打开 onlineJudge 目录下的 items.py 写下如下代码:

    class OnlinejudgeItem(scrapy.Item):
    
        id = scrapy.Field()                     # 题目编号
        title = scrapy.Field()                  # 标题
        difficulty = scrapy.Field()             # 难度
        submissionNo = scrapy.Field()         # 提交量
        acceptedNo = scrapy.Field()           # 正确数
        passingRate = scrapy.Field()           # 正确率

    三、制作爬虫

      1、在当前目录下输入命令:scrapy genspider oj "oj.dgut.edu.cn" (其中 oj 是爬虫的名字,"oj.dgut.edu.cn"算是一个约束,规定一个域名)

      2、打开 onlineJudge/spiders 下的 ojSpider.py ,增加或修改代码为:

    import scrapy
    import json
    from onlineJudge.items import OnlinejudgeItem
    
    class OjSpider(scrapy.Spider):
        name = 'oj'        # 爬虫的名字
        allowed_domains = ['oj.dgut.edu.cn']     # 域名范围
        offset = 0
        url = 'http://oj.dgut.edu.cn/api/xproblem/?limit=20&offset='
        start_urls = [url + str(offset)]       # 爬取的URL元祖/列表
    
        def parse(self, response):
            data = json.loads(response.text)['data']['results']
            if len(data):
                for i in range(len(data)):
                    submissionNo = data[i]['submission_number']
                    acceptedNo = data[i]['accepted_number']
                    try:
                        passingRate = round((int(acceptedNo)/int(submissionNo)) * 100, 2)
                    except ZeroDivisionError as e:
                        passingRate = 0
        
                    strPR = str(passingRate) + "%"
        
                    item = OnlinejudgeItem()
        
                    item['id'] = data[i]['_id']
                    item['title'] = data[i]['title']
                    item['difficulty'] = data[i]['difficulty']
                    item['submissionNo'] = submissionNo
                    item['acceptedNo'] = acceptedNo
                    item['passingRate'] = strPR
        
                    yield item
    
                    print(i)
                self.offset += 20
                yield scrapy.Request(self.url + str(self.offset), callback=self.parse)
     

    四、存储数据

        1、打算将数据存储为 excel 文档,要先安装 openpyxl 模块,通过 pip install openpyxl 下载。

        2、下载完成后,在 pipelines.py 中写入如下代码

    from openpyxl import Workbook
    
    class OnlinejudgePipeline(object):
    
        def __init__(self):
            self.wb = Workbook()
            self.ws = self.wb.active                # 激活工作簿
            self.ws.append(['编号', '标题', '难度', '提交量', '正确数', '正确率'])    # 设置表头
    
        def process_item(self, item, spider):
            line = [item['id'], item['title'], item['difficulty'],
                    item['submissionNo'], item['acceptedNo'], item['passingRate']]
            self.ws.append(line)
            self.wb.save('oj.xlsx')
            return item

    五、设置 settings.py 

        修改并增加代码:

    LOG_FILE = "oj.log"
    
    ROBOTSTXT_OBEY = True
    
    ITEM_PIPELINES = {
        'onlineJudge.pipelines.OnlinejudgePipeline': 300,
    }

    六、运行爬虫

      在当前目录下新建一个 main.py 并写下如下代码

    from scrapy import cmdline
    
    cmdline.execute("scrapy crawl oj".split())

      然后运行 main.py 文件。

      于是,想要的数据就被爬下来了

    七、分析数据

      分析数据之前,先安装好 numpy,pandas,matplotlib,xlrd。

    import pandas as pd
    import xlrd
    
    data = pd.read_excel("../onlineJudge/onlineJudge/oj.xlsx")  # 导入 excel 文件
    data.describe()

      通过观察,数据没有异常值以及确实值,虽然提交量和正确数有为0的部分,但属于正常范围,不做处理。

    data = data.set_index('编号')  # 设置编号为索引
    data.head()            # 显示前五条信息

    from matplotlib import pyplot as plt
    import matplotlib.style as psl
    %matplotlib inline
    
    psl.use('seaborn-colorblind')    # 设置图表风格
    plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签

      查看题目各难度的数目:

    level_values = data['难度'].values
    
    difficulties = {
        '简单': 0,
        '中等': 0,
        '困难': 0
    }
    
    for value in level_values:
        if value == '简单':
            difficulties['简单'] += 1
        elif value == '中等':
            difficulties['中等'] += 1
        else:
            difficulties['困难'] += 1
    
    level = pd.Series(difficulties)
    print(level)
    
    level.plot(kind = 'bar', figsize=(6, 7))
    plt.grid(axis='y')

      验证正确率与难度之间是否存在关系:

    import numpy as np
    
    relation = data[['难度', '正确率']]
    rate_values = relation['正确率'].values
    
    fig, axes = plt.subplots(figsize=(15, 6))
    axes.scatter(rate_values, level_values)
    plt.grid(axis='x')
    plt.xticks(np.arange(0, 1, 0.05))
    plt.xlabel('正确率')
    plt.ylabel('难度')

      根据图像显示,题目难度跟正确率存在一定关系,困难的题目正确率相对集中于8%-28%,中等难度的题目比较集中在23%-55%,简单难度的题目正确率主要在40%以上。

  • 相关阅读:
    Linux与Windows区别——总结中
    Linux改变文件属性与权限
    Linux文件属性与权限
    数据库范式
    JavaScript基础:逻辑运算符——&&和||(短路判断)和!
    JavaScript基础:比较运算符——==与 ===;!=与!==
    JavaScript基础:字符串转换函数——String()和toString()
    Angular7 HttpClient处理多个请求
    javascript对象引用与赋值
    SASS用法指南
  • 原文地址:https://www.cnblogs.com/lyuzt/p/10381107.html
Copyright © 2020-2023  润新知