zoukankan      html  css  js  c++  java
  • 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%以上。

  • 相关阅读:
    Hadoop集群(三) Hbase搭建
    Hadoop集群(二) HDFS搭建
    Hadoop集群(一) Zookeeper搭建
    Redis Cluster 添加/删除 完整折腾步骤
    Redis Cluster在线迁移
    Hadoop分布式HA的安装部署
    Describe the difference between repeater, bridge and router.
    what is the “handover” and "soft handover" in mobile communication system?
    The main roles of LTE eNodeB.
    The architecture of LTE network.
  • 原文地址:https://www.cnblogs.com/lyuzt/p/10381107.html
Copyright © 2011-2022 走看看