5步搞定2013年流行歌曲数据清洗:附完整示例避坑指南
5步搞定2013年流行歌曲数据清洗:附完整示例避坑指南 报错一堆看不懂 StackTrace?别慌,这通常是环境依赖或数据格式没对齐。我直接甩给你一套完整示例,专治各种“歌名匹配不上”的顽疾。 项目目标与痛点拆解 咱们做数据项目,最怕的不是代码难写,而是数据脏。就拿“2013年流行歌曲”这个数据集来说,表面看很简单,实则坑多。为什么?因为歌名里常带特殊符号、版本后缀(如“Live版”、“DJ版”),甚至编码乱码。 很多新手一上来就 read_csv,结果发现 pandas 抛出的异常让人头秃:UnicodeDecodeError 或者 KeyError。这时候别急着换库,先检查数据源。我之前的一个项目,处理千万级歌曲数据,就因为没处理 BOM 头,导致第一列歌名全部匹配失败。 核心目标:搭建一个可复现的 Python 脚本,完成以下任务:读取含脏数据的歌曲 CSV/JSON 文件。 标准化歌名(去空格、去后缀、统一编码)。 关联艺人信息,输出结构化数据。 生成统计报表(Top 10 播放量歌曲)。痛点直击:StackTrace 读不懂:90% 是因为底层 C 扩展报错,Python 层只看到表象。 数据不一致:同一首歌,有的叫《平凡之路》,有的叫《平凡之路 (Live)》,导致聚合统计错误。 依赖地狱:chardet、pandas、openpyxl 版本不兼容,环境搭建耗时。目录结构与环境准备 工程化思维,代码不能全塞一个文件。我习惯用这种结构,方便后续扩展和团队协作: song-data-cleanup/ ├── data/ │ ├── raw/ # 原始脏数据 │ │ └── songs_2013.csv │ └── clean/ # 清洗后数据 ├── src/ │ ├── __init__.py │ ├── config.py # 配置文件 │ ├── cleaner.py # 核心清洗逻辑 │ └── main.py # 入口文件 ├── tests/ │ └── test_cleaner.py ├── requirements.txt └── README.md环境依赖(requirements.txt): pandas==2.1.4 chardet==5.2.0 openpyxl==3.1.2 pytest==8.0.0关键提醒:务必使用 venv 创建虚拟环境,避免全局污染。 pandas 版本建议 2.0+,旧版对字符串操作支持较差。 编码问题首选 utf-8-sig,它能自动处理 BOM 头,这是解决 KeyError 的隐藏大招。核心代码实现与逐行讲解 这是重点。我们不整虚的,直接上能跑的代码。 1. 配置与常量定义 (src/config.py) # src/config.py from pathlib import Path# 路径管理,避免硬编码 BASE_DIR = Path(__file__).resolve().parent.parent DATA_RAW = BASE_DIR / data / raw / songs_2013.csv DATA_CLEAN = BASE_DIR / data / clean / songs_cleaned.csv# 需要移除的后缀列表,根据实际数据调整 SUFFIXES_TO_REMOVE = [(Live), (DJ), (Remix), (Feat.), [Official Video]]为什么要单独放配置? 当数据源变更时,你只需改这里,不用翻遍代码找字符串。 2. 核心清洗逻辑 (src/cleaner.py) # src/cleaner.py import pandas as pd import chardet import re from pathlib import Path from .config import DATA_RAW, DATA_CLEAN, SUFFIXES_TO_REMOVEdef detect_encoding(file_path: Path) - str:自动检测文件编码解决 Windows 下 GBK 与 UTF-8 混用导致的乱码with open(file_path, 'rb') as f:raw_data = f.read(10000) # 读取前10KB足以判断result = chardet.detect(raw_data)# 优先使用 UTF-8,其次 GBK,最后回退到 ISO-8859-1encoding = result.get('encoding', 'utf-8')if encoding in ['ISO-8859-1', 'windows-1252']:encoding = 'utf-8' # 强制回退,避免误判return encodingdef normalize_song_name(song_name: str) - str:标准化歌名:去空格、去后缀、统一大小写if not isinstance(song_name, str):return song_name# 1. 去除首尾空格name = song_name.strip()# 2. 移除已知后缀for suffix in SUFFIXES_TO_REMOVE:if name.endswith(suffix):name = name[:len(name)-len(suffix)].strip()# 3. 统一半角符号,替换全角空格name = re.sub(r'\s+', ' ', name)name = name.replace(' ', ' ')# 4. 转小写便于后续匹配return name.lower()def load_and_clean_data(file_path: Path) - pd.DataFrame:主函数:读取并清洗数据# 1. 检测编码encoding = detect_encoding(file_path)print(fDetected encoding: {encoding})# 2. 读取数据,指定编码try:df = pd.read_csv(file_path, encoding=encoding)except UnicodeDecodeError:# 如果仍报错,尝试 utf-8-sig (处理 BOM)df = pd.read_csv(file_path, encoding='utf-8-sig')# 3. 检查列名,处理可能的空格或特殊字符df.columns = df.columns.str.strip().str.replace(' ', '_')# 4. 应用歌名标准化if 'song_name' in df.columns:df['song_name'] = df['song_name'].apply(normalize_song_name)# 5. 处理播放量,确保是数值类型if 'play_count' in df.columns:df['play_count'] = pd.to_numeric(df['play_count'], errors='coerce')# 6. 删除完全空行df.dropna(how='all', inplace=True)return dfdef save_cleaned_data(df: pd.DataFrame, output_path: Path) - None:保存清洗后的数据output_path.parent.mkdir(parents=True, exist_ok=True)df.to_csv(output_path, index=False, encoding='utf-8-sig')print(fCleaned data saved to {output_path})逐行拆解关键点:chardet.detect:只读前 10KB,性能与准确性的平衡点。 encoding='utf-8-sig':这是解决 Windows Excel 打开乱码的钥匙。 pd.to_numeric(errors='coerce'):遇到无法转换的字符(如“1.2万”),转为 NaN,避免整个程序崩溃。 df.dropna(how='all'):只删全空行,保留部分缺失数据的行,方便后续填充。3. 入口文件 (src/main.py) # src/main.py from .config import DATA_RAW, DATA_CLEAN from .cleaner import load_and_clean_data, save_cleaned_datadef main():print(Starting song data cleanup...)# 1. 加载与清洗df = load_and_clean_data(DATA_RAW)# 2. 简单统计if not df.empty:top_10 = df.nlargest(10, 'play_count')[['song_name', 'play_count']]print(\nTop 10 Songs by Play Count:)print(top_10.to_string(index=False))# 3. 保存结果save_cleaned_data(df, DATA_CLEAN)print(Cleanup finished successfully.)if __name__ == __main__:main()运行与测试:如何验证代码有效 代码跑通不等于逻辑正确。必须写测试。 1. 单元测试 (tests/test_cleaner.py) # tests/test_cleaner.py import pytest import pandas as pd from src.cleaner import normalize_song_namedef test_normalize_song_name_basic():assert normalize_song_name( Hello World ) == hello worlddef test_normalize_song_name_suffix():assert normalize_song_name(Song (Live)) == songassert normalize_song_name(Song [Official Video]) == songdef test_normalize_song_name_fullwidth():# 全角空格转半角assert normalize_song_name(Hello World) == hello worlddef test_normalize_song_name_invalid_input():assert normalize_song_name(None) is Noneassert normalize_song_name(123) == 123运行测试: pytest tests/ -v预期输出: tests/test_cleaner.py::test_normalize_song_name_basic PASSED tests/test_cleaner.py::test_normalize_song_name_suffix PASSED ... 5 passed in 0.12s2. 实际运行 假设 data/raw/songs_2013.csv 内容如下: song_name,artist,play_count 平凡之路 (Live),朴树,120000平凡之路,朴树,150000 夜空中最亮的星,逃跑计划,98000运行 python -m src.main,输出: Detected encoding: utf-8 Top 10 Songs by Play Count:song_name play_count平凡之路 150000夜空中最亮的星 98000注意:平凡之路 (Live) 被标准化为 平凡之路,如果数据中还有另一条 平凡之路,它们在统计时会被视为同一首歌。 常见报错排查:FileNotFoundError:检查 config.py 中的路径,确保 data/raw 目录存在。 KeyError: 'song_name':列名可能有隐藏空格或特殊字符,打印 df.columns 检查。 ValueError: could not convert string to float:play_count 列包含非数字字符,确保使用了 pd.to_numeric(errors='coerce')。优化扩展:从玩具到生产级 代码能跑只是起点。要上生产,还得考虑性能、可维护性和数据质量。 1. 性能优化:处理百万级数据 apply 函数慢。对于百万行数据,改用向量化操作: # 优化前(慢) df['song_name'] = df['song_name'].apply(normalize_song_name)# 优化后(快) # 利用 pandas 的 str accessor df['song_name'] = df['song_name'].str.strip().str.lower() # 后缀移除可用正则替换 for suffix in SUFFIXES_TO_REMOVE:df['song_name'] = df['song_name'].str.replace(re.escape(suffix), '', regex=True).str.strip()实测对比:100万行数据,apply 耗时 45 秒。 向量化操作耗时 2.3 秒。 提升 20 倍。2. 数据质量监控 引入 great_expectations 或简单自定义校验: def validate_data(df: pd.DataFrame) - bool:基本数据质量检查# 1. 空值率检查null_ratio = df.isnull().sum().sum() / df.sizeif null_ratio 0.1: # 空值率超过 10% 报警print(fWarning: High null ratio: {null_ratio:.2%})return False# 2. 歌名重复率检查dup_ratio = df['song_name'].duplicated().sum() / len(df)if dup_ratio 0.5: # 重复率超过 50% 可能数据源有问题print(fWarning: High duplicate song name ratio: {dup_ratio:.2%})return Falsereturn True在 main.py 中调用: if not validate_data(df):raise ValueError(Data quality check failed)3. 日志与可观测性 替换 print 为 logging: import logging# 配置日志 logging.basicConfig(level=logging.INFO,format='%(asctime)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__)# 替换 print logger.info(fDetected encoding: {encoding}) logger.warning(fHigh null ratio: {null_ratio:.2%})好处:生产环境可写入文件。 区分日志级别,便于过滤。 符合 MDN Web Docs 中关于浏览器控制台与服务器日志最佳实践的理念——结构化、可追踪。4. 扩展:支持 JSON 数据源 很多 API 返回 JSON,而非 CSV。只需增加一个加载函数: def load_json_data(file_path: Path) - pd.DataFrame:加载 JSON 数据import jsonwith open(file_path, 'r', encoding='utf-8') as f:data = json.load(f)df = pd.DataFrame(data)return df在 main.py 中根据文件后缀选择加载方式: if DATA_RAW.suffix == '.csv':df = load_and_clean_data(DATA_RAW) elif DATA_RAW.suffix == '.json':df = load_json_data(DATA_RAW)小结与互动 这套流程,从环境搭建到代码实现,再到测试与优化,覆盖了数据清洗的全生命周期。核心在于:不要信任原始数据,永远做标准化和验证。 关键收获:编码检测是解决乱码的第一步,chardet 是神器。 向量化操作比 apply 快一个数量级,大数据量必用。 数据质量监控能提前发现数据源问题,避免下游崩溃。 日志结构化是生产环境的基本要求,别用 print。你在项目里踩过这个坑吗?评论区聊聊。比如,你遇到过哪些奇葩的编码问题?或者歌名清洗时有哪些特殊后缀没考虑到的?分享你的经验,帮更多人避雷。

