引言
上一篇中,我们讨论了数据应该是怎么样的格式,以及数据的获取步骤,这一篇集中讨论一下针对于这个项目而言具体的代码实现。
具体实现
按照我上一篇介绍的内容,数据获取步骤分为四步数据准备,数据预处理,数据清洗和数据标准化。
数据准备
数据来源于近五年肖四肖八预测题,格式是doc文档。
但是存在一个问题,网上寻找的肖四肖八预测题大多都是扫描版的pdf文档,并非word文档,因此想要获得到word文档,还需要进行人工处理,将pdf转化为word文档,虽然wps有自带的pdf转文档功能,但是其转化后的结果并不规整,因此还需要进行人工的处理。进行处理之后的格式是这样的:
将答案标为红色是为了识别答案。
此步骤还是消耗比较多的精力的。
数据预处理
对文档中的题目进行初步拆分和清洗。数据预处理就是将word文档中的每个题目单独的提取出来,并存放在一个json文件中,具体代码如下:
import os
import docx
import json
def one_ti(start_idx, end_idx, doc, all_test):
test = dict()
content = ""
for j in range(start_idx, end_idx):
para_text = doc.paragraphs[j].text
if content == "":
content = para_text
else:
content = content + "##n##" + para_text
content = content.replace('\t', "##t##")
content = content.replace(r"\t", "##t##")
content = content.replace(" ", "")
content = content.replace(" ", "")
content = content.replace(" ", " ")
content = content.replace("\n", "##n##")
content = content.replace("##n####n##", "##n##")
content = content.replace("##t####t##", "##t##")
test["content"] = content
all_test["test"].append(test)
print(test)
def main():
docx_path = os.path.join("datasets", "src", "politics.docx")
doc = docx.Document(docx_path)
para_nums = len(doc.paragraphs)
start_idx = 0
find_test = False
ans_flag = False
ans_style = None
all_test = dict()
all_test["test"] = []
for i in range(para_nums):
text = doc.paragraphs[i].text
num = len(doc.paragraphs[i].runs)
if num < 1:
continue
run0_style = str(doc.paragraphs[i].runs[0].font.color.rgb)
if "考研政治题库" in text:
if find_test and ans_flag:
end_idx = i
one_ti(start_idx, end_idx, doc, all_test)
find_test = True
ans_flag = False
start_idx = i + 1
if not find_test:
continue
if "【答案】" in text:
ans_flag = True
ans_style = run0_style
continue
if not ans_flag:
continue
else:
if ans_style != run0_style:
end_idx = i
one_ti(start_idx, end_idx, doc, all_test)
start_idx = i
ans_flag = False
continue
all_test_str = json.dumps(all_test, ensure_ascii=False, sort_keys=True, indent=4, separators=(',', ':'))
all_test_str.replace("},", "},\n")
os.makedirs(os.path.join("datasets", "middle"), exist_ok=True)
with open(os.path.join("datasets", "middle", "politics_all.json"), "w", encoding='utf-8') as f:
f.write(all_test_str)
print(len(all_test["test"]))
if __name__ == "__main__":
main()
程序首先读取指定的docx文件,然后遪历其中的段落。在遍历过程中,程序会根据特定的规则判断题目和答案的位置,提取题目内容和答案内容,并将其组织为一个特定的数据结构。最终,程序将提取到的题目和答案数据保存为一个json格式的文件,以便进一步处理或分析。程序的流程包括读取docx文件、遍历段落、提取题目和答案、组织数据结构、保存为json文件。
输出的json文件如下所示:
数据清洗
本步骤由人工进行,将含有图、表的题目剔除,以及拆分不正确的题目剔除。由于没有有图的题目,故此步骤略过。
数据标准化
对题目数据的格式进行标准化,并使用json格式存储。
首先读取数据预处理得到的存储题目内容的json文件"politics_all.json"。遍历每个题目,提取题目的内容、答案、解析等信息。根据题目类型(单选题、多选题、其他题型)进行不同的处理:对于单选题和多选题,提取选项内容,整理为标准格式;对于其他题型,直接提取题目内容和答案。将处理后的题目信息组织为新的数据结构,并存储到一个新的字典中。将新的字典转换为json格式的字符串。将处理后的数据保存为另一个json文件"politics_std.json"中。
具体代码如下:
import os
import json
if __name__ == "__main__":
path = os.path.join("datasets", "middle", "politics_all.json")
with open(path, "r", encoding='utf-8') as f:
test_all = json.load(f)
tests = test_all["test"]
output = ""
new_test = dict()
new_test["test"] = []
choice_func = {
"A": 0,
"B": 1,
"C": 2,
"D": 3
}
for i, test in enumerate(tests):
test_content = test["content"]
ans = test_content.split("【答案】")[-1]
analysis = test_content.split("【解析】")[-1]
content = test_content.split("【答案】")[0]
ans = ans.split("【解析】")[0]
ans = ans.replace("##n##", "")
analysis = analysis.replace("##n##", "").replace(" ", "")
# 单选题
if ans == "A" or ans == "B" or ans == "C" or ans == "D":
content = content.replace(".", ".")
choice_a = content.split("A.")[-1]
choice_b = choice_a.split("B.")[-1]
choice_c = choice_b.split("C.")[-1]
choice_d = choice_c.split("D.")[-1]
content = content.split("A.")[0]
choice_a = choice_a.split("B.")[0]
choice_b = choice_b.split("C.")[0]
choice_c = choice_c.split("D.")[0]
content = content.replace("##n##", "").replace("##t##", "").strip()
choice_a = choice_a.replace("##n##", "").replace("##t##", "").strip()
choice_b = choice_b.replace("##n##", "").replace("##t##", "").strip()
choice_c = choice_c.replace("##n##", "").replace("##t##", "").strip()
choice_d = choice_d.replace("##n##", "").replace("##t##", "").strip()
test_i = {
"tid": i + 1,
"type": 0,
"content": content,
"choices": [choice_a, choice_b, choice_c, choice_d],
"ans": choice_func[ans],
"analysis": analysis
}
new_test["test"].append(test_i)
# 多选题
elif all(char.isalpha() for char in ans):
content = content.replace(".", ".")
choice_a = content.split("A.")[-1]
choice_b = choice_a.split("B.")[-1]
choice_c = choice_b.split("C.")[-1]
choice_d = choice_c.split("D.")[-1]
content = content.split("A.")[0]
choice_a = choice_a.split("B.")[0]
choice_b = choice_b.split("C.")[0]
choice_c = choice_c.split("D.")[0]
content = content.replace("##n##", "").replace("##t##", "").strip()
choice_a = choice_a.replace("##n##", "").replace("##t##", "").strip()
choice_b = choice_b.replace("##n##", "").replace("##t##", "").strip()
choice_c = choice_c.replace("##n##", "").replace("##t##", "").strip()
choice_d = choice_d.replace("##n##", "").replace("##t##", "").strip()
test_i = {
"tid": i + 1,
"type": 2,
"content": content,
"choices": [choice_a, choice_b, choice_c, choice_d],
"ans": ans,
"analysis": analysis
}
new_test["test"].append(test_i)
else:
test_i = {
"tid": i + 1,
"type": 3,
"content": content,
"ans": ans,
}
new_test["test"].append(test_i)
output = json.dumps(new_test, ensure_ascii=False, sort_keys=True, indent=4, separators=(',', ':'))
with open(os.path.join("datasets", "middle", "politics_std.json"), "w", encoding='utf-8') as f:
f.write(output)
得到的json文件如下:
转换为LLM训练数据集
通过这一步,来得到最终的训练数据集。
首先读取经过数据标准化得到的政治考研题库的标准化json文件"politics_std.json"。然后遍历题目信息,根据题目类型创建不同类型的对话数据。创建一些关于系统身份认知和自我介绍的对话数据。将所有对话数据组织成一个数据集dataset。将数据集转换为json格式的字符串并将数据集保存为一个新的json文件"politics.json"中。
具体代码如下:
import os
import json
from tqdm import tqdm
system_prompt = "你是考研政治题库,内在是InternLM-1.8B大模型。你将对考研政治知识点做详细、耐心、充分的解答。"
if __name__ == "__main__":
dataset = []
path = os.path.join("datasets", "middle", "politics_std.json")
with open(path, "r", encoding='utf-8') as f:
all_test = json.load(f)
tests = all_test["test"]
print("创建:单选题问题...")
choice_func = {
0: "A",
1: "B",
2: "C",
3: "D"
}
for test in tqdm(tests):
if test["type"] != 0:
continue
content = test["content"].replace("##n##", "\n")
dataset.append({
"conversation": [
{
"system": system_prompt,
"input": "{}:A.{} B.{} C.{} D.{}".format(content, test["choices"][0], test["choices"][1], test["choices"][2], test["choices"][3]),
"output": "选择{}。{}。".format(choice_func[test["ans"]], test["analysis"])
}
]
})
print("创建:多选题问题...")
for test in tqdm(tests):
if test["type"] != 2:
continue
content = test["content"].replace("##n##", "\n")
dataset.append({
"conversation": [
{
"system": system_prompt,
"input": "(多选题){}:A.{} B.{} C.{} D.{}".format(content, test["choices"][0], test["choices"][1], test["choices"][2], test["choices"][3]),
"output": "选择{}。{}".format(test["ans"], test["analysis"])
}
]
})
print("创建:综合类问题...")
for test in tqdm(tests):
if test["type"] != 3:
continue
content = test["content"].replace("##n##", "\n")
dataset.append({
"conversation": [
{
"system": system_prompt,
"input": "{}?".format(content),
"output": "答案:{}".format(test["ans"])
}
]
})
print("创建:身份认知类问题...")
dataset.append({
"conversation": [
{
"system": system_prompt,
"input": "你是谁?",
"output": "我是考研政治学习助手,内在是InternLM-1.8B大模型。"
}
]
})
dataset.append({
"conversation": [
{
"system": system_prompt,
"input": "请介绍以下你自己。",
"output": "我是考研政治学习助手,内在是InternLM-1.8B大模型。"
}
]
})
dataset.append({
"conversation": [
{
"system": system_prompt,
"input": "做一下自我介绍。",
"output": "我是考研政治学习助手,内在是InternLM-1.8B大模型。"
}
]
})
dataset.append({
"conversation": [
{
"system": system_prompt,
"input": "为什么要开发你?",
"output": "政治学科作为重要学科,对于考生的发展具有深远的影响。"
}
]
})
print(len(dataset))
output = json.dumps(dataset, ensure_ascii=False, sort_keys=True, indent=4, separators=(',', ':'))
with open(os.path.join("datasets", "politics.json"), "w", encoding='utf-8') as f:
f.write(output)
最终的得到的训练数据集文件:
至此,得到了满足模型要求的训练数据集。