第15章 编程的本质与基础

学习目标

  • 理解编程在科研中的核心价值:可重复、可追溯、可扩展
  • 掌握脚本化分析的基本结构
  • 建立最小可行的调试与报错定位方法

关键概念

  • 输入-处理-输出 (IPO)
  • 变量与数据结构
  • 函数与模块化
  • 工作目录与路径
  • 调试 (Debug) 与日志 (Log)
  • 版本控制意识

正文

编程的本质:把“想法”变成“可执行流程”

在科研中,编程不是炫技,而是把你的研究流程写成一份任何人都能执行的“标准操作说明书”。

口头流程通常是:

“先清洗数据,再算指标,再做统计,最后画图。”

脚本化流程应该是:

  1. 读取哪些原始数据。
  2. 清洗规则是什么。
  3. 指标如何计算。
  4. 统计模型如何设定。
  5. 输出到哪里、叫什么名字。

科研脚本的最小结构

任何语言都可以按同一模板组织。

1) 配置区: 路径、参数、随机种子
2) 读入区: 数据读取与格式检查
3) 处理区: 清洗、转换、计算指标
4) 分析区: 统计检验 / 建模
5) 输出区: 表格、图、日志、模型对象

核心目标是:每次运行得到一致、可解释的结果。

为什么“可复现”比“跑通一次”更重要

只跑通一次,常见问题是:

  • 你下周重跑就忘了自己改过什么。
  • 同门拿到脚本无法直接复现。
  • 投稿审稿要求复现实验时无法提供清晰证据链。

可复现脚本要求你做到:

  1. 固定输入:数据源明确。
  2. 固定流程:步骤顺序固定,不靠手动点点点。
  3. 固定输出:命名规范,可自动覆盖或版本化保存。

编程基础能力:你真正需要掌握什么

1. 变量与数据结构

  • 标量:单个值(如一个被试年龄)。
  • 向量/数组:一组同类型数据(如一列反应时)。
  • 表格数据:行=观测,列=变量(科研最常见)。

建议优先理解“每列是什么变量、每行是什么观测单位”。

2. 条件与循环

  • 条件:根据规则筛选或分支处理。
  • 循环:对被试、文件、试次重复同一处理。

任何批处理都离不开这两个结构。

3. 函数化思维

把重复出现的逻辑封装成函数。

好处:

  • 避免重复粘贴代码。
  • 统一修改入口。
  • 让主脚本更清晰。

4. 路径意识

科研报错里,路径错误占比很高。

  • 使用项目相对路径优先。
  • 不把个人电脑绝对路径硬编码到共享脚本。
  • 明确当前工作目录(working directory)。

调试:如何快速定位问题

推荐使用“三步法”:

  1. 先读报错最后一行:通常给出最直接的失败原因。
  2. 定位触发位置前后几行:检查变量名、类型、路径。
  3. 最小复现:抽出最小代码片段单独运行。

常见错误映射:

错误现象 常见原因 处理方向
包找不到 环境没装或装错环境 切换/安装正确环境
文件找不到 路径或工作目录错误 打印当前目录并检查相对路径
结果全是 NA/NaN 清洗逻辑或类型转换错误 分步检查中间结果
图画不出来 数据为空或字段名不一致 先输出 head/summary 检查数据

代码风格与命名规范

建议使用可读性优先的命名:

  • 变量名体现含义,如 rt_ms, choice_prob
  • 中间结果分层命名,如 df_raw, df_clean, df_summary
  • 脚本按功能命名,如 01_clean.R, 02_model.py, 03_plot.R

注释应解释“为什么这样做”,而不只是“这里在赋值”。

最小版本管理意识

即使暂时不用完整 Git 工作流,也建议:

  1. 每次关键修改前备份一个可运行版本。
  2. 修改后写一段变更记录(做了什么、为什么)。
  3. 重要结果文件保留时间戳。

这会显著减少“我改坏了但不知道哪里坏了”的时间成本。

小结

  • 编程的核心不是语法,而是把研究流程工程化。
  • 一个好的科研脚本应该可重复运行、可追踪、可调试。
  • 先建立结构化习惯,再追求语言高级技巧。

练习与思考

  1. 把你最近做过的一次分析写成 输入-处理-输出 三段流程。
  2. 找出你现有脚本里重复出现的代码,尝试封装成一个函数。
  3. 故意制造一个“路径错误”,练习用三步法定位并修复。