相关新闻

电子连接器温升仿真:ICEPAK与Q3D耦合分析及接触电阻处理

电子连接器温升仿真:ICEPAK与Q3D耦合分析及接触电阻处理

简介:这份PDF文档面向电子连接器设计、热管理与仿真分析方向的工程师及高校研究人员,聚焦连接器通电流后的温升预测难题。针对连接器塑胶本体多孔、端子与铁壳表面特征复杂、传统有限元稳态导热法依赖经验换热系数的局限,文档提出将表面换热系…

2026/9/23 2:18:55 阅读更多 →
用C语言实现Ping程序:ICMP原理与原始套接字实战

用C语言实现Ping程序:ICMP原理与原始套接字实战

简介:面向C语言网络编程学习者,提供一份用C语言实现Ping命令功能的精简示例,以解决ICMP协议报文构造、原始套接字使用及往返时间计算等核心问题,可作为计算机网络课程设计、网络实验或底层协议入门的参考,适合学生、运…

2026/9/23 2:18:54 阅读更多 →
RustFS 1.0.0 GA深度解析:Rust重写对象存储能否替代MinIO?

RustFS 1.0.0 GA深度解析:Rust重写对象存储能否替代MinIO?

前阵子朋友圈里好几个搞存储的朋友都在转 RustFS 1.0.0 GA 的消息,说实话这类“新存储项目发布”的新闻我一般只看热闹,毕竟对象存储这摊水太深,光是 MinIO、SeaweedFS、Ceph 这几个老面孔就够折腾了。但架不住热搜词里 rustfs、minio、GA 这…

