Skip to content

第三章 数据管理 ​

无论后续要做描述统计、假设检验还是回归建模,所有分析都建立在同一块基石之上:把原始信息整理成 PSPP 能够读懂的结构化数据。PSPP 处理的核心对象称为数据集(dataset),它由一张二维表格承载——纵向的每一列是一个变量(variable),横向的每一行是一个个案(case,也称观测,observation)。数据分析本质上就是围绕这张表,定义变量含义、录入或修改数值、筛选与变换个案,最终产出可供统计过程读取的干净数据。本章把数据管理的全链路讲透:从变量到底是什么、怎样新建并定义变量,到怎样录入、从外部文件导入、怎样深入设置属性,再到排序、拆分、筛选、计算新变量与重新编码,最后落到数据清洗与缺失值处理的收尾环节。

为便于前后呼应,本章贯穿一个小而完整的示例数据集:一份班级学生调查与成绩记录。它包含学号 id、姓名 name、班级 class、性别 gender、语文 chinese、数学 math、英语 english、满意度 satisfaction(1~5 分)与出勤率 attendance(0~100)。这份数据将反复出现在各节的示例中。

3.1 数据集与变量基础概念 ​

理解 PSPP 的数据模型,关键在于厘清三件事物及其关系。一张数据集像一本名册:每一行记载一个具体对象(这里就是一名学生)的全部信息,称为一个个案;每一列描述所有对象共享的某一属性(如语文成绩),称为一个变量。同一个变量在不同个案上的取值各不相同,这些取值的全体构成该变量的一列数据。个案与变量交叉处的单个数字或文字,称作一个取值(value)。

PSPP 中的变量只有两种类型,这一点与许多现代表格软件不同,却正是统计软件严格性的来源:

  • numeric(数值型):存放可以参与四则运算的数字,例如成绩、年龄、满意度评分。数值型变量支持计算、求均值、做方差分析等一切数学操作。
  • string(字符串型):存放文本,例如姓名、班级代号、开放性回答。字符串由字节序列构成,不能直接参与算术运算。定义时需用 A 加宽度标明最大字节数,例如 name (A12) 表示最多容纳 12 字节的字符串变量。

二者的区分看似简单,却常常是初学者出错的根源:把应当是数值的列误建成字符串,后续 COMPUTE、MEANS 等过程便无法对该列求和;反之把本该是文本的列建成数值,中文姓名等非数字内容会被整列丢弃。因此,在录入之前先想清楚"这一列将来要不要算数",远比事后补救来得经济。

在此还需铺垫一个与变量类型不同维度的概念——测量尺度(measurement level,PSPP 中称度量标准),它描述变量取值背后的数学含义,而非存储方式:

  • nominal(名义尺度):取值仅代表类别,彼此无大小顺序,例如性别、班级、专业名称。
  • ordinal(有序尺度):取值有先后次序,但相邻间距未必相等,例如满意度 1~5 分、成绩等级。
  • scale(标度尺度,也称连续/定距尺度):取值既有顺序又有可比较的等距,通常可近似为连续量,例如语文、数学、英语分数与出勤率。

测量尺度不影响数据存储,却直接关系到哪些统计过程适用、结果应如何解读。例如对名义变量求"均值"通常没有意义,而对标度变量做"中位数"虽可行却未必最优。PSPP 在过程层面会依据度量标准给出合适默认,因此从一开始就把尺度设对,能让后续分析少走弯路。下面的片段即用语法直观地展示了两类变量的声明方式:

text
DATA LIST LIST /id (F4) name (A12) gender (F1) chinese (F3).
BEGIN DATA.
1001 张伟  1  88
1002 李娜  2  92
END DATA.

其中 id、gender、chinese 为数值型(F 起头指明数值格式),name 为字符串型(A12),二者混排于同一数据定义之中。运行后,数据集便拥有三列数值与一列文本,奠定了后续一切操作的结构基础。

