2.6 读取多个 CSV 文件
本章到目前为止,都在演示如何处理单个 CSV 文件。有些时候,你也只需要处理一个文件。在这些情况下,上面的示例可以告诉你如何使用 Python 程序去处理。尽管只是一个文件,这个文件也可能太大,不能手工处理,因此用程序处理文件还可以减少人为犯错的概率,比如复制 / 粘贴错误和输入错误。
但是,在大多数情况下,你需要处理的文件很多,多到使用手工处理效率非常低或者根本不可行。在这种情况下,Python 会给你惊喜,因为它可以让你自动化和规模化地进行数据处理,远远超过手工处理能够达到的限度。这一小节介绍 Python 内置的 glob 模块,并在本章前面示例的基础上,演示如何规模化地处理 CSV 文件。
为了处理多个 CSV 文件,首先需要创建多个 CSV 文件。下面的示例中创建了 3 个 CSV 文件,但是请记住,这里介绍的技术可以扩展为处理计算机允许的任意多的文件,多到几百个,甚至更多!
· 第一个 CSV 文件
(1) 打开一个电子表格程序。
(2) 加入图 2-12 所示的数据。
(3) 将文件保存为 sales_january_2014.csv。
图 2-12:第一个 CSV 文件:sales_january_2014.csv
· 第二个 CSV 文件
(1) 打开一个电子表格程序。
(2) 加入图 2-13 所示的数据。
(3) 将文件保存为 sales_february_2014.csv。
图 2-13:第二个 CSV 文件:sales_february_2014.csv
· 第三个 CSV 文件
(1) 打开一个电子表格程序。
(2) 加入图 2-14 所示的数据。
(3) 将文件保存为 sales_march_2014.csv。
图 2-14:第三个 CSV 文件:sales_march_2014.csv
文件计数与文件中的行列计数
下面先从一些简单的行列计数开始。行列计数虽然相当基础,但却是熟悉新数据集的好方式。尽管有些时候你知道要处理的输入文件中的内容,但在多数情况下,文件是别人发送给你的,你不会立即知道是哪些内容。这时,计算一下要处理的文件数量以及每个文件中行与列的数量,会对你有所帮助。
要处理前一节中创建的 3 个 CSV 文件,在文本编辑器中输入下列代码,然后将文件保存为 8csv_reader_counts_for_multiple_files.py:
1 #!/usr/bin/env python3 2 import csv 3 import glob 4 import os 5 import sys 6 input_path = sys.argv[1] 7 file_counter = 0 8 for input_file in glob.glob(os.path.join(input_path,'sales_*')): 9 row_counter = 1 10 with open(input_file, 'r', newline='') as csv_in_file: 11 filereader = csv.reader(csv_in_file) 12 header = next(filereader, None) 13 for row in filereader: 14 row_counter += 1 15 print('{0!s}: \t{1:d} rows \t{2:d} columns'.format(\ 16 os.path.basename(input_file), row_counter, len(header))) 17 file_counter += 1 18 print('Number of files: {0:d}'.format(file_counter))
第 3~4 行代码导入 Python 内置的 glob 和 os 模块,以使我们可以使用它们提供的函数列出和解析你要处理的文件路径名。glob 模块可以定位匹配于某个特定模式的所有路径名。模式中可以包含 Unixshell 风格的通配符,比如 *。在上面这个具体示例中,要搜索的模式是 'sales_*'。这个模式表示要搜索所有文件名以 sales_ 开头并且下划线后面可以是任意字符的文件。因为你创建了 3 个输入文件,所以应该知道使用这段代码可以识别出这 3 个文件,它们的文件名都是以 sales_ 开头的,下划线后面是不同的月份。
以后你可能会想找出一个文件夹下面的所有 CSV 文件,而不是以 sales_ 开头的文件。如果这样,那么你可以简单地将脚本中的模式从 'sales_*' 改变为 '*.csv'。因为 '.csv' 是所有 CSV 文件名末尾的模式,这样做可以有效地找出所有 CSV 文件。
os 模块包含了用于解析路径名的函数。例如,os.path.basename(path) 返回 path 的基本文件名。即,如果 path 是 C:\Users\Clinton\Desktop\my_input_file.csv,那么 os.path.basename(path) 返回 my_input_file.csv。
第 8 行代码是将数据处理扩展到多个文件中的关键语句。此行代码创建了一个 for 循环,在一个输入文件集合中迭代,并使用 glob 模块和 os 模块中的函数创建了一个输入文件列表以供处理。这行代码比较复杂,所以需要仔细地分析一下。os 模块中的 os.path.join() 函数将函数圆括号中的两部分连接在一起。input_path 是包含输入文件的文件夹的路径,'sales_*' 代表任何以模式 'sales_' 开头的文件名。
glob 模块中的 glob.glob() 函数将 'sales_*' 中的星号(*)转换为实际的文件名。在这个示例中,glob.glob() 函数和 os.path.join() 函数创建了一个包含 3 个输入文件的列表:
['C:\Users\Clinton\Desktop\sales_january_2014.csv', 'C:\Users\Clinton\Desktop\sales_february_2014.csv', 'C:\Users\Clinton\Desktop\sales_march_2014.csv']
然后,这行开头的 for 循环语句对于列表中每个输入文件执行下面缩进的各行代码。
第 15 行代码是一个 print 语句,打印出每个输入文件的文件名、文件中的行数、文件中的列数。print 语句中的制表符 \t 不是必需的,但是在各列之间放上一个制表符可以对齐这 3 列。这行代码使用 {} 占位符将 3 个值传入 print 语句。对于第一个值,使用 os.path.basename() 函数从完整路径名中抽取出基本文件名。对于第二个值,使用 row_counter 变量来计算每个输入文件中的总行数。最后,对于第三个值,使用内置的 len 函数计算出列表变量 header 中的值的数量,这个列表变量中包含了每个输入文件的列标题列表。我们使用这个值作为每个输入文件中的列数。最后,在第 15 行代码打印了每个文件的信息之后,第 17 行代码使用 file_counter 变量中的值显示出脚本处理的文件的数量。
要运行这个脚本,在命令行中输入以下命令,然后按回车键:
python 8csv_reader_counts_for_multiple_files.py "C:\Users\Clinton\Desktop"
请注意在命令行中,脚本名称后面是一个文件夹路径。在前面的示例中,这个位置都是输入文件名。在这个示例中,你要处理多个文件,所以必须使用包含所有输入文件的文件夹。
你可以看到 3 个输入文件的文件名和每个文件中的行数与列数被打印到屏幕上。在关于 3 个文件的信息行下面,最后的 print 语句显示了之前处理过的输入文件总数。显示信息如图 2-15 所示:
图 2-15:Python 脚本输出:3 个 CSV 文件中的行数与列数
输出结果显示脚本处理了 3 个文件,每个文件都有 7 行和 5 列。
这个示例演示了如何读取多个 CSV 文件并将每个文件的基本信息打印到屏幕上。在你不熟悉要处理的文件时,将要处理文件的基本信息打印出来是非常有用的。知道了输入文件的数量和每个文件中行与列的数量,你就对数据处理的工作量以及文件内容的一致性有了一个大致的概念。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论