第 3 章 Excel 文件

第 3 章 Excel 文件

Microsoft Excel 几乎无处不在,使用 Excel 既可以保存客户、库存和雇员数据,还可以跟踪运营、销售和财务活动。人们在商业活动中使用 Excel 的方式五花八门,难以计数。因为 Excel 是商业活动中不可或缺的工具,所以知道如何使用 Python 处理 Excel 数据可以使你将 Python 加入到数据处理工作流中,进而从其他人那里接收数据,并以他们习惯接受的方式分享数据处理结果。

与 Python 的 csv 模块不同,Python 中没有处理 Excel 文件(就是带有 .xls 和 .xlsx 扩展名的文件)的标准模块。要完成本章中的示例,你需要 xlrdxlwt 扩展包。xlrdxlwt 扩展包使 Python 可以在任何操作系统上处理 Excel 文件,而且对 Excel 日期型数据的支持非常好。如果你安装了 Anaconda Python,那么就已经有了这两个扩展包,因为它们是与安装程序捆绑在一起的。如果你是从 Python.org 网站安装的 Python,那么还需要按照附录 A 中的指示下载并安装这两个扩展包。

简单解释一下术语:当提到“Excel 文件”时,和“Excel 工作簿”是一回事。Excel 工作簿包含一个或多个 Excel 工作表。在本章中,会交替使用“文件”和“工作簿”这两个词,并将工作簿中的个别工作表直接称为工作表。

和第 2 章中处理 CSV 文件一样,本章先给出使用基础 Python 完成的示例,这样你可以清楚数据处理的每个逻辑步骤,然后给出使用 pandas 完成的示例,这样你可以获得一个(通常情况下)更短小精悍的示例(尽管有一点抽象),你可以对这个示例进行复制和修改,然后用在自己的工作中。

要开始本章示例,需要先创建一个 Excel 工作簿。

(1) 打开 Microsoft Excel。

(2) 在工作簿中添加 3 个独立的工作表,并分别命名为 january_2013、february_2013 和 march_2013。然后分别添加数据,如图 3-1、图 3-2 和图 3-3 所示。

(3) 将工作簿保存为 sales_2013.xlsx。

{%}

图 3-1:工作表 1:january_2013

{%}

图 3-2:工作表 2:february_2013

{%}

图 3-3:工作表 3:march_2013

3.1 内省Excel工作簿

既然我们已经有了一个包含 3 个工作表的 Excel 工作簿,那么就开始学习如何在 Python 中处理 Excel 工作簿吧。提示一下,本章中要使用 xlrdxlwt 扩展包,所以请确认你已经下载并安装了这些扩展包。

你可能已经知道,Excel 文件与 CSV 文件至少在两个重要方面有所不同。首先,与 CSV 文件不同,Excel 文件不是纯文本文件,所以你不能在文本编辑器中打开它并查看数据。为了验证这一点,可以点击刚才创建的 Excel 工作簿并按鼠标右键,然后用一个文本编辑器(比如 Notepad 或者 TextWrangler)打开它。你会看到一堆乱码,而不是正常字符。

其次,与 CSV 文件不同,一个 Excel 工作簿被设计成包含多个工作表,所以你需要知道在不用手动打开工作簿的前提下,如何通过工作簿内省(也就是内部检查)获取其中所有工作表的信息。通过内省一个工作簿,你可以在实际开始处理工作簿中的数据之前,检查工作表的数目和每个工作表中的数据类型和数据量。

内省 Excel 文件有助于确定文件中的数据确实是你需要的,并对数据一致性和完整性做一个初步检查。也就是说,弄清楚输入文件的数量,以及每个文件中的行数和列数,可以使你对数据处理工作的工作量和文件内容的一致性有个大致的概念。

在知道了如何内省工作簿中的工作表之后,下面开始分析单个工作表,然后处理多个工作表和多个工作簿。

要确定工作簿中工作表的数量、名称和每个工作表中行列的数量,在文本编辑器中输入下列代码,然后将文件保存为 1excel_introspect_workbook.py:

1 #!/usr/bin/env python3
2 import sys
3 from xlrd import open_workbook
4 input_file = sys.argv[1]
5 workbook = open_workbook(input_file)
6 print('Number of worksheets:', workbook.nsheets)
7 for worksheet in workbook.sheets():
8     print("Worksheet name:", worksheet.name, "\tRows:",\
9         worksheet.nrows, "\tColumns:", worksheet.ncols)

图 3-4、图 3-5 和图 3-6 分别展示了 Anaconda Spyder、Notepad++(Windows)和 TextWrangler(macOS)中的脚本。

{%}

图 3-4:Anaconda Spyder 中的 Python 脚本 1excel_introspect_workbook.py

{%}

图 3-5:Notepad++(Windows)中的 Python 脚本 1excel_introspect_workbook.py

{%}

图 3-6:TextWrangler(macOS)中的 Python 脚本 1excel_introspect_workbook.py

第 3 行代码导入 xlrd 模块的 open_workbook 函数来读取和分析 Excel 文件。

第 7 行代码使用 open_workbook 函数打开一个 Excel 输入文件,并赋给一个名为 workbook 的对象。workbook 对象中包含了工作簿中所有可用的信息,所以可以使用这个对象从工作簿中得到单独的工作表。

第 8 行代码打印出工作簿中工作表的数量。

第 9 行代码是一个 for 循环语句,在工作簿中的所有工作表之间迭代。workbook 对象的 sheets 方法可以识别出工作簿中所有的工作表。

第 10 行代码在屏幕上打印出每个工作表的名称和每个工作表中行与列的数量。print 语句使用 worksheet 对象的 name 属性来确定每个工作表的名称。同样,它使用 nrowsncols 属性来分别确定每个工作表中行与列的数量。

如果你在 Spyder IDE 中创建了这个文件,按下列步骤运行脚本。

(1) 在 IDE 左上角点击 Run 下拉菜单。

(2) 选择“Configure”。

(3) 当 Run Settings 窗口打开后,选择“Command line options”复选框,然后输入“sales_2013.xlsx”(参见图 3-7)。

(4) 确定“Working directory”是你保存脚本和 Excel 文件的目录。

(5) 点击 Run。

当点击了 Run 按钮(或者是 Run Settings 窗口中的 Run 按钮,或者是 IDE 左上角绿色的 Run 按钮)之后,你会看到输出显示在 IDE 右下角的 Python 控制台窗格上。图 3-7 显示了 Run 下拉菜单、Run Setting 窗口中的关键设置和红框内的输出。

{%}

图 3-7:在 Anaconda Spyder 中设置命令行参数

当然,你可以在命令行窗口或终端窗口中运行脚本。要完成这个操作,根据不同的操作系统,使用如下命令。

  • Windows 操作系统

    python 1excel_introspect_workbook.py sales_2013.xlsx
    
  • macOS 操作系统

    chmod +x 1excel_introspect_workbook.py
    ./1excel_introspect_workbook.py sales_2013.xlsx
    
    

你可以看到输出被打印到屏幕上,如图 3-8(Windows)或图 3-9(macOS)所示。

{%}

图 3-8:命令行窗口(Windows)中的 Python 脚本输出

{%}

图 3-9:终端窗口(macOS)中的 Python 脚本输出

第一行输出表示 Excel 输入文件 sale 2013.xlsx 中包含 3 个工作表。下面三行说明了 3 个工作表分别名为 january_2013、february_2013 和 march_2013。它们还说明了每个工作表中包含 7 行(包括标题行)和 5 列。

掌握了如何使用 Python 来内省 Excel 工作簿之后,就可以开始学习如何以不同的方法来解析单个工作表了。在此之后,本章会将这种方法扩展为处理多个工作表和多个工作簿。

3.2 处理单个工作表

尽管 Excel 工作簿可以包含多个工作表,有些时候你也只是需要一个工作表中的数据。此外,只要你知道如何分析一个工作表,就可以很容易地扩展到分析多个工作表。

3.2.1 读写Excel文件

基础Python和xlrdxlwt模块

要使用基础 Python 和 xlrdxlwt 模块读写 Excel 文件,在文本编辑器中输入下列代码,然后将文件保存为 2excel_parsing_and_write.py:

 1 #!/usr/bin/env python3
 2 import sys
 3 from xlrd import open_workbook
 4 from xlwt import Workbook
 5 input_file = sys.argv[1]
 6 output_file = sys.argv[2]
 7 output_workbook = Workbook()
 8 output_worksheet = output_workbook.add_sheet('jan_2013_output')
 9 with open_workbook(input_file) as workbook:
10     worksheet = workbook.sheet_by_name('january_2013')
11     for row_index in range(worksheet.nrows):
12          for column_index in range(worksheet.ncols):
13               output_worksheet.write(row_index, column_index, \
14                    worksheet.cell_value(row_index, column_index))
15 output_workbook.save(output_file)

第 3 行代码导入 xlrd 模块的 open_workbook 函数,第 4 行代码导入 xlwt 模块的 Workbook 对象。

第 7 行代码实例化一个 xlwt Workbook 对象,以使我们可以将结果写入用于输出的 Excel 文件。第 8 行代码使用 xlwtadd_sheet 函数为输出工作簿添加一个工作表 jan_2013_output。

第 9 行代码使用 xlrdopen_workbook 函数打开用于输入的工作簿,并将结果赋给一个 workbook 对象。第 10 行代码使用这个 workbook 对象的 sheet_by_name 函数引用名称为 january_2013 的工作表。

第 11~12 行代码创建了行与列索引值上的 for 循环语句,使用 range 函数和 worksheet 对象的 nrows 属性和 ncols 属性,在工作表的每行和每列之间迭代。

第 13 行代码使用 xlwtwrite 函数和行与列的索引将每个单元格的值写入输出文件的工作表。