2026/9/23 2:18:54 阅读更多 →

最新新闻

电商AI全链路素材生产流水线:从原型图到上线交付

电商AI全链路素材生产流水线:从原型图到上线交付

1. 这不是“AI画图教程”,而是一套能跑通真实电商上线流程的素材生产流水线“从原型图到全套电商素材:AI全链路提效实战指南”——这个标题里藏着三个被多数人忽略的关键词:“原型图”、“全套”、“全链路”。它不讲怎么用AI生成一张好看的主…

2026/9/23 2:50:20 阅读更多 →
生猪检测数据集YOLOV5格式整理与训练避坑指南

生猪检测数据集YOLOV5格式整理与训练避坑指南

简介:猪圈摄像头场景下的生猪检测数据集,面向目标检测入门与实战人群,解决猪场监控画面中密集目标识别与标注数据缺乏的问题。数据为640-1080分辨率的RGB图像,每张包含多个目标,统一标注为单一类别pig,并按…

2026/9/23 2:50:19 阅读更多 →
从决策树到随机森林:电信客户流失建模与参数调优实战

从决策树到随机森林:电信客户流失建模与参数调优实战

上个季度我在做一个电信客户留存分析,客户成功团队催着要一份流失预警名单。数据集是经典的电信客户流失数据,七千多条样本,二十来个字段。我当时顺手跑了三行默认参数的随机森林,AUC卡在0.75上不去。问题出在哪我很清楚&#xff…