3.2 新建数据文件与变量定义 ​

在图形界面 psppire 中新建数据,核心是 Variable View(变量视图)这一标签页(界面推断,手册未逐项文档化)。它把每个变量的属性横向铺成一排列,逐列设定即可完成变量定义。PSPP 的 Variable View 通常包含以下十列,理解每一列的职责,是规范建表的第一步:

  • 名称(Name):变量的唯一标识,须以字母开头、不含空格与中文,建议用英文或拼音缩写(如 chinese、attendance)。
  • 类型(Type):在弹出的对话框中选择 numeric 或 string,并据此设定宽度与小数位;字符串类型在此指定最大字节数。
  • 宽度(Width):变量显示与存储占用的字符总宽度,数值型与字符串型都适用。
  • 小数(Decimals):数值型变量保留两位小数等显示位数。务必注意:这里只改变屏幕上显示的小数位,并不对原始数值做四舍五入——底层存储的是完整精度,显示成两位只是"看上去"被截断。
  • 标签(Label):变量的中文或长说明,例如把 chinese 标为"语文成绩"。标签不参与运算,仅用于输出中替代生硬的代码名,提升可读性。
  • 值标签(Values):为离散取值附加文字说明,例如给 gender 的 1 配"男"、2 配"女"。面向类别变量时,值标签让输出表格从一堆数字变为可读文字。
  • 缺失(Missing):声明哪些取值代表缺失(详见 3.5 与 3.8 节)。
  • 列宽(Columns):该列在 Data View 中显示的宽度,纯界面偏好,不影响数据。
  • 对齐(Align):单元格内文字的左/中/右对齐方式,同样只关乎显示。
  • 度量标准(Measure):即 3.1 节所述的 nominal / ordinal / scale,在此下拉选择。

完成十列定义后,切到 Data View 即可录入数据。然而,纯图形点的方式难以复现、不易批量修改。更受教材与科研推崇的做法是用 DATA LIST LIST 语法一次性声明变量结构——它等价于在 Variable View 中把所有列填好,且可被保存为 .sps 文件反复运行。语法形式如下:

text
DATA LIST LIST
    /id (F4) name (A12) class (A1) gender (F1)
     chinese (F3) math (F3) english (F3)
     satisfaction (F1) attendance (F3).
VARIABLE LABELS
    id '学号' name '姓名' class '班级' gender '性别'
    chinese '语文成绩' math '数学成绩' english '英语成绩'
    satisfaction '满意度(1-5)' attendance '出勤率'.

DATA LIST LIST 后逐列写明变量名与格式。这里的 F 与 A 是格式类型字母(format type letter),并不是子命令——数值格式以 F 开头(如 F4、F3),字符串格式以 A 开头(如 name (A12)、class (A1));PSPP 的变量只有 numeric 与 string 两种类型,二者混排于同一数据定义之中即可声明整张表。紧接着的 VARIABLE LABELS 为各变量补上中文标签,相当于填好了 Variable View 的"标签"列。这套语法一旦写好,无论谁在何种机器上运行,得到的变量结构都分毫不差——这正是语法驱动工作流相对手工点选的最大优势。

3.3 数据录入与编辑 ​

变量结构定义好之后,下一步是把具体数值填进表格。最直观的方式是在 Data View 中点击单元格直接键入(界面推断,手册未逐项文档化):每一行对应一个学生,依次填入学号、姓名、各班成绩等。单元格录入胜在所见即所得,适合少量、零散的数据补录与修正。

但当数据量较大、或希望录入过程可复现时,应当回到语法:把 DATA LIST 与 BEGIN DATA / END DATA 配对使用,把全部数据作为语法的一部分一次性灌入。沿用 3.2 节的变量定义,完整的录入示例如下:

text
DATA LIST LIST
    /id (F4) name (A12) class (A1) gender (F1)
     chinese (F3) math (F3) english (F3)
     satisfaction (F1) attendance (F3).
