- 本书赞誉
- 前言
- 目标读者
- 不适合阅读本书的读者
- 本书结构
- 什么是数据处理
- 遇到困难怎么办
- 排版约定
- 使用代码示例
- 致谢
- 第 1 章 Python 简介
- 第 2 章 Python 基础
- 第 3 章 供机器读取的数据
- 第 4 章 处理 Excel 文件
- 第 5 章 处理 PDF 文件 以及用 Python 解决问题
- 第 6 章 数据获取与存储
- 第 7 章 数据清洗:研究、匹配与格式化
- 第 8 章 数据清洗:标准化和脚本化
- 第 9 章 数据探索和分析
- 第 10 章 展示数据
- 第 11 章 网页抓取:获取并存储网络数据
- 第 12 章 高级网页抓取:屏幕抓取器与爬虫
- 第 13 章 应用编程接口
- 第 14 章 自动化和规模化
- 第 15 章 结论
- 附录 A 编程语言对比
- 附录 B 初学者的 Python 学习资源
- 附录 C 学习命令行
- 附录 D 高级 Python 设置
- 附录 E Python 陷阱
- 附录 F IPython 指南
- 附录 G 使用亚马逊网络服务
- 关于作者
- 关于封面
8.2 数据存储
我们已经讲过几种数据存储的方法,现在有了可用的数据,我们先来复习一下这些方法。如果你正在使用数据库、知道预期的表格格式,并想要保存已经清洗过的数据,那么你应该继续使用第 6 章讲过的 Python 库来连接数据库并保存数据。对于这些 Python 库中的大部分库,你都可以使用游标直接向数据库提交。
我们强烈建议在数据库脚本中添加错误信息,在遇到网络故障或数据库故障时可以捕获这些错误信息。我们建议频繁向数据库提交,这样可以避免网络问题或延迟问题影响脚本的运行。
如果你用的是第 6 章中讲过的 SQLite 例子,你需要将新的干净数据保存到你的数据库中。我们来看一下如何做到这一点:
import dataset db = dataset.connect('sqlite:///data_wrangling.db') ➊ table = db['unicef_survey'] ➋ for row_num, data in enumerate(zipped_data): ➌ for question, answer in data: ➍ data_dict = { ➎ 'question': question[1], ➏ 'question_code': question[0], 'answer': answer, 'response_number': row_num, ➐ 'survey': 'mn', } table.insert(data_dict) ➑
❶ 这里我们访问本地数据库。如果你将文件保存到其他目录,一定要修改文件路径,将其修改为数据库文件相对于当前目录的位置(例如,如果数据库文件保存在上层目录中:file:///../datawrangling.db)。
❷ 本行代码创建一个新表:unicef_data。我们知道很多 UNICEF 调查都有相同的规律,所以我们这个数据库名是没有歧义、可复用的。
❸ 我们希望保存所在的行编号,这样每个回答都有一个编号。本行代码用到了 enumerate 函数,这样在数据库中可以找到(每一行 / 每一个回答的)每一条数据(它们的共用一个行编号)。
❹ 我们知道,我们的数据被分割成元组,标题列表是元组的第一个元素,问题回答是元组的第二个元素。本行代码利用 for 循环解析其中包含的数据并进行存储。
❺ 每一个问题和回答在数据库中都有对应的条目,所以我们可以将每行(即每次采访)所有的回答合并在一起。本行代码创建一个字典,其中包含每次采访中每个回答的必要数据。
❻ 标题列表中第二个元素是问题的详细说明。本行代码将其保存为 question,并将 UNICEF 问题代码保存为 question_code。
❼ 为了记录每一行回答(或每一次采访),本行代码添加了 enumerate 函数得到的 rownum。
❽ 最后,利用新表的 insert 方法将新字典插入我们的数据库中。
我们希望将清洗过的数据保存到 SQLite 数据库中。我们创建了一个新的数据库,用到了 enumerate 函数,这样我们可以合并每一个回答(每一行)。如果我们要访问数据,可以访问新表,利用第 6 章学过的函数来查看所有的数据记录,并在需要时进行检索。
如果你希望将清洗过的数据导出到简单文件中,应该也很容易做到。我们来看一下:
from csv import writer def write_file(zipped_data, file_name): with open(file_name, 'wb') as new_csv_file: ➊ wrtr = writer(new_csv_file) ➋ titles = [row[0][1] for row in zipped_data[0]] ➌ wrtr.writerow(titles) ➍ for row in zipped_data: answers = [resp[1] for resp in row] ➎ wrtr.writerow(answers) write_file(zipped_data, 'cleaned_unicef_data.csv') ➏
❶ with...as 的作用是将第一个函数的输出赋值给第二个变量名。本行代码将新文件 open(file_name, 'wb') 赋值给变量 new_csv_file。'wb' 的意思是以二进制模式写入。
❷ 初始化 CSV writer 对象,传入一个打开的文件,然后将 writer 对象赋值给 wrtr 变量。
❸ writer 对象需要数据列表来逐行写入,本行创建的是标题行的标题列表。长标题是元组第一部分的第二个元素,所以对应的代码是 row[0][1]。
❹ 用到了 writer 对象的 writerow 方法,将一个可迭代对象转换成一行逗号分隔的数据。本行代码写入的是标题行。
❺ 利用列表生成式提取出所有回答(元组的第二个元素)。
❻ 将利用列表生成式创建的所有列表或回答写入 CSV 数据文件。
这里我们用到了学过的语法,也用到了一些新语法。我们已经学过如何用 with...as 将简单函数的返回值赋值给一个变量名。这里我们希望将打开的文件赋值给 new_csv_file 变量。这种语法通常用于文件和其他 I/O 对象,因为 Python 执行完 with 代码块中的代码之后,它会自动关闭文件,这很棒!
此外,代码中我们用到了 CSV writer 对象,与 CSV reader 对象的用法类似。writerow 可以将包含所有数据列的列表写入到 CSV 文件中。
writerow 方法接受一个可迭代对象,所以一定要传入一个列表或元组。如果你传入一个字符串,那么看到一些有趣的 CSV(“l,i,k,e,,t,h,i,s”)时不要惊讶。
我们还用到了列表生成式来创建标题列表和回答列表。由于我们不需要用这个函数生成一个新对象或修改过的对象,所以没有返回任何值。这个函数可以帮我们复习目前学过的许多概念。
如果你想用其他方法来保存数据,可以参考第 6 章给出的关于保存数据的建议。保存完清洗过的数据之后,你可以继续进行后面的清洗过程,并对数据进行分析。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论