最后,第 15 行代码保存并关闭输出工作簿。

要运行这个脚本,在命令行中输入以下命令,然后按回车键:

python 2excel_parsing_and_write.py sales_2013.xlsx output_files\2output.xls

你可以打开输出文件 2output.xls 查看一下结果。

你可能已经发现,Purchase Date 列(也就是第 E 列)中的日期显示为数值,不是日期。Excel 将日期和时间保存为浮点数,这个浮点数代表从 1900 年 1 月 0 日开始经过的日期数,加上一个 24 小时的小数部分。例如,数值 1 代表 1900 年 1 月 1 日,因为从 1900 年 1 月 0 日过去了 1 天。因此,这一列中的数值代表日期,但是没有格式化为日期的形式。

xlrd 扩展包提供了其他函数来格式化日期值。下一个示例通过演示如何格式化日期数据修正了前一个示例,这样日期值就可以像在输入文件中一样打印到屏幕上或写入输出文件了。

格式化日期数据。这个示例是基于前一个示例的,它展示了如何使用 xlrd 修改日期数据格式,使它们看上去和输入 Excel 文件中一样。例如,如果 Excel 工作表中的一个日期数据为 1/19/2000,那么我们通常希望将 1/19/2000 或其他相关日期格式写入输出文件。但是,就像前一个示例中那样,使用现在的示例代码,你会在输出文件中得到一个数值 36 544.0,因为这就是 1/0/1900 和 1/19/2000 之间的天数。

为了对日期列进行格式化,在文本编辑器中输入下列代码,然后将文件保存为 3excel_parsing_and_write_keep_dates.py:

 1 #!/usr/bin/env python3
 2 import sys
 3 from datetime import date
 4 from xlrd import open_workbook, xldate_as_tuple
 5 from xlwt import Workbook
 6 input_file = sys.argv[1]
 7 output_file = sys.argv[2]
 8 output_workbook = Workbook()
 9 output_worksheet = output_workbook.add_sheet('jan_2013_output')
10 with open_workbook(input_file) as workbook:
11     worksheet = workbook.sheet_by_name('january_2013')
12     for row_index in range(worksheet.nrows):
13          row_list_output = []
14          for col_index in range(worksheet.ncols):
15               if worksheet.cell_type(row_index, col_index) == 3:
16                    date_cell = xldate_as_tuple(worksheet.cell_value\
17                         (row_index, col_index),workbook.datemode)
18                    date_cell = date(*date_cell[0:3]).strftime\
19                         ('%m/%d/%Y')
20                    row_list_output.append(date_cell)
21                    output_worksheet.write(row_index, col_index, date_cell)
22               else:
23                    non_date_cell = worksheet.cell_value\
24                         (row_index,col_index)
25                    row_list_output.append(non_date_cell)
26                    output_worksheet.write(row_index, col_index,\
27                         non_date_cell)
28 output_workbook.save(output_file)

第 3 行代码从 datetime 模块导入 date 函数,以使我们可以将数值转换成日期并对日期进行格式化。

第 4 行代码从 xlrd 模块中导入两个函数。在前面的示例中,是使用第一个函数打开的 Excel 工作簿,所以这里将重点介绍第二个函数。函数 xldate_as_tuple 可以将 Excel 中代表日期、时间或日期时间的数值转换为元组。只要将数值转换成了元组,就可以提取出具体时间元素(例如:年、月、日)并将时间元素格式化成不同的时间格式(例如: 1/1/2010 或 January 1, 2010)。

