尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Python解析考研词汇PDF:词形还原、语境卡与Anki间隔重复流水线

Python解析考研词汇PDF:词形还原、语境卡与Anki间隔重复流水线 简介这份PDF面向考研英语备考者以30篇精编文章串联考研词汇帮助在真实语境中巩固单词、提升阅读速度与长难句理解适合基础到强化阶段反复精读也可用于日常打卡与考前复盘。资源共1个PDF文件压缩包约103KB轻量便于电脑、手机或打印阅读内容按单元组织围绕文章配套词汇扩展、阅读理解、英语句法和地理文化知识例如Unit 1以“许可证”与移民打工经历切入带出permit、farm、winter store、dried chestnuts、grain等词并延伸摩洛哥、休达、厄瓜多尔等背景。已有626人学习下载。读者可借30篇文章建立语境记忆积累高频词、固定搭配与句型同时训练阅读定位、句法分析和文化常识适合需要把词汇书转化为文章精读材料的考研人群。1. 把《精编星火30篇文章贯通考研词汇资料.pdf》变成可复现的背词流水线考研词汇书买了三本能坚持背到 C 的人不多。根因不是毅力是词表脱离了语境《精编星火30篇文章贯通考研词汇资料.pdf》这类资料的思路是把大纲词塞进 30 篇成篇的文章里让每个生词至少在正文里落地一次背词变成读文章。对做 IT 的人来说这份 PDF 还有一层价值——它本身就是一份结构化语料。把 30 篇文章拆出来配上词频统计、词形还原和间隔重复排程翻到哪背到哪就变成一条能脚本能跑的流水线。下面按解析、对齐、出卡、验证四步走代码都可以直接改路径就跑。2. 解析 30 篇文章PDF 取词、分篇与清洗的最小脚本拿到 PDF 第一件事不是打开阅读器开始背而是判断它有没有文本层。星火这类教辅 PDF 绝大多数由排版软件导出正文是字符对象PyMuPDF 一行就能全取出来只有影印版才需要走 OCR。判断方法很便宜python -c import fitz; dfitz.open(精编星火30篇文章贯通考研词汇资料.pdf); print([len(p.get_text().strip()) for p in d][:10])打印出来每页都是几百上千说明有文本层全是 0 就是图片页得先上 OCR。这一步两分钟能省掉后面几小时的返工。2.1 取正文工具怎么挑PyMuPDF、pdfplumber、pypdf工具取正文速度坐标精度典型场景PyMuPDF (fitz)快块级 bbox整本抽取30 篇一次跑完pdfplumber慢一个量级字符级双栏、词表分列时单独修页pypdf中等基本没有只查页数和元数据30 篇文章、每篇几百词数据量很小选型原则是先能用坐标兜底的工具。PyMuPDF 的get_text(blocks)返回带 bbox 的文本块跑得最快pdfplumber 慢但能拿到每个字符的坐标遇到双栏排版或者词表分两列时更稳。常见做法是 PyMuPDF 抽全文跑完发现某几页顺序乱了再对那几页单独用 pdfplumber 修。2.2 用标题锚点把整本 PDF 切成 30 篇30 篇的标志通常是Passage 1到Passage 30也可能是Text、Unit或中文第一篇。别硬编码一种写成一个正则加常量先跑一遍看命中多少次命中 30 再往下做。import re import fitz # PyMuPDF PDF 精编星火30篇文章贯通考研词汇资料.pdf # 篇标题锚点先宽松匹配跑完确认命中数为 30 再收紧 HEAD re.compile(r^\s*(?:Passage|Text|Unit)\s*(\d{1,2})\b, re.I) # 每篇末尾的生词表区块作为正文截止标记 STOP re.compile(r^\s*(?:生词|词汇|Notes?|Words?|短语)\s*$, re.I) def split_articles(pdf_path): doc fitz.open(pdf_path) arts, cur, stopped {}, None, False for pno in range(doc.page_count): page doc[pno] # sortTrue 按 y 再按 x 排序双栏页面不加会左右交错 for block in page.get_text(blocks, sortTrue): for line in block[4].splitlines(): m HEAD.match(line) if m: cur, stopped int(m.group(1)), False arts.setdefault(cur, []) continue if STOP.match(line): stopped True continue if cur is not None and not stopped: arts[cur].append(line) return {k: \n.join(v).strip() for k, v in arts.items()} if __name__ __main__: a split_articles(PDF) print(len(a), sorted(a)[:5]) assert sorted(a) list(range(1, 31)), 篇号不连续检查页眉误命中sortTrue是关键参数双栏页面不加排序会把左右两栏拼在一起。HEAD里的^\s*配合splitlines()逐行匹配防止正文中偶然出现的 passage 被误判如果你的资料里篇标题不在行首去掉^但一定要补\b否则passages也会命中。末尾的assert别省篇号缺一个说明标题被页眉打断了靠人工翻页找要慢得多。每篇文章后面通常还跟着生词表标题类似生词Notes。这个区块必须截止不然词表里的词会和正文词混在一起后面按文章聚合频率就失真。STOP命中后把stopped置真直到下一篇标题出现才复位。2.3 清洗规则断词、音标、题号和页眉页脚PDF 取出来的文本有三类脏东西一定会遇到跨行断词vocabu-\nlary、紧跟词头的音标/ˈvəʊkæbjələri/、以及页眉页脚和题号。不处理的话词频表里会多出一堆只有前缀的假词。规则正则作用注意断词合并-\n(?[a-z])vocabu-\nlary→vocabulary只在小写字母前合并避免吃掉真连字符音标剔除/(?:.{2,20}?)/去/ˈwɜːd/遇到斜杠包裹的日期要抽查行首编号^\s*(?:\d{1,3}|[A-D])[\.、]\s*去题号、选项号会伤到数字开头的正文行跑完抽查多余空行\n{2,}压成单换行要保留段落就改压成\n\n连续空格[ \t]{2,}压成单空格表格对齐信息会丢正文无所谓import re RULES [ (r-\n(?[a-z]), ), # 跨行断词合并 (r/(?:.{2,20}?)/, ), # 剔除音标 (r^\s*(?:\d{1,3}|[A-D])[\.、]\s*, ), # 剔除行首题号 (r\n{2,}, \n), # 压缩空行 (r[ \t]{2,}, ), # 压缩空格 ] def clean(text: str) - str: for pat, rep in RULES: text re.sub(pat, rep, text, flagsre.M) return text.strip()规则的顺序不能乱。必须先合断词再压空白——反过来vocabu-\nlary中间的空行先被压掉连字符和字母之间的换行就没了第一条规则直接失效。词性标记n./v./adj.先留着别删。同一个词头在不同文章里词性不同是个很有用的提示。比如address在第 3 篇是名词地址在第 17 篇是动词处理、应对这种多义正是考研阅读的常考点出卡时可以做成同一个词的两张语境卡。清洗完做一次自检统计每篇词数。30 篇文章每篇正常在 300 到 500 词之间某篇只有 20 词大概率是篇标题被页眉打断或者STOP正则提前命中把正文切掉了。3. 词表对齐把文章里的词映射到考研大纲词汇正文干净之后才轮到真正决定效率的一步把文章词表和大纲词表对上。这里的关键不是匹配而是聚合——决定一个词值不值得出卡看的是它跨了几篇文章。3.1 词形还原spaCy、WordNetLemmatizer 和规则后缀怎么选方案依赖速度准确度适用spaCyen_core_web_sm一个小模型中高自带词性正文全量处理首选NLTK WordNetLemmatizerwordnet 语料快中默认按名词还原快速跑一遍对照规则后缀剥离无极快低不规则变形不认兜底或做差异对比按词元聚合而不是按原始词形统计。30 篇文章的价值在于同一个大纲词会在不同语境里反复出现按原始词形算study/studies/studying/studied会各算一次看不出贯通。还原成study之后再把出现过的文章编号收起来这才是能用的信号。import spacy # 关闭 parser 和 ner词形还原只依赖 tagger 和 lemmatizer nlp spacy.load(en_core_web_sm, disable[parser, ner]) def lemmas(text: str): doc nlp(text) out [] for t in doc: if not t.is_alpha or t.is_stop or len(t.text) 3: continue # 同时保留原词形和词元原词形用来回溯例句 out.append((t.text.lower(), t.lemma_.lower(), t.pos_)) return outdisable[parser, ner]是提速的关键句法树和命名实体识别在这个场景里没用关掉之后几千词单核一两秒跑完。三条过滤条件一起用词表能砍掉一半以上噪音。注意not、no、few这类短词别被误伤——考研阅读里的否定和程度词很关键可以单独维护一个白名单绕过is_stop。3.2 交集、差集和一张可回溯的对齐表大纲词表自己准备一个纯文本一行一个词全部小写。整理好的大纲词汇表大概五千多个词条。字段类型用途surfacestr原词形用来回溯并挖空句子lemmastr词元聚合和去重的主键articleint第几篇卡片背面显示来源sent_idint句序方便定位原句posstr词性多义词靠它区分contextstr完整句子做语境卡的正反面in_syllabusbool是否落在大纲内import pandas as pd syllabus {w.strip().lower() for w in open(syllabus.txt, encodingutf-8)} rows [] for aid, art in articles.items(): doc nlp(art) for sid, sent in enumerate(doc.sents): ctx sent.text.strip() for t in sent: if not t.is_alpha or t.is_stop or len(t.text) 3: continue lem t.lemma_.lower() rows.append((t.text.lower(), lem, aid, sid, t.pos_, ctx, lem in syllabus)) df pd.DataFrame(rows, columns[surface, lemma, article, sent_id, pos, context, in_syllabus]) core (df[df.in_syllabus] .groupby(lemma) .agg(freq(lemma, size), arts(article, nunique), first_ctx(context, first)) .sort_values([arts, freq], ascendingFalse))freq是这个词在 30 篇里出现的总次数arts是覆盖的文章数。排序先按arts再按freq因为一个词散落在 8 篇文章里比在一篇文章里刷 20 次更有记忆价值——前者是真实复现后者只是作者在同一主题里反复用词。first_ctx只取第一次出现的句子够用但不够好。更稳的做法是先给每行算一个ctx_score取句子长度在 10 到 30 词之间、且不含其他生词的那一句这样挖空之后的难度最合适聚合时用max挑出来。3.3 覆盖率与阈值30 篇文章到底能覆盖多少大纲词这一步得有个清醒预期。30 篇文章正文总词量大概一万到一万五去重词元两三千跟五千多的大纲词取交集覆盖率通常在三成到五成之间。这份资料的定位是精读核心词不是全量替代不要把交集全部出成卡片。指标计算方式参考阈值说明文章覆盖率 arts该词元出现的文章数≥ 3 优先出卡跨篇复现性价比最高频次 freq出现总次数只做辅助排序单篇高频多半是主题词句子可用性context 词数10–30 词太短没语境太长刷不动大纲覆盖率交集词元 / 大纲总数只做参考别设 KPI防止预期落空实操上分三档arts 3的先出卡这批通常两三百个正好一个月的量arts 2的排第二轮arts 1但freq很高的多半是文章主题词某篇讲经济economic出现十几次单独打个主题词标签考前扫一遍就行不进日常复习队列。4. 出卡与排程把对齐结果变成每天能刷的复习任务对齐表只是一堆数字真正每天要面对的是卡片。这一步的设计决定了前面所有解析工作到底有没有转化成记忆。4.1 卡片字段为什么原句 篇号比孤立词表好用孤立词表的卡片正面一个单词背面一个中文释义。刷起来很爽但迁移不到阅读里——真实阅读时你看到的是句子不是词表。把原句放在正面、目标词挖空复习时做的动作是在语境里认出这个词这才是 30 篇文章贯通词汇的正确用法。位置字段示例正面Context挖空The committee will ____ the proposal next week.正面Article第 12 篇背面Wordaddress背面Meaningv. 处理应对背面其他义项n. 地址演讲import re def cloze(surface: str, context: str) - str: # count1 必须加同句出现两次会挖两个洞答案就不唯一了 return re.sub(r\b re.escape(surface) r\b, ____, context, count1, flagsre.I)挖空靠字符串替换就能做但count1不能省。同一句里address出现两次的情况是有的挖两个洞之后你不知道考的是哪一个。flagsre.I让首字母大写的形式也能命中re.escape防止词里带连字符时正则报错。4.2 用 genanki 生成可导入的 apkgimport genanki MODEL genanki.Model( 1607392319, # 固定 ID定了就别改 星火30篇-语境卡, fields[{name: Word}, {name: Context}, {name: Article}, {name: Meaning}], templates[{ name: 语境回忆, qfmt: div classctx{{Context}}/divhrsmall{{Article}}/small, afmt: {{FrontSide}}hr idanswerb{{Word}}/bbr{{Meaning}}, }], ) def build_deck(core, outxinghuo30.apkg): deck genanki.Deck(2059400110, 考研词汇::星火30篇) for lem, r in core.iterrows(): note genanki.Note( modelMODEL, fields[lem, cloze(lem, r[first_ctx]), f第 {int(r[arts])} 篇覆盖, r.get(meaning, )], # 标签带上档位方便做筛选牌组 tags[arts3 if r[arts] 3 else arts2], ) deck.add_note(note) genanki.Package(deck).write_to_file(out) build_deck(core)Model 和 Deck 的第一个参数是数字 ID自己随便给一个固定值但一旦定了就不能改。改了 IDAnki 会当成新牌组重新导入之前积累的复习进度全丢。改模板内容可以改 ID 不行。sort_field建议设成Word浏览器里按字母排序时词根相近的词会挨在一起能顺带看出构词规律。标签里带上arts3/arts2后面用tag:arts3建筛选牌组做专题复习比手动翻列表快得多。4.3 复习间隔新卡上限和调度器怎么设参数位置建议值理由每日新卡上限牌组选项 → 新卡片15–25超过 30复习量第二周就崩每日复习上限牌组选项 → 复习200配合新卡量单次控制在半小时内学习步长学习阶段1 分钟 / 10 分钟默认就行语境卡不需要更细调度器牌组选项 → 高级切到 FSRS参数少适合自建牌组目标记忆保持率FSRS 参数0.90提到 0.95 复习量接近翻倍经典 SM-2 需要在简单加成间隔修正上手动调自建牌组没有历史数据支撑调起来全靠感觉。新一些版本的 Anki 内置了 FSRS 调度器在牌组选项里直接切换它只问一个目标记忆保持率默认 0.9按这个跑就够。注意切换调度器之后旧卡的历史复习记录会被重新解读第一周的到期量会抖一下别在这时候手改间隔。排程跟 30 篇文章对齐着来。arts 3的三百词每天 20 张新卡十五天出完第一轮第二轮接着出arts 2的两百词。配合每周回读原文两到三篇卡片的语境和原文的语境互相印证比纯刷卡稳。5. 用共现关系和回读抽样验证贯通是否真的发生背了一段时间之后需要一个客观信号判断哪些词真打通了。一个便宜的办法是看共现两个词元在 3 篇以上文章里同时出现大概率属于同一主题簇比如economic/policy/market这类词放一起复习比拆开背效率高。from collections import Counter from itertools import combinations pair Counter() grouped df[df.in_syllabus].groupby(article)[lemma].unique() for lemmas_in_article in grouped: # unique() 去重是必须的否则单词高频会污染词对计数 for a, b in combinations(sorted(set(lemmas_in_article)), 2): pair[(a, b)] 1 # 只在 3 篇以上同现的词对才算稳定主题簇 hot [(k, v) for k, v in pair.items() if v 3] print(sorted(hot, keylambda x: -x[1])[:20])unique()不能省。同一篇里某个词出现十次词对会被重复计数v 3的阈值就形同虚设全是同一个词跟别人配对的噪音。跑出来的高频词对可以直接生成主题牌组每个牌组十来个词专门留到考前扫。回读抽样的判定标准比刷卡正确率更有参考价值抽样方式样本量判定处理随机抽已到期卡20 张正确率 70%该批降回 learning新卡减半回读原文遮住生词表1 篇生词 15 个这篇主题词单独出一组遮词看句的完形式回读10 句认词但读不懂句问题在语法不在词汇第三条判定最容易被忽略。很多人刷卡正确率 90%回读原文还是读不懂卡在句子结构而不是词义上。这时候继续加卡是无效投入应该把那几个句子单独拎出来做结构拆解认词和读句是两件事别混在同一个指标里看。最后给一个排序技巧把freq和arts合成一个权重省掉手动分档的纠结import numpy as np core core.assign( # arts 权重给满代表跨篇复现freq 取对数压掉单篇刷词的虚高 scorelambda d: d[arts] * 2 np.log1p(d[freq]) ).sort_values(score, ascendingFalse)两个系数是配平过的arts最大 30贡献 60 分freq取对数后落在 1 到 4 之间只贡献几分盖不过复现次数。按 score 排序取前 300 个出卡剩下的等第二轮。这个公式不是最优解但比单看频率靠谱也比凭感觉分档省事。本文还有配套的精品资源点击获取
返回列表