第12讲 · 清洗并分析成绩数据

清洗并分析成绩数据

把虚构成绩文本清洗成结构化记录,再完成统计与异常检查。

1读取原始成绩文件
2清洗并保存有效记录
3完成统计并生成报告

处理前后对比

处理前:空行、字段缺失、分数不是数字 · 处理后:保留4条有效记录,识别2条异常记录

处理前 · scores.txt
小林,Python,88

格式错误
小郑,AI协作,优秀
小周,数据整理,76
小吴,Python,59
小陈,Python,94
处理后 · score_report.txt
成绩分析报告
有效记录:4
异常记录:2
平均分:79.25
最高分:小陈 94
不及格:小吴 59

同一份数据经过读取、清洗、结构化和统计,最终生成可以直接验收的分析报告。

查看并逐行读取成绩文件

read_score_lines.py
import os

WORKSPACE = "/tmp/lesson12_workspace"
SOURCE = "小林,Python,88\n\n格式错误\n小郑,AI协作,优秀\n小周,数据整理,76\n小吴,Python,59\n小陈,Python,94"

def prepare_scores():
    os.makedirs(WORKSPACE, exist_ok=True)
    path = os.path.join(WORKSPACE, "scores.txt")
    with open(path, "w", encoding="utf-8") as fixture:
        fixture.write(SOURCE)
    return path

path = prepare_scores()
line_number = 0
with open(path, "r", encoding="utf-8") as file:
    for line in file:
        line = line.strip()
        if not line:
            continue
        line_number += 1
        print(f"第{line_number}条:{line}")
with open(path, "r", encoding="utf-8") as file:
以UTF-8编码读取文本
for line in file:
逐行遍历文件
line = line.strip()
清理每行首尾空白
if not line: continue
跳过空行
1先观察原始文件中的正常与异常记录
2open以只读模式打开文件
3for按顺序取得每一行
4strip清理空白并跳过空行

拆分一行成绩数据

parse_score_row.py
import os

WORKSPACE = "/tmp/lesson12_workspace"
SOURCE = "小林,Python,88\n\n格式错误\n小郑,AI协作,优秀\n小周,数据整理,76\n小吴,Python,59\n小陈,Python,94"

def prepare_scores():
    os.makedirs(WORKSPACE, exist_ok=True)
    path = os.path.join(WORKSPACE, "scores.txt")
    with open(path, "w", encoding="utf-8") as fixture:
        fixture.write(SOURCE)
    return path

line = "小林,Python,88"
parts = line.split(",")
name, subject, score = parts
score = int(score)
print("字段列表:", parts)
print("姓名:", name)
print("科目:", subject)
print("分数:", score)
print("分数类型:", type(score).__name__)
parts = line.split(",")
按英文逗号拆分
name, subject, score = parts
解包三个字段
score = int(score)
转换分数类型
1split返回字符串列表
2解包按顺序接收三个字段
3int把分数字符串转换为整数

检查成绩字段数量

check_score_fields.py
import os

WORKSPACE = "/tmp/lesson12_workspace"
SOURCE = "小林,Python,88\n\n格式错误\n小郑,AI协作,优秀\n小周,数据整理,76\n小吴,Python,59\n小陈,Python,94"

def prepare_scores():
    os.makedirs(WORKSPACE, exist_ok=True)
    path = os.path.join(WORKSPACE, "scores.txt")
    with open(path, "w", encoding="utf-8") as fixture:
        fixture.write(SOURCE)
    return path

rows = ["小林,Python,88", "格式错误", "小周,数据整理,76"]
invalid_count = 0
for line in rows:
    parts = line.split(",")
    if len(parts) != 3:
        invalid_count += 1
        print("跳过字段不完整:", line)
        continue
    print("字段完整:", parts)
print("字段异常:", invalid_count)
if len(parts) != 3:
判断字段数量是否完整
invalid_count += 1
累计异常记录
continue
跳过当前记录
1len取得字段数量
2三个字段才是完整记录
3continue跳过当前异常行

检查分数是否有效

check_score_value.py
import os

WORKSPACE = "/tmp/lesson12_workspace"
SOURCE = "小林,Python,88\n\n格式错误\n小郑,AI协作,优秀\n小周,数据整理,76\n小吴,Python,59\n小陈,Python,94"

def prepare_scores():
    os.makedirs(WORKSPACE, exist_ok=True)
    path = os.path.join(WORKSPACE, "scores.txt")
    with open(path, "w", encoding="utf-8") as fixture:
        fixture.write(SOURCE)
    return path

rows = ["小林,Python,88", "小郑,AI协作,优秀", "小周,数据整理,76"]
valid_scores = []
for line in rows:
    name, subject, score = line.split(",")
    try:
        score = int(score)
    except ValueError:
        print("跳过无效分数:", line)
        continue
    valid_scores.append(score)
    print("有效分数:", name, score)
print("有效分数数量:", len(valid_scores))
try:
执行可能失败的类型转换
score = int(score)
尝试得到整数分数
except ValueError:
捕获转换失败
1try尝试转换分数
2ValueError表示内容不能转成整数
3except只处理对应的转换失败

保存结构化成绩记录

build_score_records.py
import os