第 15 行代码创建了一个 if-else 语句来检验单元格类型是否为数字 3。如果你查看了 xlrd 模块的说明文档(https://secure.simplistix.co.uk/svn/xlrd/trunk/xlrd/doc/xlrd.html?p=4966#sheet.Cell-class),就会知道单元格类型为 3 表示这个单元格中包含日期数据。因此,if-else 语句检验每个单元格是否含有日期数据。如果含有日期数据,那么 if 代码块就对单元格进行处理;如果不含有日期数据,那么就使用 else 代码块对单元格进行处理。因为日期数据在最后一列,所以 if 代码块处理最后一列。

第 16 行代码使用 worksheet 对象的 cell_value 函数和行列索引来引用单元格中的值。此外,你还可以使用 cell().value 函数,这两个函数可以给出同样的结果。这个单元格中的值作为 xldate_as_tuple 函数中的第一个参数,会被转换成元组中的一个代表日期的浮点数。

参数 workbook.datemode 是必需的,它可以使函数确定日期是基于 1900 年还是基于 1904 年,并据此将数值转换成正确的元组(在 Mac 上的某些 Excel 版本从 1904 年 1 月 1 日开始计算日期。要获取这方面的更多信息,请阅读 Microsoft 参考指南(https://support.microsoft.com/en-us/kb/214330)。xldate_as_tuple 函数的结果被赋给一个元组变量 date_cell。这行代码太长了,所以被分为两行,第一行末尾字符是一个反斜杠(你应该记得在第 1 章中我们曾说过反斜杠是必需的,这样 Python 才能将这两行解释为一行)。尽管如此,在你自己的代码中,可以将所有代码都写在一行中而不使用反斜杠。

第 18 行代码使用元组索引来引用元组 date_cell 中的前 3 个元素(也就是年、月、日)并将它们作为参数传给 date 函数,这个函数可以将这些值转换成一个 date 对象,date 对象在第 1 章中曾介绍过。然后,strftime 函数将 date 对象转换为一个具有特定格式的字符串。格式 '%m/%d/%Y' 表示像 2014 年 3 月 15 日这样的日期应该显示为 03/15/2014。格式化后的日期字符串被重新赋给变量 date_cell。第 20 行代码使用列表的 append 函数将 date_cell 中的值追加给输出列表 row_list_output

在运行了上面的脚本之后,为了对第 16 和 18 行代码中的操作有个大致概念,可以在两个 date_cell=…行之间添加一个 print 语句(也就是 print(date_cell))。重新保存并运行脚本,看一下 xldate_as_tuple 函数打印在屏幕上的结果。然后,删除这个 print 语句,将它移到第二个 date_cell=…语句下面。重新保存并运行脚本,看一下 date.strftime 函数打印在屏幕上的结果。这些 print 语句可以帮助你看到这两行中的函数是如何将 Excel 中代表日期的数值转换成一个元组,然后又转换成格式化的日期字符串的。

else 代码块处理所有的非日期单元格。第 23 行代码使用 worksheet 对象的 cell_value 函数和行列索引引用单元格中的值,并将其赋给变量 non_date_cell。第 25 行代码使用列表的 append 函数将 non_date_cell 中的值追加给 row_list_output。这两行代码提取出每行前四列中的值,并将它们追加到 row_list_output 中。

在行中的每一列都处理完成,并加入到 row_list_output 中之后,第 26 行代码将 row_list_output 中的值写入输出文件。

要运行这个脚本,在命令行中输入以下命令,然后按回车键:

python 3excel_parsing_and_write_keep_dates.py sales_2013.xlsx\
output_files\3output.xls

你可以打开输出文件 3output.xls 查看一下结果。

pandas。pandas 也有一组读取 Excel 文件的函数。下面是使用 pandas 分析 Excel 文件的示例代码。请将这段代码保存为 pandas_read_and_write_excel.py(此段代码读取 Excel 输入文件,将内容打印在屏幕上,然后将内容写入 Excel 输出文件):

#!/usr/bin/env python3
import pandas as pd
import sys
input_file = sys.argv[1]
output_file = sys.argv[2]
data_frame = pd.read_excel(input_file, sheetname='january_2013')
writer = pd.ExcelWriter(output_file)
data_frame.to_excel(writer, sheet_name='jan_13_output', index=False)
writer.save()

要运行这个脚本,在命令行中输入以下命令,然后按回车键:

python pandas_parsing_and_write_keep_dates.py sales_2013.xlsx\
output_files\pandas_output.xls

你可以打开输出文件 pandas_output.xls 查看一下结果。

现在你已经明白了如何处理一个 Excel 工作簿中的工作表,以及如何保留日期格式,那么接下来学习一下如何在工作表中筛选出特定的行。正如我们在第 2 章中做的那样,接下来将讨论如何按照以下方式筛选行:(a)行中的值满足特定条件;(b)行中的值属于某个集合;(c)行中的值匹配于特定的正则表达式。

3.2.2 筛选特定行

有些时候,你并不需要 Excel 文件中的所有行。例如,你可能只需要包含一个特定的词或数值的那些行,或者,你可能只需要那些与一个具体日期相关联的行。在这些情况下,可以使用 Python 筛选掉不需要的行,只保留需要的行。

你可能已经熟悉了如何在 Excel 文件中手动筛选行,但是本章重点在于提高你的能力,使你可以处理因体积太大而难以打开的 Excel 文件,以及手动处理过于浪费时间的多个 Excel 工作表。

  1. 行中的值满足某个条件

    基础 Python。首先,来看一下如何使用基础 Python 筛选出特定的行。在这个示例中,你想筛选出 Sale Amount 大于 $1400.00 的行。

    为了筛选出满足这个条件的行,在文本编辑器中输入下列代码,然后将文件保存为 4excel_value_meets_condition.py:

     1 #!/usr/bin/env python3
     2 import sys
     3 from datetime import date
     4 from xlrd import open_workbook, xldate_as_tuple
     5 from xlwt import Workbook
     6 input_file = sys.argv[1]
     7 output_file = sys.argv[2]
     8 output_workbook = Workbook()
     9 output_worksheet = output_workbook.add_sheet('jan_2013_output')
    10 sale_amount_column_index = 3
    11 with open_workbook(input_file) as workbook:
    12     worksheet = workbook.sheet_by_name('january_2013')
    13     data = []
    14     header = worksheet.row_values(0)
    15     data.append(header)
    16     for row_index in range(1,worksheet.nrows):
    17          row_list = []
    18          sale_amount = worksheet.cell_value\
    19          (row_index, sale_amount_column_index)
    20          if sale_amount > 1400.0:
    21               for column_index in range(worksheet.ncols):
    22                    cell_value = worksheet.cell_value\
    23                    (row_index,column_index)
    24                    cell_type = worksheet.cell_type\
    25                    (row_index, column_index)
    26                    if cell_type == 3:
    27                         date_cell = xldate_as_tuple\
    28                         (cell_value,workbook.datemode)
    29                         date_cell = date(*date_cell[0:3])\
    30                         .strftime('%m/%d/%Y')
    31                         row_list.append(date_cell)
    32                    else:
    33                         row_list.append(cell_value)
    34          if row_list:
    35               data.append(row_list)
    36    for list_index, output_list in enumerate(data):
    37         for element_index, element in enumerate(output_list):
    38              output_worksheet.write(list_index, element_index, element)
    39 output_workbook.save(output_file)
    
    

    第 13 行代码创建了一个空列表 data。我们将用输入文件中要写入输出文件中的那些行来填充这个列表。

    第 14 行代码提取出标题行中的值。因为我们想保留标题行,而且检验这一行是否满足筛选条件没有意义,所以第 15 行代码将标题行直接追加到 data 中。

    第 18 行代码创建了一个变量 sale_amount,用来保存行中的销售额。cell_value 函数使用第 10 行代码中定义的 sale_amount_column_index 中的值来定位 Sale Amount 列。因为我们想保留销售额大于 $1400.00 的那些行,所以要使用这个变量作为检验条件。

    第 21 行代码创建了一个 for 循环,来处理 Sale Amount 大于 1400.0 的那些行。对于这些行,我们先提取出每个单元格的值,赋给变量 cell_value,再提取出每个单元格的类型,赋给变量 cell_type。然后,检验行中的每个值是否是日期类型。如果是日期类型,那么就将这个值格式化成日期数据。为了生成一个每个值都正确格式化的行,我们在第 17 行创建了一个空列表 row_list,然后用第 31 和 33 行代码将行中的日期类型数据和非日期类型数据都追加进 row_list

    我们为输入文件中的每一行都创建空列表 row_list,但是只使用值填充某些空列表(就是 Sale Amount 这列的值大于 1400.0 的那些行的空列表)。所以,对于输入文件中的每一行,第 34 行代码检验 row_list 是否为空,只将非空的 row_list 添加到 data 中。

    最后,在第 36 和 37 行代码中,我们在 data 中的各个列表之间和列表中的各个值之间进行迭代,将这些值写入输出文件。将要保留的行追加到一个新列表 data 中的原因是,这样可以得到新的连续的行索引值。于是,当我们将这些行写入输出文件时,它们看上去就像是一个连续的整体,行与行之间不会出现缺口。否则,如果在主体 for 循环中处理各行的时候就将它们写入输出文件的话,那么 xlwtwrite 函数就会使用输入文件中原来的行索引值将行写入输出文件,造成行与行之间存在缺口。在后面选择特定列的小节中,我们还会使用这种方法,以此来保证将各列作为一个连续整体写入输出文件,列与列之间不出现缺口。

    要运行这个脚本,在命令行中输入以下命令,然后按回车键:

    python 4excel_value_meets_condition.py sales_2013.xlsx output_files\4output.xls
    
    

    你可以打开输出文件 4output.xls 查看一下结果。

    pandas。你可以使用 pandas 筛选出符合某个条件的行,指定你想判断的列的名称,并在数据框名称后面的方括号中设定具体的判断条件。例如,在下面的脚本中,我们设定的判断条件就可以筛选出 Sale Amount 列大于 1400.00 的所有行。

    如果你需要设定多个条件,那么可以将这些条件放在圆括号中,根据需要的逻辑顺序用“&”或“|”连接起来。在注释掉的两行代码中,展示了如何基于两个条件来筛选行。第一行代码使用“&”,表示两个条件必须都为真。第二行代码使用“|”,表示只要一个条件为真就可以。(在下面的示例代码中,并没有加了注释的语句,应该是作者删掉了。——译者注)

    要使用 pandas 筛选出满足特定条件的行,在文本编辑器中输入下列代码,然后将文件保存为 pandas_value_meets_condition.py:

    #!/usr/bin/env python3
    import pandas as pd
    import sys
    input_file = sys.argv[1]
    output_file = sys.argv[2]
    data_frame = pd.read_excel(input_file, 'january_2013', index_col=None)
        data_frame_value_meets_condition = \
    data_frame[data_frame['Sale Amount'].astype(float) > 1400.0]
    writer = pd.ExcelWriter(output_file)
    data_frame_value_meets_condition.to_excel(writer, sheet_name='jan_13_output',\
    index=False)
    writer.save()
    
    

    要运行这个脚本,在命令行中输入以下命令,然后按回车键:

    python pandas_value_meets_condition.py sales_2013.xlsx\
    output_files\pandas_output.xls
    
    

    你可以打开输出文件 pandas_output.xls 查看一下结果。

  2. 行中的值属于某个集合

    基础 Python。要使用基础 Python 筛选出购买日期属于一个特定集合(例如:日期 01/24/2013 和 01/31/2013 的集合)的行,在文本编辑器中输入下列代码,并将文件保存为 5excel_value_in_set.py:

     1 #!/usr/bin/env python3
     2 import sys
     3 from datetime import date
     4 from xlrd import open_workbook, xldate_as_tuple
     5 from xlwt import Workbook
     6 input_file = sys.argv[1]
     7 output_file = sys.argv[2]
     8 output_workbook = Workbook()
     9 output_worksheet = output_workbook.add_sheet('jan_2013_output')
    10 important_dates = ['01/24/2013', '01/31/2013']
    11 purchase_date_column_index = 4
    12 with open_workbook(input_file) as workbook:
    13     worksheet = workbook.sheet_by_name('january_2013')
    14     data = []
    15     header = worksheet.row_values(0)
    16     data.append(header)
    17     for row_index in range(1, worksheet.nrows):
    18          purchase_datetime = xldate_as_tuple(worksheet.cell_value\
    19          (row_index, purchase_date_column_index)\
    20          ,workbook.datemode)
    21          purchase_date = date(*purchase_datetime[0:3]).strftime('%m/%d/%Y')
    22          row_list = []
    23          if purchase_date in important_dates:
    24          for column_index in range(worksheet.ncols):
    25               cell_value = worksheet.cell_value\
    26               (row_index,column_index)
    27               cell_type = worksheet.cell_type(row_index, column_index)
    28               if cell_type == 3:
    29                    date_cell = xldate_as_tuple\
    30                    (cell_value,workbook.datemode)
    31                    date_cell = date(*date_cell[0:3])\
    32                   .strftime('%m/%d/%Y')
    33                   row_list.append(date_cell)
    34               else:
    35                   row_list.append(cell_value)
    36      if row_list:
    37           data.append(row_list)
    38    for list_index, output_list in enumerate(data):
    39         for element_index, element in enumerate(output_list):
    40              output_worksheet.write(list_index, element_index, element)
    41 output_workbook.save(output_file)
    
    

    这个脚本与基于条件筛选行的脚本非常相似,区别在于第 10、21 和 23 行。第 10 行代码创建了一个列表 important_dates,包含了要使用的日期。第 21 行代码创建了一个变量 purchase_date,它等于 Purchase Date 列中格式化后的值,并用它来匹配 important_dates 中格式化的日期。第 23 行代码检验行中的日期是否是 important_dates 中的一个日期。如果是,那么就处理这一行,并将其写入输出文件。

    要运行这个脚本,在命令行中输入以下命令,然后按回车键:

    python 5excel_value_in_set.py sales_2013.xlsx output_files\5output.xls
    
    

    你可以打开输出文件 5output.xls 查看一下结果。

    pandas。在这个示例中,我们想筛选出购买日期为 01/24/2013 或 01/31/2013 的行。pandas 提供了 isin 函数,你可以使用它来检验一个特定值是否在一个列表中。

    要使用 pandas 基于集合成员筛选行,在文本编辑器中输入下列代码,然后将文件保存为 pandas_value_in_set.py:

    #!/usr/bin/env python3
    import pandas as pd
    import sys
    input_file = sys.argv[1]
    output_file = sys.argv[2]
    data_frame = pd.read_excel(input_file, 'january_2013', index_col=None)
    important_dates = ['01/24/2013','01/31/2013']
    data_frame_value_in_set = data_frame[data_frame['PurchaseDate']\
    .isin(important_dates)]
    writer = pd.ExcelWriter(output_file)
    data_frame_value_in_set.to_excel(writer, sheet_name='jan_13_output', index=False)
    writer.save()
    
    

    在命令行中运行这个脚本:

    python pandas_value_in_set.py sales_2013.xlsx output_files\pandas_output.xls
    
    

    你可以打开输出文件 pandas_output.xls 查看一下结果。

  3. 行中的值匹配于特定模式

    基础 Python。要使用基础 Python 筛选出客户姓名包含一个特定模式(例如:以大写字母 J 开头)的行,在文本编辑器中输入下列代码,然后将文件保存为 6excel_value_matches_pattern.py:

     1 #!/usr/bin/env python3
     2 import re
     3 import sys
     4 from datetime import date
     5 from xlrd import open_workbook, xldate_as_tuple
     6 from xlwt import Workbook
     7 input_file = sys.argv[1]
     8 output_file = sys.argv[2]
     9 output_workbook = Workbook()
    10 output_worksheet = output_workbook.add_sheet('jan_2013_output')
    11 pattern = re.compile(r'(?P<my_pattern>^J.*)')
    12 customer_name_column_index = 1
    13 with open_workbook(input_file) as workbook:
    14     worksheet = workbook.sheet_by_name('january_2013')
    15     data = []
    16     header = worksheet.row_values(0)
    17     data.append(header)
    18     for row_index in range(1, worksheet.nrows):
    19          row_list = []
    20          if pattern.search(worksheet.cell_value\
    21          (row_index, customer_name_column_index)):
    22               for column_index in range(worksheet.ncols):
    23                    cell_value = worksheet.cell_value\
    24                    (row_index,column_index)
    25                    cell_type = worksheet.cell_type(row_index, column_index)
    26                    if cell_type == 3:
    27                         date_cell = xldate_as_tuple\
    28                         (cell_value,workbook.datemode)
    29                         date_cell = date(*date_cell[0:3])\
    30                         .strftime('%m/%d/%Y')
    31                         row_list.append(date_cell)
    32                     else:
    33                         row_list.append(cell_value)
    34           if row_list:
    35                data.append(row_list)
    36    for list_index, output_list in enumerate(data):
    37         for element_index, element in enumerate(output_list):
    38               output_worksheet.write(list_index, element_index, element)
    39 output_workbook.save(output_file)
    
    

    第 2 行代码导入 re 模块,以使我们可以使用模块中的函数和方法。

    第 11 行代码使用 re 模块的 compile 函数创建了一个正则表达式 pattern。如果你能看懂,那么这个函数中的内容就很好解释。r 表示单引号之间的模式是一个原始字符串。元字符 ?P<my_pattern> 捕获了名为 <my_pattern> 的组中匹配了的子字符串,以便在需要时将它们打印到屏幕上或写入文件。我们要搜索的实际模式是 '^J.*'。插入符号(^)是一个特殊符号,表示“在字符串开头搜索模式”。所以,字符串需要以大写字母 J 开头。句点 . 可以匹配任何字符,除了换行符。所以除换行符之外的任何字符都可以跟在 J 后面。最后,* 表示重复前面的字符 0 次或更多次。.* 组合在一起用来表示除换行符之外的任意字符可以在 J 后面出现任意次。

    第 20 行代码使用 re 模块中的 search 函数在 Customer Name 列中搜索模式,并检测是否能找到一个匹配。如果找到了一个匹配,就将这一行中的每个值添加到 row_list 中。第 31 行代码将日期值添加到 row_list 中,第 33 行代码将非日期值添加到 row_list 中。如果 row_list 不是空的,第 35 行代码将 row_list 中的每个列表值添加到 data

    最后,第 36 和 37 行代码中的两个 for 循环在 data 中的各个列表中迭代,将各行写入输出文件。

    要运行这个脚本,在命令行中输入以下命令,然后按回车键:

    python 6excel_value_matches_pattern.py sales_2013.xlsx output_files\6output.xls
    
    

    你可以打开输出文件 6output.xls 查看一下结果。

    pandas。在这个示例中,你想筛选出客户姓名以大写字母 J 开头的那些行。pandas 提供了若干字符串和正则表达式函数,包括 startswithendswithmatchsearch 等,你可以使用这些函数在文本中识别子字符串和模式。

    要使用 pandas 筛选出客户姓名以大写字母 J 开头的那些行,在文本编辑器中输入下列代码,然后将文件保存为 pandas_value_matches_pattern.py:

    #!/usr/bin/env python3
    import pandas as pd
    import sys
    input_file = sys.argv[1]
    output_file = sys.argv[2]
    data_frame = pd.read_excel(input_file, 'january_2013', index_col=None)
    data_frame_value_matches_pattern = data_frame[data_frame['Customer Name']\
    .str.startswith("J")]
    writer = pd.ExcelWriter(output_file)
    data_frame_value_matches_pattern.to_excel(writer, sheet_name='jan_13_output',\
    index=False)
    writer.save()
    
    

    要运行这个脚本,在命令行中输入以下命令,然后按回车键:

    python pandas_value_matches_pattern.py sales_2013.xlsx\
    output_files\pandas_output.xls
    
    

    你可以打开输出文件 pandas_output.xls 查看一下结果。

3.2.3 选取特定列

有些时候,你并不需要工作表中所有的列。在这种情况下,可以使用 Python 选取出你需要保留的列。

有两种通用方法可以在 Excel 文件中选取特定的列。下面的小节演示了这两种选取列的方法:

  • 使用列索引值

  • 使用列标题

  • 列索引值

    基础 Python。从工作表中选取特定列的一种方法是使用要保留的列的索引值。当你想保留的列的索引值非常容易识别,或者在处理多个输入文件过程中,各个输入文件中列的位置是一致(也就是不会发生改变)的时候,这种方法非常有效。

    例如,假设我们想保留 Customer Name 和 Purchase Date 这两列。要使用基础 Python 选取这两列,在文本编辑器中输入下列代码,然后将文件保存为 7excel_column_by_index.py:

     1 #!/usr/bin/env python3
     2 import sys
     3 from datetime import date
     4 from xlrd import open_workbook, xldate_as_tuple
     5 from xlwt import Workbook
     6 input_file = sys.argv[1]
     7 output_file = sys.argv[2]
     8 output_workbook = Workbook()
     9 output_worksheet = output_workbook.add_sheet('jan_2013_output')
    10 my_columns = [1, 4]
    11 with open_workbook(input_file) as workbook:
    12     worksheet = workbook.sheet_by_name('january_2013')
    13     data = []
    14     for row_index in range(worksheet.nrows):
    15          row_list = []
    16          for column_index in my_columns:
    17               cell_value = worksheet.cell_value(row_index,column_index)
    18               cell_type = worksheet.cell_type(row_index, column_index)
    19               if cell_type == 3:
    20                    date_cell = xldate_as_tuple\
    21                    (cell_value,workbook.datemode)
    22                    date_cell = date(*date_cell[0:3]).strftime('%m/%d/%Y')
    23                    row_list.append(date_cell)
    24                else:
    25                    row_list.append(cell_value)
    26           data.append(row_list)
    27    for list_index, output_list in enumerate(data):
    28         for element_index, element in enumerate(output_list):
    29              output_worksheet.write(list_index, element_index, element)
    30 output_workbook.save(output_file)
    
    

    第 10 行代码创建了一个列表变量 my_columns,包含整数 1 和 4。这两个整数分别代表 Customer Name 和 Purchase Date 列的索引值。

    第 16 行代码创建了一个 for 循环,在 my_columns 中的两个列索引值之间迭代。在每次循环中,提取出列中单元格的值和类型,判断单元格中的值是否是日期类型,并对单元格进行相应处理,然后将值追加到 row_list 中。第 26 行代码将 row_list 中的值添加到 data 中。

    最后,第 27 和 28 行代码中的两个 for 循环在 data 中的列表之间迭代,将其中的值写入输出文件。

    要运行这个脚本,在命令行中输入以下命令,然后按回车键:

    python 7column_column_by_index.py sales_2013.xlsx output_files\7output.xls
    
    

    你可以打开输出文件 7output.xls 查看一下结果。

    pandas。有很多方法可以使用 pandas 选取特定列。一种方法是设置数据框,在方括号中列出要保留的列的索引值或名称(字符串)。

    另一种方法,也就是下面所展示的,是设置数据框和 iloc 函数。iloc 函数非常有用,因为它可以使你同时选择特定的行与特定的列。所以,如果使用 iloc 函数来选择列,那么就需要在列索引值前面加上一个冒号和一个逗号,表示你想为这些特定的列保留所有的行。否则,iloc 函数也会使用这些索引值去筛选行。

    要使用 pandas 基于索引值去选取列,在文本编辑器中输入下列代码,然后将文件保存为 pandas_column_by_index.py:

    #!/usr/bin/env python3
    import pandas as pd
    import sys
    input_file = sys.argv[1]
    output_file = sys.argv[2]
    data_frame = pd.read_excel(input_file, 'january_2013', index_col=None)
    data_frame_column_by_index = data_frame.iloc[:, [1, 4]]
    writer = pd.ExcelWriter(output_file)
    data_frame_column_by_index.to_excel(writer, sheet_name='jan_13_output',\
    index=False)
    writer.save()
    
    

    要运行这个脚本,在命令行中输入以下命令,然后按回车键:

    python pandas_column_by_index.py sales_2013.xlsx output_files\pandas_output.xls
    
    

    你可以打开输出文件 pandas_output.xls 查看一下结果。

  • 列标题

    第二种在工作表中选取一组列的方法是使用列标题。当你想保留的列的标题非常容易识别,或者在处理多个输入文件过程中,各个输入文件中列的位置会发生改变,但标题不变的时候,这种方法非常有效。

    基础 Python。要使用基础 Python 选取 Customer ID 和 Purchase Date 列,在文本编辑器中输入下列代码,然后将文件保存为 8excel_column_by_name.py:

     1 #!/usr/bin/env python3
     2 import sys
     3 from datetime import date
     4 from xlrd import open_workbook, xldate_as_tuple
     5 from xlwt import Workbook
     6 input_file = sys.argv[1]
     7 output_file = sys.argv[2]
     8 output_workbook = Workbook()
     9 output_worksheet = output_workbook.add_sheet('jan_2013_output')
    10 my_columns = ['Customer ID', 'Purchase Date']
    11 with open_workbook(input_file) as workbook:
    12     worksheet = workbook.sheet_by_name('january_2013')
    13     data = [my_columns]
    14     header_list = worksheet.row_values(0)
    15     header_index_list = []
    16     for header_index in range(len(header_list)):
    17          if header_list[header_index] in my_columns:
    18               header_index_list.append(header_index)
    19     for row_index in range(1,worksheet.nrows):
    20         row_list = []
    21         for column_index in header_index_list:
    22              cell_value = worksheet.cell_value(row_index,column_index)
    23              cell_type = worksheet.cell_type(row_index, column_index)
    24              if cell_type == 3:
    25                   date_cell = xldate_as_tuple\
    26                   (cell_value,workbook.datemode)
    27                   date_cell = date(*date_cell[0:3]).strftime('%m/%d/%Y')
    28                   row_list.append(date_cell)
    29              else:
    30                   row_list.append(cell_value)
    31         data.append(row_list)
    32    for list_index, output_list in enumerate(data):
    33         for element_index, element in enumerate(output_list):
    34               output_worksheet.write(list_index, element_index, element)
    35 output_workbook.save(output_file)
    
    

    第 10 行代码创建了一个列表变量 my_columns,包含要保留的两列的名称。因为这是要写入输出文件的列标题,所以在第 13 行代码中,直接将其加入输出列表 data

    第 16 行代码创建了一个 for 循环,在 header_list 中的列标题索引值之间迭代。第 17 行代码使用列表索引来检验每个列标题是否在列表 my_columns 中。如果是,就使用第 18 行代码将这个列标题的索引值追加到 header_index_list 中。后面将在第 21 行代码中使用这些索引值,仅处理那些要写入输出文件的列。

    第 21 行代码创建了一个 for 循环,在 header_index_list 中的列索引值之间迭代。通过使用 header_index_list,只处理在 my_columns 中列出的那些列。

    要运行这个脚本,在命令行中输入以下命令,然后按回车键:

    python 8excel_column_by_name.py sales_2013.xlsx output_files\8output.xls
    
    

    你可以打开输出文件 8output.xls 查看一下结果。

    pandas。要使用 pandas 基于列标题选取特定列,一种方式是在数据框名称后面的方括号中将列名以字符串方式列出。另外一种方式是使用 loc 函数。如果使用 loc 函数,那么需要在列标题列表前面加上一个冒号和一个逗号,表示你想为这些特定的列保留所有行。

    要使用 pandas 基于列标题选取列,在文本编辑器中输入下列代码,然后将文件保存为 pandas_column_by_name.py:

    #!/usr/bin/env python3
    import pandas as pd
    import sys
    input_file = sys.argv[1]
    output_file = sys.argv[2]
    data_frame = pd.read_excel(input_file, 'january_2013', index_col=None)
    data_frame_column_by_name = data_frame.loc[:, ['Customer ID', 'Purchase Date']]
    writer = pd.ExcelWriter(output_file)
    data_frame_column_by_name.to_excel(writer, sheet_name='jan_13_output',\
    index=False)
    writer.save()
    
    

    要运行这个脚本,在命令行中输入以下命令,然后按回车键:

    python pandas_column_by_name.py sales_2013.xlsx output_files\pandas_output.xls
    
    

    你可以打开输出文件 pandas_output.xls 查看一下结果。

3.3 读取工作簿中的所有工作表

本章到目前为止,都在演示如何处理单个工作表。有些时候,你只需要处理一个工作表就可以了。在这些情况下,这里的示例可以告诉你如何使用 Python 程序去自动处理工作表。

但是,在很多情况下你需要处理多个工作表,多到使用手工处理效率非常低或者根本不可行。在这种情况下,Python 会给你惊喜,因为它可以让你自动化和规模化地进行数据处理,远远超过手工处理能够达到的限度。本小节提供了两个示例,演示了如何在一个工作簿的所有工作表中筛选特定的行与列。

我仅提供一个用于筛选行的示例和一个用于筛选列的示例,因为我想把本章篇幅保留在合理范围之内(后面还会有介绍如何处理一个工作簿中特定的一组工作表和如何处理多个工作簿的章节)。此外,在前面的示例中,你已经掌握了选择特定的行与列的其他方法,就应该知道如何将那些筛选操作应用在这里的示例中。

3.3.1 在所有工作表中筛选特定行

  1. 基础Python

    要使用基础 Python 在所有工作表中筛选出销售额大于 $2000.00 的所有行,在文本编辑器中输入下列代码,然后将文件保存为 9excel_value_meets_condition_all_worksheets.py:

     1 #!/usr/bin/env python3
     2 import sys
     3 from datetime import date
     4 from xlrd import open_workbook, xldate_as_tuple
     5 from xlwt import Workbook
     6 input_file = sys.argv[1]
     7 output_file = sys.argv[2]
     8 output_workbook = Workbook()
     9 output_worksheet = output_workbook.add_sheet('filtered_rows_all_worksheets')
    10 sales_column_index = 3
    11 threshold = 2000.0
    12 first_worksheet = True
    13 with open_workbook(input_file) as workbook:
    14     data = []
    15     for worksheet in workbook.sheets():
    16          if first_worksheet:
    17               header_row = worksheet.row_values(0)
    18               data.append(header_row)
    19               first_worksheet = False
    20          for row_index in range(1,worksheet.nrows):
    21               row_list = []
    22               sale_amount = worksheet.cell_value\
    23               (row_index, sales_column_index)
    24               if sale_amount > threshold:
    25                    for column_index in range(worksheet.ncols):
    26                         cell_value = worksheet.cell_value\
    27                         (row_index,column_index)
    28                         cell_type = worksheet.cell_type\
    29                         (row_index, column_index)
    30                         if cell_type == 3:
    31                              date_cell = xldate_as_tuple\
    32                              (cell_value,workbook.datemode)
    33                              date_cell = date(*date_cell[0:3])\
    34                              .strftime('%m/%d/%Y')
    35                              row_list.append(date_cell)
    36                         else:
    37                              row_list.append(cell_value)
    38               if row_list:
    39                    data.append(row_list)
    40    for list_index, output_list in enumerate(data):
    41         for element_index, element in enumerate(output_list):
    42               output_worksheet.write(list_index, element_index, element)
    43 output_workbook.save(output_file)
    
    

    第 10 行代码创建了一个变量 sales_column_index,保存 Sale Amount 列的索引值。同样,第 11 行代码创建了一个变量 threshold 来保存你所关心的销售额。我们要将 Sale Amount 列中的每个值与这个阈值进行比较,来确定哪一行要被写入到输出文件中。

    第 15 行代码创建了一个 for 循环,用来在工作簿中的所有工作表之间迭代。它使用 workbook 对象的 sheets 属性来列出工作簿中所有的工作表。

    第 16 行代码判断当前工作表是不是第一个工作表,如果是第一个工作表,我们就提取出标题行,将其追加到 data 中,然后将 first_worksheet 设为 False。代码继续处理余下的销售额大于阈值的数据行。

    对于所有后续的工作表,first_worksheet 都是 False,所以脚本直接来到第 20 行代码处理每个工作表中的数据行。因为 range 函数不是从 0 开始,而是从 1 开始,所以你应该知道代码处理的是数据行,不是标题行。

    要运行这个脚本,在命令行中输入以下命令,然后按回车键:

    python 9excel_value_meets_condition_all_worksheets.py sales_2013.xlsx\
    output_files\9output.xls
    
    

    你可以打开输出文件 9output.xls 查看一下结果。

  2. pandas

    在 pandas 中,通过在 read_excel 函数中设置 sheetname=None,可以一次性读取工作簿中的所有工作表。pandas 将这些工作表读入一个数据框字典,字典中的键就是工作表的名称,值就是包含工作表中数据的数据框。所以,通过在字典的键和值之间迭代,你可以使用工作簿中所有的数据。当你在每个数据框中筛选特定行时,结果是一个新的筛选过的数据框,所以你可以创建一个列表保存这些筛选过的数据框,然后将它们连接成一个最终数据框。

    在下面这个示例中,我们想在所有工作表中筛选出销售额大于 $2000.00 的所有行。要使用 pandas 筛选出这些行,在文本编辑器中输入下列代码,然后将文件保存为 pandas_value_meets_condition_all_worksheets.py:

    #!/usr/bin/env python3
    import pandas as pd
    import sys
    input_file = sys.argv[1]
    output_file = sys.argv[2]
    data_frame = pd.read_excel(input_file, sheetname=None, index_col=None)
    row_output = []
    for worksheet_name, data in data_frame.items():
        row_output.append(data[data['Sale Amount'].astype(float) > 2000.0])
    filtered_rows = pd.concat(row_output, axis=0, ignore_index=True)
    writer = pd.ExcelWriter(output_file)
    filtered_rows.to_excel(writer, sheet_name='sale_amount_gt2000', index=False)
    writer.save()
    
    

    要运行这个脚本,在命令行中输入以下命令,然后按回车键:

    python pandas_value_meets_condition_all_worksheets.py sales_2013.xlsx\
    output_files\pandas_output.xls
    
    

    你可以打开输出文件 pandas_output.xls 查看一下结果。

3.3.2 在所有工作表中选取特定列

有些时候,Excel 工作簿中包含了多个工作表,每个工作表中包含的列并不都是你需要的。在这种情况下,你可以使用 Python 读取所有工作表,筛选掉不需要的列,只保留需要的列。

从前面的内容可知,至少有两种方法可以从工作表中选取一组列:使用列索引值和列标题。下面的示例演示了如何使用列标题从一个工作簿的所有工作表中选取特定的列。

  1. 基础Python

    要使用基础 Python 在所有工作表中选取 Customer Name 和 Sale Amount 列,在文本编辑器中输入下列代码,然后将文件保存为 10excel_column_by_name_all_worksheet.py:

     1 #!/usr/bin/env python3
     2 import sys
     3 from datetime import date
     4 from xlrd import open_workbook, xldate_as_tuple
     5 from xlwt import Workbook
     6 input_file = sys.argv[1]
     7 output_file = sys.argv[2]
     8 output_workbook = Workbook()
     9 output_worksheet = output_workbook.add_sheet('selected_columns_all_worksheets')
    10 my_columns = ['Customer Name', 'Sale Amount']
    11 first_worksheet = True
    12 with open_workbook(input_file) as workbook:
    13    data = [my_columns]
    14    index_of_cols_to_keep = []
    15    for worksheet in workbook.sheets():
    16         if first_worksheet:
    17              header = worksheet.row_values(0)
    18              for column_index in range(len(header)):
    19                   if header[column_index] in my_columns:
    20                        index_of_cols_to_keep.append(column_index)
    21              first_worksheet = False
    22        for row_index in range(1, worksheet.nrows):
    23             row_list = []
    24             for column_index in index_of_cols_to_keep:
    25                  cell_value = worksheet.cell_value\
    26                  (row_index, column_index)
    27                  cell_type = worksheet.cell_type(row_index, column_index)
    28                  if cell_type == 3:
    29                       date_cell = xldate_as_tuple\
    30                       (cell_value,workbook.datemode)
    31                       date_cell = date(*date_cell[0:3])\
    32                       .strftime('%m/%d/%Y')
    33                       row_list.append(date_cell)
    34                  else:
    35                       row_list.append(cell_value)
    36              data.append(row_list)
    37    for list_index, output_list in enumerate(data):
    38         for element_index, element in enumerate(output_list):
    39               output_worksheet.write(list_index, element_index, element)
    40 output_workbook.save(output_file)
    
    

    第 10 行代码创建了一个列表变量 my_columns,包含了我们要保留的两列的名称。

    第 13 行代码将 my_columns 放入 data,作为 data 中的第一个列表,因为它是要写入输出文件的列的列标题。第 14 行代码创建了一个空列表 index_of_cols_to_keep,用来保存 Customer Name 和 Sale Amount 列的索引值。

    第 16 行代码检验当前是否在处理第一个工作表。如果是第一个工作表,我们就识别出 Customer Name 和 Sale Amount 列的索引值,并将其追加到列表 index_of_cols_to_keep 中。然后,将 first_worksheet 的值设为 False。代码继续处理余下的数据行,第 24 行代码仅用于处理 Customer Name 和 Sale Amount 列中的值。

    对于所有后续的工作表,first_worksheet 都是 False,所以脚本直接来到第 22 行代码处理每个工作表中的数据行。对于这些工作表,只处理索引值在 index_of_cols_to_keep 中的那些列。如果这些列中有日期型数据,就将其格式化。在组合好一行要写入输出文件的数据之后,使用第 36 行代码将这个数据列表追加到 data 中。

    要运行这个脚本,在命令行中输入以下命令,然后按回车键:

    python 10excel_column_by_name_all_worksheets.py sales_2013.xlsx\
    output_files\10output.xls
    
    

    你可以打开输出文件 10output.xls 查看一下结果。

  2. pandas

    我们再一次使用 pandas 中的 read_excel 函数将所有工作表读入一个字典。然后,使用 loc 函数在每个工作表中选取特定的列,创建一个筛选过的数据框列表,并将这些数据框连接在一起,形成一个最终数据框。

    在这个示例中,我们想在所有工作表中选取 Customer Name 和 Sale Amount 列。要使用 pandas 选取这些列,在文本编辑器中输入下列代码,然后将文件保存为 pandas_column_by_name_all_worksheets.py:

    #!/usr/bin/env python3
    import pandas as pd
    import sys
    input_file = sys.argv[1]
    output_file = sys.argv[2]
    data_frame = pd.read_excel(input_file, sheetname=None, index_col=None)
    column_output = []
    for worksheet_name, data in data_frame.items():
        column_output.append(data.loc[:, ['Customer Name', 'Sale Amount']])
    selected_columns = pd.concat(column_output, axis=0, ignore_index=True)
    writer = pd.ExcelWriter(output_file)
    selected_columns.to_excel(writer, sheet_name='selected_columns_all_worksheets',\
    index=False)
    writer.save()
    
    

    要运行这个脚本,在命令行中输入以下命令,然后按回车键:

    python pandas_column_by_name_all_worksheets.py sales_2013.xlsx\
    output_files\pandas_output.xls
    
    

    你可以打开输出文件 pandas_output.xls 查看一下结果。

3.4 在Excel工作簿中读取一组工作表

本章最开始的几小节演示了如何在一个工作表中筛选特定的行与特定的列。前一个小节演示了如何在一个工作簿的所有工作表中筛选特定的行与列。

但是,有些情况下,你只需要处理工作簿中的一组工作表。例如,你的工作簿可能包含很多工作表,但是你只需要处理其中的 20 个。在这种情况下,可以使用工组簿的 sheet_by_indexsheet_by_name 函数来处理一组工作表。

这一小节只提供了一个示例来演示如何在工作簿的一组工作表中筛选特定的行。之所以这样做,是因为到目前为止,你应该能够将前面各个示例中的筛选与选择操作集成到这个示例中了。

在一组工作表中筛选特定行

  1. 基础Python

    在这个示例中,我们想从第一个和第二个工作表中筛选出销售额大于 $1900.00 的那些行。要使用基础 Python 从第一个和第二个工作表中筛选出这样的行,在文本编辑器中输入下列代码,然后将文件保存为 11excel_value_meets_condition_set_of_worksheets.py:

     1 #!/usr/bin/env python3
     2 import sys
     3 from datetime import date
     4 from xlrd import open_workbook, xldate_as_tuple
     5 from xlwt import Workbook
     6 input_file = sys.argv[1]
     7 output_file = sys.argv[2]
     8 output_workbook = Workbook()
     9 output_worksheet = output_workbook.add_sheet('set_of_worksheets')
    10 my_sheets = [0,1]
    11 threshold = 1900.0
    12 sales_column_index = 3
    13 first_worksheet = True
    14 with open_workbook(input_file) as workbook:
    15     data = []
    16     for sheet_index in range(workbook.nsheets):
    17          if sheet_index in my_sheets:
    18               worksheet = workbook.sheet_by_index(sheet_index)
    19               if first_worksheet:
    20                    header_row = worksheet.row_values(0)
    21                    data.append(header_row)
    22                    first_worksheet = False
    23               for row_index in range(1,worksheet.nrows):
    24                    row_list = []
    25                    sale_amount = worksheet.cell_value\
    26                    (row_index, sales_column_index)
    27                    if sale_amount > threshold:
    28                         for column_index in range(worksheet.ncols):
    29                              cell_value = worksheet.cell_value\
    30                              (row_index,column_index)
    31                              cell_type = worksheet.cell_type\
    32                              (row_index, column_index)
    33                              if cell_type == 3:
    34                                   date_cell = xldate_as_tuple\
    35                                   (cell_value,workbook.datemode)
    36                                   date_cell = date(*date_cell[0:3])\
    37                                   .strftime('%m/%d/%Y')
    38                                   row_list.append(date_cell)
    39                              else:
    40                                   row_list.append(cell_value)
    41                    if row_list:
    42                         data.append(row_list)
    43    for list_index, output_list in enumerate(data):
    44         for element_index, element in enumerate(output_list):
    45               output_worksheet.write(list_index, element_index, element)
    46 output_workbook.save(output_file)
    
    

    第 10 行代码创建了一个列表变量 my_sheets,其中包含两个整数,表示要处理的工作表的索引值。

    第 16 行代码创建了工作簿中所有工作表的索引值,并在这些索引值上应用一个 for 循环。

    第 17 行代码检验 for 循环中要处理的索引值是否是 my_sheets 中的一个索引值。这个检验确保代码只处理那些我们想处理的工作表。

    因为我们在工作表索引值之间迭代,所以在第 18 行代码中,需要使用工作簿的 sheet_by_index 函数与索引值一起引用当前工作表。

    对于要处理的第一个工作表,第 19 行代码为 True,所以我们将标题行追加到 data 中,然后将 first_worksheet 设为 False。此后,和前面的示例一样,以同样的方法处理余下的数据行。对于第二个和此后要处理的工作表,脚本直接转到第 23 行代码来处理工作表中的数据行。

    要运行这个脚本,在命令行中输入以下命令,然后按回车键:

    python 11excel_value_meets_condition_set_of_worksheets.py sales_2013.xlsx\
    output_files\11output.xls
    
    

    你可以打开输出文件 11output.xls 查看一下结果。

  2. pandas

    使用 pandas 在工作簿中选择一组工作表非常容易。你只需在 read_excel 函数中将工作表的索引值或名称设置成一个列表就可以了。在这个示例中,我们创建一个索引值列表 my_sheets,然后在 read_excel 函数中设定 sheetname 等于 my_sheets

    要使用 pandas 选择一组工作表,在文本编辑器中输入下列代码,然后将文件保存为 pandas_value_meets_condition_set_of_worksheets.py:

    #!/usr/bin/env python3
    import pandas as pd
    import sys
    input_file = sys.argv[1]
    output_file = sys.argv[2]
    my_sheets = [0,1]
    threshold = 1900.0
    data_frame = pd.read_excel(input_file, sheetname=my_sheets, index_col=None)
    row_list = []
    for worksheet_name, data in data_frame.items():
        row_list.append(data[data['Sale Amount'].astype(float) > threshold])
    filtered_rows = pd.concat(row_list, axis=0, ignore_index=True)
    writer = pd.ExcelWriter(output_file)
    filtered_rows.to_excel(writer, sheet_name='set_of_worksheets', index=False)
    writer.save()
    
    

    要运行这个脚本,在命令行中输入以下命令,然后按回车键:

    python pandas_value_meets_condition_set_of_worksheets.py\
    sales_2013.xlsx output_files\pandas_output.xls
    
    

    你可以打开输出文件 pandas_output.xls 查看一下结果。

3.5 处理多个工作簿

本章前面的几小节演示了如何为单个工作表、工作簿中所有的工作表和工作簿中的一组工作表筛选出特定的行与特定的列。这些处理工作簿的技术是非常有用的。但是,有时你需要处理多个工作簿。在这种情况下,Python 会给你惊喜,因为它可以让你自动化和规模化地进行数据处理,远远超过手工处理能够达到的限度。

这一节重新引入了 Python 内置的 glob 模块,之前第 2 章中曾介绍过这个模块。在本章前面几个示例的基础上,下面演示一下如何处理多个工作簿。

为了使用多个工作簿,首先需要创建多个工作簿。那么让我们再创建另外两个 Excel 工作簿,这样就一共有 3 个工作簿了。但是,请记住这里介绍的技术可以扩展为处理任意多的文件,只要计算机能力允许。

先从下面这个步骤开始。

(1) 打开现有的工作簿 sales_2013.xlsx。

现在,创建第二个工作簿。

(2) 将现有的 3 个工作表名称改为 january_2014、february_2014 和 march_2014。

(3) 在 3 个工作表中,将 Purchase Date 列中的年份改成 2014。

每个工作表中有 6 行数据,所以你一共需要进行 18 次修改(6 行 *3 个工作表)。除了修改年份以外,不需要修改其他内容。

(4) 将第二个工作簿保存为 sales_2014.xlsx。

图 3-10 展示了修改过日期后的 january_2014 工作表中的内容。

{%}

图 3-10:修改第一个工作簿中的数据,创建第二个工作簿

现在,创建第三个工作簿。

(5) 将现有的 3 个工作表名称改为 january_2015、february_2015 和 march_2015。

(6) 在 3 个工作表中,将 Purchase Date 列中的年份改成 2015。

每个工作表中有 6 行数据,所以你一共需要进行 18 次修改(6 行 *3 个工作表)。除了修改年份以外,不需要修改其他内容。

(7) 将第三个工作簿保存为 sales_2015.xlsx。

图 3-11 展示了修改过日期后的 january_2015 工作表中的内容。

{%}

图 3-11:修改第二个工作簿中的数据,创建第三个工作簿

3.5.1 工作表计数以及每个工作表中的行列计数

在某些情况下,你知道要处理的工作簿中的内容。但是,有些时候工作簿不是你创建的,所以你不清楚其中的内容。与 CSV 文件不同,Excel 工作簿可以包含多个工作表,所以如果你不清楚这些工作表中的内容,那么在开始处理工作表之前,获取一些关于工作表的描述性信息则是非常重要的。

如果想知道一个文件夹中工作簿的数量,每个工作簿中工作表的数量,以及每个工作表中行与列的数量,在文本编辑器中输入下列代码,然后将文件保存为 12excel_introspect_all_workbooks.py:

 1 #!/usr/bin/env python3
 2 import glob
 3 import os
 4 import sys
 5 from xlrd import open_workbook
 6 input_directory = sys.argv[1]
 7 workbook_counter = 0
 8 for input_file in glob.glob(os.path.join(input_directory, '*.xls*')):
 9     workbook = open_workbook(input_file)
10     print('Workbook: %s' % os.path.basename(input_file))
11     print('Number of worksheets: %d' % workbook.nsheets)
12     for worksheet in workbook.sheets():
13          print('Worksheet name:', worksheet.name, '\tRows:',\
14                    worksheet.nrows, '\tColumns:', worksheet.ncols)
15     workbook_counter += 1
16 print('Number of Excel workbooks: %d' % (workbook_counter))

第 2 和 3 行代码分别导入 Python 内置的 glob 模块和 os 模块,以使我们可以使用其中的函数识别和解析待处理文件的路径名。

第 8 行代码使用 Python 内置的 glob 模块和 os 模块创建了一个要处理的输入文件列表,并对这个输入文件列表应用 for 循环,这行代码可以使我们对所有要处理的工作簿进行迭代。

第 10~14 行代码在屏幕上打印出每个工作簿的信息。第 10 行代码打印工作簿的名称。第 11 行代码打印工作簿中工作表的数量。第 13 和 14 行代码打印出工作簿中工作表的名称和每个工作表中行与列的数量。

要运行这个脚本,在命令行中输入以下命令,然后按回车键:

python 12excel_introspect_all_workbooks.py "C:\Users\Clinton\Desktop"

你应该可以看到输出被打印到屏幕上,如图 3-12 所示。

{%}

图 3-12:处理多个工作簿的 Python 脚本的输出

输出显示,脚本处理了 3 个工作簿,还打印出了 3 个工作簿的名称(例如:sales_2013.xls)、每个工作簿中 3 个工作表的名称(例如:january_2013),以及每个工作表中行与列的数量(例如:7 行和 5 列)。

当你对要处理的文件不太熟悉的时候,打印出文件的一些描述性信息是非常有用的。知道了文件的数量以及每个文件中行与列的数量,你就可以大致了解文件处理任务量和文件内容的一致性了。

3.5.2 从多个工作簿中连接数据

  1. 基础Python

    要使用基础 Python 将多个工作簿中所有工作表的数据垂直连接成一个输出文件,在文本编辑器中输入下列代码,然后将文件保存为 13excel_concat_data_from_multiple_workbook.py:

     1 #!/usr/bin/env python3
     2 import glob
     3 import os
     4 import sys
     5 from datetime import date
     6 from xlrd import open_workbook, xldate_as_tuple
     7 from xlwt import Workbook
     8 input_folder = sys.argv[1]
     9 output_file = sys.argv[2]
    10 output_workbook = Workbook()
    11 output_worksheet = output_workbook.add_sheet('all_data_all_workbooks')
    12 data = []
    13 first_worksheet = True
    14 for input_file in glob.glob(os.path.join(input_folder, '*.xls*')):
    15     print os.path.basename(input_file)
    16     with open_workbook(input_file) as workbook:
    17          for worksheet in workbook.sheets():
    18               if first_worksheet:
    19                    header_row = worksheet.row_values(0)
    20                    data.append(header_row)
    21                    first_worksheet = False
    22               for row_index in range(1,worksheet.nrows):
    23                    row_list = []
    24                    for column_index in range(worksheet.ncols):
    25                         cell_value = worksheet.cell_value\
    26                         (row_index,column_index)
    27                         cell_type = worksheet.cell_type\
    28                         (row_index, column_index)
    29                         if cell_type == 3:
    30                              date_cell = xldate_as_tuple\
    31                              (cell_value,workbook.datemode)
    32                              date_cell = date(*date_cell[0:3])\
    33                              .strftime('%m/%d/%Y')
    34                              row_list.append(date_cell)
    35                         else:
    36                              row_list.append(cell_value)
    37                    data.append(row_list)
    38 for list_index, output_list in enumerate(data):
    39     for element_index, element in enumerate(output_list):
    40               output_worksheet.write(list_index, element_index, element)
    41 output_workbook.save(output_file)
    
    

    第 13 行代码创建了一个布尔型(就是 True/False)变量 first_worksheet,用来区别要处理的第一个工作表和其他后续工作表。对于要处理的第一个工作表,第 18 行代码为 True,所以我们将标题行追加到 data 中,然后将 first_worksheet 设为 False

    对于第一个工作表中余下的数据行和后续工作表中的所有行,我们跳过标题行,处理数据行。因为第 22 行代码中的 range 函数不是从 0 开始,而是从 1 开始的,所以我们知道是从第二行开始处理的。

    要运行这个脚本,在命令行中输入以下命令,然后按回车键:

    python 13excel_ concat_data_from_multiple_workbooks.py "C:\Users\Clinton\Desktop"\
    output_files\13output.xls
    
    

    你可以打开输出文件 13output.xls 查看一下结果。

  2. pandas

    pandas 提供了 concat 函数来连接数据框。如果你想把数据框一个一个地垂直堆叠起来,那么就要设置参数 axis=0。如果你想把数据框一个一个地平行连接起来,那么就要设置参数 axis=1。此外,如果你需要基于某个关键字列连接数据框,pandas 中的 merge 函数可以提供类似 SQL join 的操作(如果你不理解这个,没有关系,接下来的第 4 章中会有更多关于数据库的介绍)。

    要使用 pandas 将多个工作簿中所有工作表的数据垂直连接成一个输出文件,在文本编辑器中输入下列代码,然后将文件保存为 pandas_concat_data_from_multiple_workbook.py:

    #!/usr/bin/env python3
    import pandas as pd
    import glob
    import os
    import sys
    input_path = sys.argv[1]
    output_file = sys.argv[2]
    all_workbooks = glob.glob(os.path.join(input_path,'*.xls*'))
    data_frames = []
    for workbook in all_workbooks:
        all_worksheets = pd.read_excel(workbook, sheetname=None, index_col=None)
        for worksheet_name, data in all_worksheets.items():
             data_frames.append(data)
    all_data_concatenated = pd.concat(data_frames, axis=0, ignore_index=True)
    writer = pd.ExcelWriter(output_file)
    all_data_concatenated.to_excel(writer, sheet_name='all_data_all_workbooks',\
    index=False)
    writer.save()
    
    

    要运行这个脚本,在命令行中输入以下命令,然后按回车键:

    python pandas_concat_data_from_multiple_workbooks.py "C:\Users\Clinton\Desktop"\
    output_files\pandas_output.xls
    
    

    你可以打开输出文件 pandas_output.xls 查看一下结果。

3.5.3 为每个工作簿和工作表计算总数和均值

  1. 基础Python

    要使用基础 Python 为多个工作簿计算工作表级别和工作簿级别的统计量,在文本编辑器中输入下列代码,然后将文件保存为 14excel_sum_average_multiple_workbook.py:

     1 #!/usr/bin/env python3
     2 import glob
     3 import os
     4 import sys
     5 from datetime import date
     6 from xlrd import open_workbook, xldate_as_tuple
     7 from xlwt import Workbook
     8 input_folder = sys.argv[1]
     9 output_file = sys.argv[2]
    10 output_workbook = Workbook()
    11 output_worksheet = output_workbook.add_sheet('sums_and_averages')
    12 all_data = []
    13 sales_column_index = 3
    14 header = ['workbook', 'worksheet', 'worksheet_total', 'worksheet_average',\
    15                         'workbook_total', 'workbook_average']
    16 all_data.append(header)
    17 for input_file in glob.glob(os.path.join(input_folder, '*.xls*')):
    18     with open_workbook(input_file) as workbook:
    19          list_of_totals = []
    20          list_of_numbers = []
    21          workbook_output = []
    22          for worksheet in workbook.sheets():
    23               total_sales = 0
    24               number_of_sales = 0
    25               worksheet_list = []
    26               worksheet_list.append(os.path.basename(input_file))
    27               worksheet_list.append(worksheet.name)
    28               for row_index in range(1,worksheet.nrows):
    29                    try:
    30                         total_sales += float(str(worksheet.cell_value\
    31                         (row_index,sales_column_index))\
    32                         .strip('$').replace(',',''))
    33                         number_of_sales += 1.
    34                    except:
    35                          total_sales += 0.
    36                          number_of_sales += 0.
    37                average_sales = '%.2f' % (total_sales / number_of_sales)
    38                worksheet_list.append(total_sales)
    39                worksheet_list.append(float(average_sales))
    40                list_of_totals.append(total_sales)
    41                list_of_numbers.append(float(number_of_sales))
    42                workbook_output.append(worksheet_list)
    43           workbook_total = sum(list_of_totals)
    44           workbook_average = sum(list_of_totals)/sum(list_of_numbers)
    45           for list_element in workbook_output:
    46                list_element.append(workbook_total)
    47                list_element.append(workbook_average)
    48           all_data.extend(workbook_output)
    49  
    50  for list_index, output_list in enumerate(all_data):
    51      for element_index, element in enumerate(output_list):
    52           output_worksheet.write(list_index, element_index, element)
    53  output_workbook.save(output_file)
    
    

    第 12 行代码创建了一个空列表 all_data,用来保存要写入输出文件的所有行。第 13 行代码创建了一个变量 sales_column_index,保存 Sale Amount 列的索引值。

    第 14 行代码为输出文件创建了一个列标题列表,并使用第 16 行代码将其追加到 all_data 中。

    在第 19、20 和 21 行代码中,分别创建了 3 个列表。list_of_totals 用来保存工作簿中所有工作表的销售额总计。同样,list_of_numbers 用来保存工作簿的所有工作表中用来计算总销售额的销售额数据个数。第三个列表,workbook_output,用来保存要写入输出文件的所有输出列表。

    第 25 行代码创建了一个列表 worksheet_list,用来保存要保留的所有工作表的信息。在第 26 和 27 行代码中,将工作簿名称和工作表名称追加到 worksheet_list 中。同样,在第 38 和 39 行代码中,将销售额总计和均值追加到 worksheet_list 中。在第 42 行代码中,将 worksheet_list 追加到 workbook_output 中,在工作簿级别保存信息。

    在第 40 和 41 行代码中,将工作表的销售额总计和销售额数据个数分别追加到 list_of_totalslist_of_numbers 中,这样我们可以对所有工作表保存这些值。在第 43 和 44 行代码中,使用这两个列表计算出工作簿的销售额总计和销售额均值。

    在第 45~47 行代码中,我们在 workbook_output 的各个列表之间迭代(每个工作簿有 3 个列表,因为每个工作簿有 3 个工作表),并将工作簿级别的销售额总计和均值追加到每个列表中。

    当获得了所有要为工作簿保留的信息之后(就是 3 个列表,每个工作表有一个列表),就将这些列表扩展到 all_data 中。我们使用 extend,不是 append,以使 workbook_output 中的每个列表都会成为 all_data 中的一个独立元素。这样的话,在处理完所有工作簿之后,all_data 就是一个具有 9 个元素的列表,每个元素都是一个列表。否则,如果使用 appendall_data 中就会只有 3 个元素,每个元素都是一个列表的列表。

    要运行这个脚本,在命令行中输入以下命令,然后按回车键:

    python 14excel_sum_average_multiple_workbooks.py "C:\Users\Clinton\Desktop"\
    output_files\14output.xls
    
    

    你可以打开输出文件 14output.xls 查看一下结果。

  2. pandas

    pandas 可以直接在多个工作簿之间迭代,并可以同时在工作簿级别和工作表级别计算统计量。在下面的脚本中,为工作簿中的每个工作表计算统计量,然后将结果连接成一个数据框。接下来,计算工作簿级别的统计量,将它们转换成一个数据框,然后通过基于工作簿名称的左连接将两个数据框合并在一起,并将结果数据框添加到一个列表中。当所有工作簿级别的数据框都进入列表之后,将这些数据框连接成一个独立数据框,并写入输出文件。

    要使用 pandas 计算工作表级别和工作簿级别的统计量,在文本编辑器中输入下列代码,然后将文件保存为 pandas_sum_average_multiple_workbook.py:

    #!/usr/bin/env python3
    import pandas as pd
    import glob
    import os
    import sys
    input_path = sys.argv[1]
    output_file = sys.argv[2]
    all_workbooks = glob.glob(os.path.join(input_path,'*.xls*'))
    data_frames = []
    for workbook in all_workbooks:
        all_worksheets = pd.read_excel(workbook, sheetname=None, index_col=None)
        workbook_total_sales = []
        workbook_number_of_sales = []
        worksheet_data_frames = []
        worksheets_data_frame = None
        workbook_data_frame = None
        for worksheet_name, data in all_worksheets.items():
             total_sales = pd.DataFrame([float(str(value).strip('$').replace(\
             ',',''))
             for value in data.loc[:, 'Sale Amount']]).sum()
             number_of_sales = len(data.loc[:, 'Sale Amount'])
             average_sales = pd.DataFrame(total_sales / number_of_sales)
     
             workbook_total_sales.append(total_sales)
             workbook_number_of_sales.append(number_of_sales)
             data = {'workbook': os.path.basename(workbook),
                       'worksheet': worksheet_name,
                       'worksheet_total': total_sales,
                       'worksheet_average': average_sales}
     
             worksheet_data_frames.append(pd.DataFrame(data, \
             columns=['workbook', 'worksheet', \
             'worksheet_total', 'worksheet_average']))
        worksheets_data_frame = pd.concat(\
        worksheet_data_frames, axis=0, ignore_index=True)
        workbook_total = pd.DataFrame(workbook_total_sales).sum()
        workbook_total_number_of_sales = pd.DataFrame(\
        workbook_number_of_sales).sum()
        workbook_average = pd.DataFrame(\
        workbook_total / workbook_total_number_of_sales)
     
        workbook_stats = {'workbook': os.path.basename(workbook),
                             'workbook_total': workbook_total,
                             'workbook_average': workbook_average}
        workbook_stats = pd.DataFrame(workbook_stats, columns=\
        ['workbook', 'workbook_total', 'workbook_average'])
        workbook_data_frame = pd.merge(worksheets_data_frame, workbook_stats, \
        on='workbook', how='left')
        data_frames.append(workbook_data_frame)
    all_data_concatenated = pd.concat(data_frames, axis=0, ignore_index=True)
    writer = pd.ExcelWriter(output_file)
    all_data_concatenated.to_excel(writer, sheet_name='sums_and_averages', \
    index=False)
    writer.save()
    
    

    要运行这个脚本,在命令行中输入以下命令,然后按回车键:

    python pandas_sum_average_multiple_workbooks.py "C:\Users\Clinton\Desktop"\
    output_files\pandas_output.xls
    
    

    你可以打开输出文件 pandas_output.xls 查看一下结果。

    本章介绍了很多基础性操作,包括读取和分析 Excel 工作簿、在工作表中浏览行与列、处理多个 Excel 工作表、处理多个 Excel 工作簿、以及为多个 Excel 工作表和工作簿计算统计量的方法。如果一直跟随本章内容练习示例代码,你应该完成了 14 个新的 Python 脚本!

    练习本章中示例代码的最大收获是,你很好地掌握了浏览和处理 Excel 文件的技术,而 Excel 文件是商业过程中最常用的一种文件。而且,因为很多商业机构将数据保存在 Excel 工作簿中,所以你现在已经掌握了处理这些工作簿中数据的一系列方法,无论工作簿的数量和体积有多大,也无论每个工作簿中有多少工作表,你都可以使用计算机数据处理的强大能力来自动化和规模化地处理和分析 Excel 工作簿中的各种数据。

    我们要面对的下一个数据源是数据库。因为数据库是一种非常常用的数据存储,所以知道如何访问其中的数据是非常重要的。只要知道了如何访问其中的数据,你就可以像处理 CSV 文件和 Excel 文件一样,同样以一行接一行的方式来处理这些数据。掌握了第 2 章和本章中的示例代码之后,你已经完全做好了处理数据库中数据的准备。

3.6 本章练习

(1) 对根据具体条件、集合和正则表达式来筛选行数据的一个脚本进行修改,将与示例代码中不同的一组数据打印出来并写入输出文件。

(2) 对根据索引值或列标题来筛选列数据的一个脚本进行修改,将与示例代码中不同的一组数据打印出来并写入输出文件。

(3) 创建一个新的 Python 脚本,将筛选行或列的某个脚本中的代码与从多个工作簿中连接数据的某个脚本中的代码组合起来,生成一个新的输出文件,其中包含来自于多个工作簿的特定行与特定列。

目录