尧图精选

SIB严重障碍量表电子化:从.doc解析到计分入库与随访

🕒 发布时间:2026/9/17 21:55:46 📁 来源:尧图网络
简介《严重障碍量表SIB.doc》是一份面向临床医生、护理人员、老年精神科研究者及临床试验从业者的专业评估文档用于系统测量晚期阿尔茨海默病患者的认知功能水平帮助判断损伤程度并支持个体化照护方案与疗效跟踪。量表共51个条目覆盖社会交往、记忆、定向力、语言、视觉空间与构造能力、注意力及行为等维度总分由0分损伤最严重至100分条目附有逐级评分标准。例如社会交往部分要求测试者主动握手并自我介绍、以手势或搀扶引导患者入座依据患者是否自发行动、需提示或需协助分别给1至2分记忆力部分通过自我介绍后复述姓名考察回忆定向力围绕当前月份与所在城市提问允许给予多选提示语言部分则涵盖书写姓名、抄写打印文字、列举一年十二个月、命名杯子勺子等日常物品以及阅读卡片并按指令递出手掌等任务。资源包仅含1个doc文档约93KB已有90人学习下载适合需要掌握标准化施测流程与记分规则的专业读者随时查阅。1. 一份「严重障碍量表SIB.doc」真正要处理的是什么拿到 严重障碍量表SIB.doc 这类文件的人多数不是想读一遍而是要把它变成系统里能算、能存、能前后对比的东西40 多个条目手工计分容易串行分量表散落在几页里随访时还要算变化量靠 Excel 复制粘贴迟早出错。SIBSevere Impairment Battery严重障碍量表用于中重度至重度痴呆患者的认知评估常见文献描述为 40 个条目、总分 0100、单次施测 2030 分钟条目门槛低、多用单字或指认式作答——这个特征决定了它天然适合电子化也决定了文档解析比 MMSE 更麻烦条目编号全角半角混排、选项和分值挤在同一行、不少版本到手时已经是扫描件或改过后缀的假 .doc。后面按「拆文档 → 建计分 → 落库 → 随访」把这条路走通读者是负责量表电子化的后端与数据工程师以及需要自己攒科研数据集的临床研究者。2. 把 .doc 版 SIB 量表拆成可解析文本与结构化 JSON2.1 先确认文件是不是真的 .docmagic bytes 判别从 OA、邮箱、IM 里流转出来的文件后缀基本不可信。我见过把 .docx 直接改名成 .doc 的也见过把扫描件另存成 .doc 的。老版 Word 用的是 OLE2 复合文档格式头部是D0 CF 11 E0 A1 B1 1A E1OOXML 系列docx/xlsx本质是 zip头部50 4B 03 04RTF 以{\rtf开头PDF 以%PDF-开头。先判别再选工具能省掉一半排查时间。# sniff_doc.py —— 不依赖扩展名只读头部 8 字节判类型 import pathlib SIGNATURES [ (b\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1, ole2-doc), # 老版 Word 二进制 (bPK\x03\x04, zip-ooxml), # docx 等 OOXML (b{\\rtf, rtf), # RTF (b%PDF-, pdf), # PDF可能是扫描件 ] def sniff(path: str) - str: head pathlib.Path(path).read_bytes()[:8] for sig, name in SIGNATURES: if head.startswith(sig): return name return unknownread_bytes()[:8]只读文件头几十 MB 的附件也不会把内存打满。判别结果里unknown要警惕可能是 WPS 的私有封装也可能是加密文档这时候别硬解析先让业务方给原始文件。文件类型头部特征推荐处理路径OLE2 二进制 .docD0 CF 11 E0LibreOffice 转 docx或 antiword 取纯文本OOXML .docx50 4B 03 04python-docx 直接读表格结构RTF7B 5C 72 74 66striprtf 或 LibreOffice 统一转换扫描 PDF / 图片25 50 44 46先 OCR再走同一套解析提示量表条目原文、分值和分量表归属一律以你手上的 SIB.doc 为准。不同修订版本条目数和计分口径存在差异代码里的条目内容只能当占位符。2.2 转换工具怎么选LibreOffice headless、antiword、catdoc 的取舍三条命令各有适用面我一般主路径走 LibreOffice辅路径走 catdoc 做交叉校验。# 1) LibreOffice headless还原度最高能保留表格结构与单元格边界 soffice --headless --convert-to docx --outdir ./out 严重障碍量表SIB.doc # 2) antiword纯文本模式速度最快但表格会被拍平成普通行 antiword -m UTF-8.txt 严重障碍量表SIB.doc sib_antiword.txt # 3) catdoc可显式指定编码处理老的 GBK 文档更稳 catdoc -d utf-8 严重障碍量表SIB.doc sib_catdoc.txt--convert-to docx的意义在于把「条目号 / 题干 / 选项 / 分值」这几列从视觉排版还原成表格关系后续用 python-docx 遍历doc.tables比抠文本靠谱得多。-m UTF-8.txt是 antiword 的映射文件不做映射时中文会变乱码-d utf-8是 catdoc 的输出编码开关源文件是 GBK 时必加。主辅两条路径的产物要做一致性校验同一份 .doc两条路径抽出的条目数应当相同条目号的集合也应当相同。不一致说明有换行、分页或文本框干扰回去看原始 docx 的表格结构。2.3 用正则把 SIB 条目、选项与分值抽成 JSON中文量表最常见的坑是全角字符。和1.在不做归一化时是两个完全不同的模式同一条目换个版本就匹配不上。先归一化再匹配。import re # 全角数字、括号、点号、冒号统一转半角否则跨版本匹配必挂 TRANS str.maketrans(, 0123456789().:) # 行首条目号 题干 可选的行尾满分标注 ITEM_RE re.compile( r^\s*(?Pno\d{1,2})\s*[.、)]\s*(?Ptext.?) r(?:[(](?Pmax\d{1,2})\s*分?[)])?\s*$ ) def parse_items(lines): items, cur [], None for raw in lines: line raw.translate(TRANS).strip() if not line: continue m ITEM_RE.match(line) if m: cur { no: int(m.group(no)), text: m.group(text).strip(), max: int(m.group(max)) if m.group(max) else None, options: [], } items.append(cur) elif cur is not None: # 续行、选项行统一挂到上一个条目不新起条目 cur[options].append(line) return itemsITEM_RE用^...$逐行匹配而不是整篇扫描因为条目题干常跨行整篇匹配会把两个条目粘成一条。(?Pmax...)设为可选是因为不少版本的满分只写在计分说明里而不在题干行这些条目需要在映射表中补max不能默认成 1。options单独收集方便后面做选项级核对。2.4 结构化落地字段约定与条目数自检解析结果落成固定结构后面的计分引擎只认这个结构不再碰原始文档。{ scale: SIB, source_file: 严重障碍量表SIB.doc, source_type: ole2-doc, items: [ {no: 1, text: ……, max: 3, subscale: attention, options: []} ] }scale和source_type是审计字段出问题时能回溯到具体文件和解析路径。落到库之前做三项自检条目号不重复、条目号基本连续、max求和等于文档标注的总分。第二条允许有跳号有些版本条目号带小项后缀但跳号超过三处就该人工看一眼。def self_check(data, declared_total100): nos [i[no] for i in data[items]] assert len(set(nos)) len(nos), 条目号重复 assert all(i[max] for i in data[items]), 存在未标注满分的条目 s sum(i[max] for i in data[items]) print(f条目数{len(nos)} 满分合计{s} 声明总分{declared_total}) return s declared_total这个「满分合计」校验成本极低却很能抓错——分值解析漏一条、多抓一条合计立刻对不上。3. SIB 计分引擎分量表映射、缺失值策略与边界护栏3.1 条目到分量表的映射表怎么建映射表是整条链路上唯一必须人工确认的东西。常见文献把 SIB 划成注意、定向、语言、记忆、视空间、结构、运用、社交互动、进食等若干分量表但每个分量表具体覆盖哪些条目号不同版本差异不小别照抄网上的表。用一份 CSV 维护格式参考如下示例行仅示意格式item_nosubscalemax_score1attention32attention320memory4CSV 比硬编码在代码里好版本变更时改数据不改逻辑也方便让临床同事直接核对。加载时统一做类型转换条目号转int避免1和1在字典里对不上。3.2 计分函数缺失值、跳转与部分完成怎么算def score_sib(responses, mapping, policystrict): responses: {item_no: score}mapping: [{no, max, subscale}] detail, total, answered {}, 0, 0 for row in mapping: no, mx row[no], row[max] if no not in responses: if policy strict: # 缺一条就拒绝出分 raise ValueError(f条目 {no} 缺失) if policy zero: # 缺失记 0重度场景下会系统性拉低总分 val 0 else: continue # pro_rate先跳过最后按比例折算 else: val responses[no] answered 1 if not 0 val mx: raise ValueError(f条目 {no} 得分 {val} 超出 0~{mx}) total val detail.setdefault(row[subscale], 0) detail[row[subscale]] val if policy pro_rate: full sum(r[max] for r in mapping) total round(total * full / sum(r[max] for r in mapping if r[no] in responses)) return {total: total, subscales: detail, answered: answered}policy是最关键的参数。科研和随访场景我默认strict缺一条就抛异常宁可回去补测也不要一个悄悄折算过的分数流进数据集。zero用在质控扫库阶段可以但必须打标。pro_rate只在量表内部条目高度同质、且缺失是随机发生时才勉强成立折算结果要额外记一个标志位。0 val mx这行范围校验看着啰嗦实际拦掉的错最多录入把3打成33、把两道题的分加在一起填进去都在这儿暴露。3.3 三个必调参数的取值与影响参数可选值影响建议默认缺失策略strict / zero / pro_rate决定缺条目时总分是否可用strict满分口径文档标注 / 条目累加决定总分是否与他人的数据可比文档标注条目累加做自检分量表折算原始分 / 百分比随访比较是否受条目缺失干扰横断面用原始分随访用百分比口径不一致是跨中心数据合并里最隐蔽的问题两边都是「总分 87」一个基于文档声明的 100 分制一个基于条目累加得到的 96 分制合在一起算均值就是错的。所以每次计分都要把policy和满分口径写进结果记录而不是只存一个数字。3.4 和人工计分对照抽 5 份做逐条目回归上线前一定要和人工计分对一遍方法很土但有效让同事在 Excel 里按条目号一列列填分脚本逐条目 diff定位到第一条不一致就停比看总分更快找到根因。def diff_with_manual(auto, manual): for no in sorted(manual): if auto.get(no) ! manual[no]: return f首处不一致条目 {no}自动{auto.get(no)} 人工{manual[no]} return 全部一致总分一致但明细不一致的情况最危险——分量表分析会整体偏掉所以必须逐条目比不能只比总分。4. 落库SIB 评分表设计、批量入库与纵向随访查询4.1 表结构一次评估一行条目明细单独存CREATE TABLE sib_assessment ( id INTEGER PRIMARY KEY, subject_code TEXT NOT NULL, -- 受试者编号不存姓名等直接标识 assessed_on DATE NOT NULL, total_score INTEGER NOT NULL CHECK (total_score BETWEEN 0 AND 100), policy TEXT NOT NULL DEFAULT strict, source_doc TEXT, -- 溯源哪份 SIB.doc 算出来的 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE sib_item_score ( assessment_id INTEGER NOT NULL REFERENCES sib_assessment(id), item_no INTEGER NOT NULL, subscale TEXT NOT NULL, score INTEGER NOT NULL, max_score INTEGER NOT NULL, PRIMARY KEY (assessment_id, item_no) );明细单独建表的理由很实在算分量表、做条目级变化分析、复核错分都要用到条目粒度只存总分的话发现异常时只能回去翻原始文档。CHECK约束是最后一道护栏应用层漏掉的范围校验在这里兜底。参数字段policy不要省它是复现一次计分的必要信息。4.2 批量入库一个目录的 SIB.doc 一次跑完import sqlite3, pathlib, json def import_dir(folder, conn, scorer): ok, failed 0, [] for p in sorted(pathlib.Path(folder).glob(*.doc*)): try: data parse_and_map(p) # 解析 映射 res scorer(data[responses], data[mapping], policystrict) with conn: # 单份文件一个事务 cur conn.execute( INSERT INTO sib_assessment(subject_code, assessed_on, total_score, policy, source_doc) VALUES (?,?,?,?,?), (data[subject_code], data[assessed_on], res[total], strict, p.name)) conn.executemany( INSERT INTO sib_item_score VALUES (?,?,?,?,?), [(cur.lastrowid, r[no], r[subscale], data[responses][r[no]], r[max]) for r in data[mapping]]) ok 1 except Exception as e: # 单份失败不影响整批 failed.append((p.name, str(e))) return ok, failedwith conn保证单份文件的评估主表与明细表要么都进、要么都不进不会出现有总分没明细的脏数据。异常按文件粒度捕获跑完打印failed列表统一处理——几十份文件里通常只有两三份是扫描件或缺条目没必要为它们中断整批。subject_code和assessed_on从文件名或单独的对照表来别指望从量表正文里抠容易抓错。4.3 纵向随访查询用窗口函数直接算变化量SELECT subject_code, assessed_on, total_score, total_score - LAG(total_score) OVER ( PARTITION BY subject_code ORDER BY assessed_on) AS delta FROM sib_assessment ORDER BY subject_code, assessed_on;LAG取同一受试者的上一次总分delta就是相邻两次随访的变化量。第一次随访delta为 NULL属正常。要注意两点变化量的解读必须带上随访间隔隔三个月的降 5 分和隔一年的降 5 分不是一回事不同policy算出来的分数不要放进同一个序列比WHERE policy strict该加就加。5. SIB 短版抽取与报告生成里的具体技巧5.1 用白名单从条目池里稳定抽出短版条目短版量表通常只是从完整条目里挑固定几条别重新解析一份文档直接从同一份结构化 JSON 里按条目号白名单取口径天然一致。SHORT_FORM {3, 5, 9, 12, 17, 21, 26, 33} # 条目号以实际版本为准 def extract_short(data, whitelistSHORT_FORM): pool {i[no]: i for i in data[items]} missing whitelist - pool.keys() if missing: raise ValueError(f短版条目缺失{sorted(missing)}) # 版本不匹配直接报错 return [pool[no] for no in sorted(whitelist)]missing检查是这套做法的核心价值换了一个修订版本的 SIB.doc条目号一漂移脚本立刻报错而不是安静地算出一个错的短版分数。白名单建议放进配置文件由临床同事签字确认后再定版。5.2 报告生成里最容易出的三类错现象根因处理方式总分与明细对不上报告取了解析出的分值而非计分结果报告只读计分引擎输出禁止二次求和缺失条目被当成 0读取时用dict.get(no, 0)读分处改用strict校验缺就抛随访变化量正负号反了LAG的排序方向或减数写反固定写当前 - 上一次并单测一条上升样本生成报告时还有个小技巧把policy、满分口径、条目数这几个元信息一起印在报告页脚。三个月后有人质疑某个分数翻页脚就能定位到当时的计分口径不用去翻那次跑批的日志。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →