ECN>> oj>> 返回
项目作者: MaxLyu

项目描述 :
OnlineJudge难度与正确度的相关性检验
高级语言: Jupyter Notebook
项目地址: git://github.com/MaxLyu/oj.git
创建时间: 2019-03-29T06:38:06Z
项目社区:https://github.com/MaxLyu/oj

开源协议:

下载


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

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



一、新建项目


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


二、明确目的


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




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


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



  1. 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 ,增加或修改代码为:





  1. import scrapy
    import json
    from onlineJudge.items import OnlinejudgeItem

    class OjSpider(scrapy.Spider):
    name = oj # 爬虫的名字
    alloweddomains = [‘oj.dgut.edu.cn’]     # 域名范围
    offset = 0
    url = http://oj.dgut.edu.cn/api/xproblem/?limit=20&offset=
    starturls = [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 中写入如下代码





  1. 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


修改并增加代码:



  1. LOG_FILE = oj.log

    ROBOTSTXT_OBEY
    = True

    ITEM_PIPELINES
    = {
    onlineJudge.pipelines.OnlinejudgePipeline: 300,
    }


六、运行爬虫


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



  1. from scrapy import cmdline

    cmdline.execute(
    scrapy crawl oj.split())


  然后运行 main.py 文件。



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




七、分析数据


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



  1. import pandas as pd
    import xlrd

    data
    = pd.read_excel(../onlineJudge/onlineJudge/oj.xlsx)  # 导入 excel 文件
    data.describe()



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



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




  1. from matplotlib import pyplot as plt
    import matplotlib.style as psl
    %matplotlib inline

    psl.use(
    seaborn-colorblind) # 设置图表风格
    plt.rcParams[font.sans-serif]=[SimHei] #用来正常显示中文标签


  查看题目各难度的数目:



  1. 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)



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



  1. 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%以上。