BEGIN DATA.
1001 张伟  A 1  88  95  90  5  96
1002 李娜  B 2  92  88  85  4  91
1003 王芳  A 2  79  82  88  3  88
1004 刘洋  C 1  65  70  72  2  75
1005 陈静  B 2  95  91  93  5  98
1006 赵磊  C 1  58  63  60  1  70
END DATA.

录入要点有三。其一,DATA LIST 与 BEGIN DATA/END DATA 必须三件套齐备、一一配对,缺一不可。其二,数据行须严格按变量定义的次序与宽度排列:字符串如 name (A12) 宽度足够,class (A1) 只占 1 字节故只写一个字母;数值按 F 格式对齐,字段间以空白分隔即可。其三也是最易踩的坑——END DATA. 必须独占一行,且以英文句点收尾。若把 END DATA. 与某行数据写在同一行,或漏掉句点,PSPP 会继续把后续内容当作数据读取,导致结构错乱甚至语法报错。

运行上述代码片段后,六个学生的全部信息便落入活动数据集。此时在 Data View 中可见六行九列的完整表格;若此前已用 VARIABLE LABELS 加过标签,输出与浏览时列头将显示中文而非代码。需要指出的是,录入进内存的数据尚未存盘,关闭前务必用 SAVE(见 3.8 节)写出为 .sav 系统文件,否则改动会在退出时丢失。

3.4 从外部文件导入数据 ​

现实中大量数据已经存在于 Excel、OpenDocument 表格或 CSV/文本文件中,逐行手工键入既低效又易错。PSPP 提供了 GET DATA 命令专门读取这些外部格式,但有一个极易混淆的边界必须首先厘清。

IMPORT 与 GET DATA 是两回事。 IMPORT 命令(详见 IMPORT 节点)只能读取 PSPP 自身的系统文件(.sav)与便携文件(.por),它无法直接打开 Excel 工作簿或 CSV 文本。凡遇到 Excel/ODS/CSV/纯文本,正确的入口永远是 GET DATA,而非 IMPORT。初学者常误以为"导入"都走 IMPORT,结果面对 .xlsx 无所适从——记住:外部表格用 GET DATA,PSPP 自家文件才用 IMPORT。

GET DATA 通过 /TYPE 子命令区分来源,而 /TYPE 又是必须且必须作为第一个出现的子命令,取值包括 GNM(Gnumeric)、ODS(OpenDocument,兼容多数 .ods 及现代 Excel 导出的开放格式)、PSQL(PostgreSQL)与 TXT(文本/CSV)。下面分别给出两类最常见场景的完整语法。

场景一:导入 Excel/ODS 电子表格

text
GET DATA /TYPE=ODS /FILE='students.ods'
        /SHEET=NAME 'Sheet1'
        /CELLRANGE=FULL
        /READNAMES=ON
        /ASSUMEDSTRWIDTH=32.

关键子命令说明:/SHEET=NAME 'Sheet1' 指定工作表,也可用 /SHEET=INDEX n 按序号选定;/CELLRANGE=FULL 读取整张表,亦可用 /CELLRANGE=RANGE 'C3:P19' 仅取某个矩形区域;/READNAMES=ON(默认值即开启)把首行当作变量名读入,而非当作数据;/ASSUMEDSTRWIDTH=32 给未被显式指定宽度的字符串变量预设 32 字节——这一点尤其要留心,PSPP 对字符串宽度的默认假设偏窄,长文本列若不加此声明容易被截断,故建议显式给定足够宽度。

场景二:导入 CSV/分隔文本

text
GET DATA /TYPE=TXT /FILE='students.csv'
        /ARRANGEMENT=DELIMITED
        /DELIMITERS=','
        /FIRSTCASE=2
        /VARIABLES=id F4 name A12 class A1 gender F1
                    chinese F3 math F3 english F3
                    satisfaction F1 attendance F3.