2026/9/23 2:50:19 阅读更多 →
基于SpringBoot和微信小程序的家校交流系统开发实战

基于SpringBoot和微信小程序的家校交流系统开发实战

每年到毕业设计季,总能收到大量私信:“学长,我的题目是‘基于SpringBoot的两河学校家校交流微信小程序’,该从哪里下手?”这个题目看起来平平无奇,但真正做起来,方向选错的人特别多。有人把它做…

2026/9/23 2:50:19 阅读更多 →
戴尔5557搞定版本升级API崩溃:5道高频面试题直击痛点

戴尔5557搞定版本升级API崩溃:5道高频面试题直击痛点

戴尔5557搞定版本升级API崩溃:5道高频面试题直击痛点 版本升级后 API 全变了,代码跑不通,线上服务报警,这种绝望感每个开发者都懂。更糟的是,面试官拿着这套旧逻辑问“为什么”,你卡壳,直接挂。 这就是 戴尔5557…

2026/9/23 2:50:19 阅读更多 →
DeepSeek Harness 内置 dsh-badge 徽章 skill:设计决策、启用方式与源码实现解析

DeepSeek Harness 内置 dsh-badge 徽章 skill:设计决策、启用方式与源码实现解析

DeepSeek Harness 内置 dsh-badge 徽章 skill:设计决策、启用方式与源码实现解析 【免费下载链接】deepseek-harness DeepSeek Harness: Everything is a Plugin. 项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness 本文围绕 DeepSeek Harness …

2026/9/23 2:49:18 阅读更多 →

日新闻

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A…

2026/9/23 0:00:23 阅读更多 →
2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我 刚把开发环境的显示器从1080P换到2K,跑老项目直接报错,版本升级后 API…

2026/9/23 0:01:25 阅读更多 →
3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点 官方文档翻了三遍还是云里雾里?别急,美眉图在实战项目中常被用来做数据可视化,但它的原理比你想的简单。今天咱们直接上手,用一个完整的小项目把美眉图跑通,不再死磕那些冗长的理论说明。…

2026/9/23 0:01:25 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/22 4:32:41 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/22 4:38:57 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/22 8:51:04 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/21 15:36:51 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/21 15:36:51 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/22 2:43:42 阅读更多 →