WORKSPACE = "/tmp/lesson12_workspace"
SOURCE = "小林,Python,88\n\n格式错误\n小郑,AI协作,优秀\n小周,数据整理,76\n小吴,Python,59\n小陈,Python,94"

def prepare_scores():
    os.makedirs(WORKSPACE, exist_ok=True)
    path = os.path.join(WORKSPACE, "scores.txt")
    with open(path, "w", encoding="utf-8") as fixture:
        fixture.write(SOURCE)
    return path

name, subject, score = "小林", "Python", 88
record = {"name": name, "subject": subject, "score": score}
records = []
records.append(record)
print("记录数量:", len(records))
print("第一条记录:", records[0])
print("姓名与分数:", records[0]["name"], records[0]["score"])
record = {"name": name, "subject": subject, "score": score}
创建一条命名清楚的记录
records.append(record)
加入有效记录列表
record["score"]
按键读取整数分数
1字典保存一条记录
2列表保存多条记录
3append只加入通过校验的数据

计算总分、平均分与最高分

calculate_score_statistics.py
import os

WORKSPACE = "/tmp/lesson12_workspace"
SOURCE = "小林,Python,88\n\n格式错误\n小郑,AI协作,优秀\n小周,数据整理,76\n小吴,Python,59\n小陈,Python,94"

def prepare_scores():
    os.makedirs(WORKSPACE, exist_ok=True)
    path = os.path.join(WORKSPACE, "scores.txt")
    with open(path, "w", encoding="utf-8") as fixture:
        fixture.write(SOURCE)
    return path

records = [
    {"name": "小林", "score": 88},
    {"name": "小周", "score": 76},
    {"name": "小吴", "score": 59},
    {"name": "小陈", "score": 94},
]
total = sum(record["score"] for record in records)
average = total / len(records)
highest = max(records, key=lambda record: record["score"])
print("总分:", total)
print(f"平均分:{average:.2f}")
print("最高分:", highest["name"], highest["score"])
sum(record["score"] for record in records)
汇总全部分数
total / len(records)
计算平均分
max(records, key=lambda record: record["score"])
取得最高分记录
1sum计算总分
2len提供有效记录数量
3max返回最高分整条记录
4格式化平均分保留两位小数

统计各科目记录数

count_score_subjects.py
import os

WORKSPACE = "/tmp/lesson12_workspace"
SOURCE = "小林,Python,88\n\n格式错误\n小郑,AI协作,优秀\n小周,数据整理,76\n小吴,Python,59\n小陈,Python,94"

def prepare_scores():
    os.makedirs(WORKSPACE, exist_ok=True)
    path = os.path.join(WORKSPACE, "scores.txt")
    with open(path, "w", encoding="utf-8") as fixture:
        fixture.write(SOURCE)
    return path

records = [
    {"subject": "Python"}, {"subject": "数据整理"},
    {"subject": "Python"}, {"subject": "Python"},
]
subject_counts = {}
for record in records:
    subject = record["subject"]
    subject_counts[subject] = subject_counts.get(subject, 0) + 1
for subject in sorted(subject_counts):
    print(subject, subject_counts[subject])
subject_counts = {}
准备空计数字典
subject_counts.get(subject, 0) + 1
读取旧次数并加一
sorted(subject_counts)
稳定输出科目顺序
1科目名作为字典键
2出现次数作为字典值
3get为第一次出现的科目提供零起点

筛选不及格成绩记录

filter_failing_scores.py
import os

WORKSPACE = "/tmp/lesson12_workspace"
SOURCE = "小林,Python,88\n\n格式错误\n小郑,AI协作,优秀\n小周,数据整理,76\n小吴,Python,59\n小陈,Python,94"

def prepare_scores():
    os.makedirs(WORKSPACE, exist_ok=True)
    path = os.path.join(WORKSPACE, "scores.txt")
    with open(path, "w", encoding="utf-8") as fixture:
        fixture.write(SOURCE)
    return path

records = [
    {"name": "小林", "subject": "Python", "score": 88},
    {"name": "小周", "subject": "数据整理", "score": 76},
    {"name": "小吴", "subject": "Python", "score": 59},
]
failing = []
for record in records:
    if record["score"] < 60:
        failing.append(record)
for record in failing:
    print(record["name"], record["subject"], record["score"])
if record["score"] < 60:
判断是否低于及格线
failing.append(record)
保存命中的完整记录
1遍历全部有效记录
2分数低于60时命中
3保留完整记录用于报告

生成成绩分析报告

score_analyzer.py
records, invalid_count = load_records(path)
report_path = os.path.join(WORKSPACE, "score_report.txt")
with open(report_path, "w", encoding="utf-8") as file:
    file.write(report + "\n")

总结成绩分析项目

1输入:读取UTF-8文本文件
2清洗:跳过空行,检查字段与分数
3结构化:用字典列表保存有效记录
4分析:完成总体、分类与条件统计
5输出:生成并打开成绩分析报告

语法拆解

read → split
读取并拆分原始数据
validate → append
校验后保存统一记录
aggregate → write
统计并写出报告文件
课堂 Python 解释器
点击“逐步运行”后,这里会显示结果。
Python:按执行步骤显示结果。