此处 /ARRANGEMENT=DELIMITED 表明文件以分隔符划分字段;/DELIMITERS=',' 指明逗号分隔,制表符需用 \t 表示;/FIRSTCASE=2 告知程序跳过第 1 行表头、从第 2 行起读数据——忘记这一行,表头文字会被当成第一条个案,字符串列尚能容错、数值列则会引入脏数据。最后的 /VARIABLES= 逐个列出变量名与格式,它必须放在所有子命令的最后,且是必填项:PSPP 不会像电子表格那样自动推断类型,而要靠你在这里明确每份字段是 F(数值)还是 A(字符串)及其宽度。

无论哪种导入,结果都进入内存中的活动数据集,原文件不被改动。读完建议立即用 SAVE 落盘为 .sav,以免重复导入。若导入后字符串出现莫名截断或首行混入了表头,回头检查 /ASSUMEDSTRWIDTH 与 /FIRSTCASE 这两项即可定位。

3.5 变量属性的深入设置 ​

建好变量、录入数据之后,真正的"数据管理工作"才刚开始。一份能被统计过程正确理解的数据,离不开对标签、值标签、缺失值与度量标准的精细设定。这些属性在 Variable View 中可点选设置,也可用对应命令一次性批量声明——后者显然更利于复现。

变量标签 VARIABLE LABELS 为变量附加说明文字,输出表格的列头将显示标签而非代码:

text
VARIABLE LABELS gender '性别' satisfaction '课程满意度(1-5)' attendance '出勤率(%)'.

值标签 VALUE LABELS 为离散取值对应文字,是类别变量可读化的关键。需要特别记住:VALUE LABELS 会清空该变量已有的全部值标签后再写入,因此它适合首次定义;若要在此基础上追加而不破坏既有标签,须改用 ADD VALUE LABELS。

text
VALUE LABELS gender 1 '男' 2 '女'.
ADD VALUE LABELS satisfaction 1 '非常不满意' 2 '不满意' 3 '一般' 4 '满意' 5 '非常满意'.

上面先为 gender 定义男女,再用 ADD VALUE LABELS 把满意度的五级文字补上,二者互不干扰。若误用 VALUE LABELS 去加第五级,前面四级的标签将被一扫而空。

缺失值 MISSING VALUES 声明哪些取值代表"缺失",是数据清洗的基石(详见 3.8 节)。数值型变量最多可声明 3 个离散缺失值,或一个连续范围;字符串变量规则相同。范围用 THRU 衔接,端点可用 LO/LOWEST 与 HI/HIGHEST 指代最小、最大边界:

text
MISSING VALUES attendance (999) satisfaction (LO THRU 0).

本例把出勤率的 999(明显不可能的值)与满意度中"0 及更小"的区间一并标为缺失。此后多数统计过程默认将这些取值排除在计算之外,从而免于污染均值与标准差。

度量标准 VARIABLE LEVEL 显式指定变量的测量尺度,呼应 3.1 节的铺垫:

text
VARIABLE LEVEL gender class (NOMINAL) satisfaction (ORDINAL)
               chinese math english attendance (SCALE).

这样,gender 与 class 被标为名义、satisfaction 为有序、各成绩与出勤率为标度。过程在默认行为上会参考这一设定,例如对名义变量避免给出无意义的均值。把 3.5 节的四条命令与 3.2、3.3 节的建表录入串成一段语法,便构成了这份学生数据集"从结构到语义"的完整定义,后续所有分析都建立在它之上。

3.6 数据整理:排序、拆分文件、选择个案 ​

数据落盘之后,往往要先按分析意图重新排列或切分,再交给统计过程。这一节的三组命令分别解决"排顺序""分组算""取子集"三类需求。

SORT CASES 按指定变量对个案重新排序,菜单路径为 Data → Sort Cases【手册明示】。语法中可用 (D) 或 (DOWN) 表示降序,(A) 或 (UP) 表示升序,省略则默认升序:

text
SORT CASES BY class (A) chinese (D).

上述命令先按班级升序、班级内再按语文成绩降序排列六个学生。需要强调:SORT CASES 只改变内存中活动数据集的行序,不会改动原 .sav 文件,要保留排序结果仍需 SAVE。

SPLIT FILE 让后续统计过程按某个(或几个)分组变量分别出具结果,而不必手动拆表。它有两种模式:LAYERED(默认,各组的表合并在同一输出中便于对照)与 SEPARATE(每组独立成表)。关闭拆分用 SPLIT FILE OFF.:

text
SORT CASES BY class (A).
SPLIT FILE LAYERED BY class.

这里先按 class 排序再拆分,次序并非偶然——SPLIT FILE 在分组时只识别相邻的同类个案,若事先未排序,同一班级的学生可能分散在多处,拆分出的结果就会支离破碎。拆分效果会一直持续,直到显式 SPLIT FILE OFF. 才解除,因此分析完一组后别忘了关掉,否则后续无关过程也会被无谓分组。

SELECT IF 与 FILTER 都用于"只保留部分个案",但性质截然相反,这是本节最需警觉的分水岭。SELECT IF 会永久删除不满足条件的个案——除非用 TEMPORARY 包裹,否则被剔除的数据无从恢复:

text
SELECT IF attendance >= 75.

执行后,出勤率低于 75 的学生(如示例中 attendance 为 70 的赵磊)将从数据集中彻底消失。相比之下,FILTER 只是"过滤"而非"删除":被过滤变量取值为 0 或缺失的个案在分析中暂时隐藏,却仍留在数据集里,用 FILTER OFF. 即可原样恢复:

text
COMPUTE flag = (attendance >= 75).
FILTER BY flag.
* 此时低于75的个案被暂时排除,但数据仍在
FILTER OFF.

一个来自手册的 SELECT IF 实例是 SELECT IF dob > date.dmy(31,12,1999).,即仅保留 1999 年底之后出生者。请务必牢记:删除不可逆,过滤可恢复。在拿不准该不该丢掉数据时,优先用 FILTER 试探,确认无误后再考虑 SELECT IF。

3.7 变量计算与重新编码 ​

原始数据 seldom 直接满足分析需要:常常要由既有变量算出新指标,或把连续分数归并成等级。PSPP 提供 COMPUTE 与 RECODE 两件利器应对这两种场景。

COMPUTE 按表达式生成(或覆盖)一个变量,语法为 COMPUTE variable = expression.。若目标变量是数值型且尚不存在,PSPP 会自动新建它,默认格式 F8.2:

text
COMPUTE total = chinese + math + english.
COMPUTE average = total / 3.

这两行算出了每个学生的总分与三科平均。然而,当目标变量是字符串时,绝不可依赖自动新建——必须先以 STRING 命令显式声明其宽度,否则 COMPUTE 会因目标类型不明而报错或产生不可预期结果:

text
STRING remark (A6).
COMPUTE remark = '已录入'.

这里先用 STRING remark (A6). 把目标建成 6 字节字符串,再将 COMPUTE 的结果写入,次序不可颠倒。菜单上对应操作位于 Transform → Compute Variable(界面推断,手册未逐项文档化)。

RECODE 把变量的取值按规则映射为新值,常用于分数分级、异常值归并。语法为 RECODE src_vars (源值 = 目标值) … [INTO dest_vars].,省略 INTO 则就地改写源变量,写上 INTO 则把结果存入新变量、保留原值。它支持丰富的特殊记号:THRU 表示含端点的区间;LO/LOWEST 与 HI/HIGHEST 指代最小、最大边界;MISSING、SYSMIS 匹配缺失;ELSE 兜住前面未覆盖的一切(必须放在最后一组);COPY 表示原样保留;(CONVERT) 可把数值型字符串先转为数值再判断。多组规则之间用 / 分隔。

text
RECODE total
    (LOWEST THRU 179 = 1)
    (180 THRU 209 = 2)
    (210 THRU 239 = 3)
    (240 THRU HIGHEST = 4)
    INTO level_num.
ADD VALUE LABELS level_num 1 '不及格' 2 '及格' 3 '良好' 4 '优秀'.

上面把总分划为四级并写入新变量 level_num,再用 ADD VALUE LABELS 配文字。若想把等级直接存成字符串字母,则目标须先 STRING:

text
STRING grade (A6).
RECODE total
    (LOWEST THRU 179 = '不及格')
    (180 THRU 209 = '及格')
    (210 THRU 239 = '良好')
    (240 THRU HIGHEST = '优秀')
    INTO grade.

另一个展示 SYSMIS 与 COPY 的手册式示例是 RECODE x y (0 = 99) (1 THRU 10 = COPY) (1000 THRU HIGHEST = SYSMIS) (ELSE = 999).:它把 0 改写为 99、1~10 原样保留、1000 及以上标为系统缺失、其余一律填 999。善用这些记号,重新编码既能清理异常,又能无损地衍生出可供分组分析的新类别变量。

3.8 数据清洗与缺失值处理 ​

把前面各节串起来,数据管理的最终落点便是清洗:识别并妥善处理脏数据与缺失值,再把整理好的数据集稳妥保存。MISSING VALUES(3.5 节)所定义的那些取值,在 PSPP 中称为用户缺失值(user-missing)。它们的关键作用在于:多数统计过程默认会将用户缺失值在分析中排除,例如 DESCRIPTIVES 默认 NOINCLUDE,意味着被标为缺失的出勤率 999 不会进入均值与标准差的计算,从而避免一个荒谬的取值拉偏整列统计量。若确有需要把缺失值也纳入,才须显式附加 INCLUDE 子命令——这一默认排除机制,正是 3.5 节强调"先标缺失、再算统计"的原因。

一套完整的清洗流程通常如下:先以 MISSING VALUES 锁定异常码(如 attendance (999)),必要时用 RECODE 把这些异常归并或标为缺失;再以 SELECT IF 或 FILTER 剔除无效个案(注意前者的不可逆性);随后用 COMPUTE 与 RECODE 衍生分析所需的总分、等级等变量;最后把内存中这版干净数据写出为系统文件,供后续章节的统计分析直接读取:

text
* 数据清洗与保存示例
MISSING VALUES attendance (999).
COMPUTE total = chinese + math + english.
RECODE total (LOWEST THRU 179 = 1)(180 THRU 209 = 2)
           (210 THRU 239 = 3)(240 THRU HIGHEST = 4) INTO level_num.
ADD VALUE LABELS level_num 1 '不及格' 2 '及格' 3 '良好' 4 '优秀'.
SAVE OUTFILE='students_clean.sav'.

收尾的 SAVE OUTFILE='students_clean.sav'. 把清洗后的活动数据集持久化为 PSPP 系统文件。需要认清:SAVE 写出的是当前内存中的全部内容——包括排序结果、拆分状态解除后的数据、以及所有新建与重编码的变量;而像 SPLIT FILE 这类"过程状态"本身不会被存进文件。此后在第四章及以后的描述统计中,只需 IMPORT 读回这份 .sav,便能以一份语义清晰、缺失妥善处理的数据,直接进入均值、频率与图表的分析,不必再重复本章的整理劳动。

至此,从理解变量类型、建表定义、录入与导入,到属性设定、排序拆分筛选、计算重编码,直至清洗保存,数据管理的完整链路已经闭合。它所产出的那份干净数据集,正是全书中所有统计操作的共同起点。

基于 GNU PSPP 2.0.1 手册与入门教程整理