2.2 筛选特定的行
有些时候,你并不需要文件中所有的数据。例如,你可能只需要一个包含特定词或数字的行的子集,或者是与某个具体日期关联的行的子集。在这些情况下,可以用 Python 筛选出特定的行来使用。
你应该很熟悉如何在 Excel 中手动筛选行,但是本章的重点在于提高你的能力,使你既能处理因为体积太大以致 Excel 不能打开的 CSV 文件,又能处理多个 CSV 文件。因为要通过手动处理这些文件,时间花费太多了。
下面各小节演示了在输入文件中筛选出特定行的 3 种方法:
· 行中的值满足某个条件
· 行中的值属于某个集合
· 行中的值匹配于某个模式(正则表达式)
你会发现这些小节中的代码在结构上是一致的。接下来会详细解释这种通用结构,使你可以轻松地修改代码来满足自己的业务规则。
在下面的 3 个小节中,请注意以下结构,从而来理解如何从输入文件中筛选出特定的行:
for row in filereader: ***if value in row meets some business rule or set of rules:*** do something else: do something else
这段伪代码展示了用来在输入文件中筛选出特定行的通用代码结构。在下面的小节中,会修改封装在 *** 之间的代码,以使脚本能够满足具体业务规则,抽取出你需要的数据。
2.2.1 行中的值满足某个条件
01. 基础Python
有些时候,当行中的值满足一个具体条件时,才需要保留这些行。例如,你可能会希望在数据集中保留那些成本高于某个具体阈值的行,或者希望保留所有购买日期在一个具体日期之前的行。在这种情况下,你可以检验行中的值是否满足具体的条件,然后筛选出满足条件的行。
下面的示例演示了检验行值是否满足两个具体条件的方法,并将满足条件的行的子集写入一个输出文件。在这个示例中,保留供应商名字为 Supplier Z 或成本大于 $600.00 的行,并将结果写入输出文件。要筛选出满足这些条件的行的子集,在文本编辑器中输入以下代码,将文件保存为 3csv_reader_value_meets_condition.py:
1 #!/usr/bin/env python3 2 import csv 3 import sys 4 input_file = sys.argv[1] 5 output_file = sys.argv[2] 6 with open(input_file, 'r', newline='') as csv_in_file: 7 with open(output_file, 'w', newline='') as csv_out_file: 8 filereader = csv.reader(csv_in_file) 9 filewriter = csv.writer(csv_out_file) 10 header = next(filereader) 11 filewriter.writerow(header) 12 for row_list in filereader: 13 supplier = str(row_list[0]).strip() 14 cost = str(row_list[3]).strip('$').replace(',', '') 15 if supplier == 'Supplier Z' or float(cost) > 600.0: 16 filewriter.writerow(row_list)
第 10 行代码使用 csv 模块的 next 函数读出输入文件的第一行,赋给名为 header 的列表变量。第 11 行代码将标题行写入输出文件。
第 13 行代码取出每行数据中的供应商名字,并赋给名为 supplier 的变量。这行代码使用列表索引取出每行数据的第一个值 row[0],然后使用 str 函数将其转换为一个字符串。在此之后,使用 strip 函数删除字符串两端的空格、制表符和换行符。最后,将处理好的字符串赋给变量 supplier。
第 14 行代码取出每行数据中的成本,并赋给名为 cost 的变量。这行代码使用列表索引取出每行数据的第四个值 row[3],然后使用 str 函数将其转换为一个字符串。在此之后,使用 strip 函数从字符串中删除美元符号。接着使用 replace 函数从字符串中删除逗号。最后,将处理好的字符串赋给变量 cost。
第 15 行代码创建了一个 if 语句,来检验每行中的这两个值是否满足条件。具体来说,这里想筛选出供应商名字为 Supplier Z 或者成本大于 $600.00 的那些行。if 和 or 之间的第一个条件检验变量 supplier 中的值是否为 Supplier Z。or 和冒号之间的第二个条件检验变量 cost 中的值在被转换为浮点数之后,是否大于 600.0。
第 16 行代码使用 filewriter 的 writerow 函数将满足条件的行写入输出文件。
要运行这个脚本,输入以下命令,然后按回车键:
python 3csv_reader_value_meets_condition.py supplier_data.csv\ output_files\3output.csv
在屏幕上你不会看到任何输出,但可以打开输出文件 3output.csv 看一下结果。检查一下,确保结果正确,然后可以修改一下代码,设定不同的供应商或成本阈值,试着筛选一下其他数据。
02. pandas
pandas 提供了一个 loc 函数,可以同时选择特定的行与列。你需要在逗号前面设定行筛选条件,在逗号后面设定列筛选条件。下面的 loc 函数中的条件设置为:Supplier Name 列中姓名包含 Z,或者 Cost 列中的值大于 600.0,并且需要所有的列。在文本编辑器中输入以下代码,将文件保存为 pandas_value_meets_condition.py(这个脚本使用 pandas 来分析 CSV 文件,并将满足条件的行写入输出文件)。
#!/usr/bin/env python3 import pandas as pd import sys input_file = sys.argv[1] output_file = sys.argv[2] data_frame = pd.read_csv(input_file) data_frame['Cost'] = data_frame['Cost'].str.strip('$').astype(float) data_frame_value_meets_condition = data_frame.loc[(data_frame['Supplier Name']\ .str.contains('Z')) | (data_frame['Cost'] > 600.0), :] data_frame_value_meets_condition.to_csv(output_file, index=False)
在命令行中运行脚本,并给出数据源文件和输出文件。
python pandas_value_meets_condition.py supplier_data.csv\ output_files\pandas_output.csv
在屏幕上你不会看到任何输出,但可以打开输出文件 pandas_output.csv 看一下结果。试试修改一下 loc 函数中的参数,选择出另外一些数据。
2.2.2 行中的值属于某个集合
01. 基础Python
有些时候,当行中的值属于某个集合时,才需要保留这些行。例如,你可能会希望在数据集中保留那些供应商名字属于集合 {Supplier X, Supplier Y} 的行(这里的花括号表示集合,不是 Python 中的字典),或者希望保留所有购买日期属于集合 {'1/20/14', '1/30/14'} 的行。在这种情况下,你可以检验行中的值是否属于某个集合,然后筛选出具有属于该集合的值的行。
下面的示例演示了检验行值是否是集合成员的方法,并将具有集合中的值的行写入到输出文件。在这个示例中,是要保留那些购买日期属于集合 {'1/20/14', '1/30/14'} 的行,并将结果写入输出文件。要筛选出值属于这个集合的行的子集,在文本编辑器中输入以下代码,并将文件保存为 4csv_reader_value_in_set.py:
1 #!/usr/bin/env python3 2 import csv 3 import sys 4 input_file = sys.argv[1] 5 output_file = sys.argv[2] 6 important_dates = ['1/20/14', '1/30/14'] 7 with open(input_file, 'r', newline='') as csv_in_file: 8 with open(output_file, 'w', newline='') as csv_out_file: 9 filereader = csv.reader(csv_in_file) 10 filewriter = csv.writer(csv_out_file) 11 header = next(filereader) 12 filewriter.writerow(header) 13 for row_list in filereader: 14 a_date = row_list[4] 15 if a_date in important_dates: 16 filewriter.writerow(row_list)
第 6 行代码创建了一个名为 important_dates 的列表变量,其中包含两个特定日期,这个变量就是你的集合。创建包含特定值的变量,然后在代码中引用变量,这种编写代码的方式非常有用。使用了这种方式,如果变量值发生了变化,你只需在一个地方修改代码(就是定义变量的地方),变量值的变化就会反映到代码中所有引用该变量的地方。
第 14 行代码取出每一行的购买日期,并将其赋给变量 a_date。从行列表的索引值 row[4] 可知,购买日期在第 5 列。
第 15 行代码创建了一个 if 语句来检验 a_date 变量中的购买日期是否属于 important_dates 这个集合。如果变量值在集合中,下一行代码就将这一行写入输出文件。
在命令行中运行下面脚本:
python 4csv_reader_value_in_set.py supplier_data.csv output_files/4output.csv
你可以打开输出文件 4output.csv 来检查结果。
02. pandas
当行中的值属于某个集合时,如何使用 pandas 筛选出这些行呢?在文本编辑器中输入以下代码,然后将文件保存为 pandas_value_in_set.py(这个脚本分析 CSV 文件,并将值属于某个集合的行写入输出文件):
#!/usr/bin/env python3 import pandas as pd import sys input_file = sys.argv[1] output_file = sys.argv[2] data_frame = pd.read_csv(input_file) important_dates = ['1/20/14', '1/30/14'] data_frame_value_in_set = data_frame.loc[data_frame['Purchase Date'].\ isin(important_dates), :] data_frame_value_in_set.to_csv(output_file, index=False)
这里最重要的新命令就是简洁的 isin。
和以前一样,在命令行中运行脚本,并给出源数据文件名和输出文件名:
python pandas_value_in_set.py supplier_data.csv output_files\pandas_output.csv
你可以打开输出文件 pandas_output.csv 来检查结果。
2.2.3 行中的值匹配于某个模式/正则表达式
01. 基础Python
有些时候,当行中的值匹配了或包含了一个特定模式(也就是正则表达式)时,才需要保留这些行。例如,你可能会希望在数据集中保留所有发票编号开始于“001-”的行,或者希望保留所有供应商名字中包含“Y”的行。在这种情况下,你可以检验行中的值是否匹配或包含某种模式,然后筛选出匹配了或包含了该模式的行。
下面的示例演示了如何检验某个值是否匹配特定的模式,并将具有这种值的行写入输出文件。在这个示例中,保留发票编号由“001-”开头的行,并将结果写入一个输出文件。要筛选出某个值匹配了这个模式的行,在文本编辑器中输入下列代码,然后将文件保存为 5csv_reader_value_matches_pattern.py:
1 #!/usr/bin/env python3 2 import csv 3 import re 4 import sys 5 input_file = sys.argv[1] 6 output_file = sys.argv[2] 7 pattern = re.compile(r'(?P<my_pattern_group>^001-.*)', re.I) 8 with open(input_file, 'r', newline='') as csv_in_file: 9 with open(output_file, 'w', newline='') as csv_out_file: 10 filereader = csv.reader(csv_in_file) 11 filewriter = csv.writer(csv_out_file) 12 header = next(filereader) 13 filewriter.writerow(header) 14 for row_list in filereader: 15 invoice_number = row_list[1] 16 if pattern.search(invoice_number): 17 filewriter.writerow(row_list)
第 3 行代码导入正则表达式(re)模块,这样就可以使用 re 模块中的函数了。
第 7 行代码使用 re 模块的 compile 函数创建一个名为 pattern 的正则表达式变量。如果你学习了第 1 章,那么应该很熟悉这个函数。r 表示将单引号之间的模式当作原始字符串来处理。
元字符 ?P<my_pattern_group> 捕获了名为 <my_pattern_group> 的组中匹配了的子字符串,以便在需要时将它们打印到屏幕或写入文件。
这里要搜索的实际模式是^001-.*。插入符号(^)是一个特殊符号,表示只在字符串开头搜索模式。所以,字符串需要以“001-”开头。句点 . 可以匹配任何字符,除了换行符。所以除换行符之外的任何字符都可以跟在“001-”后面。最后,* 表示重复前面的字符 0 次或更多次。.* 组合在一起用来表示除换行符之外的任意字符可以在“001-”后面出现任意次。更通俗的说法是:字符串在“-”后面可以包含任意值,只要字符串开始于“001-”,就会匹配正则表达式。
最后,参数 re.I 告诉正则表达式进行大小写敏感的匹配。此参数在这个示例中不是太重要,因为模式是数值型的,但是它说明了在模式中包含字符并且需要进行大小写敏感的匹配时,应该如何设置参数。
第 15 行代码使用列表索引从行中取出发票编号,并赋给变量 invoice_number。在下一行中,将在这个变量中寻找模式。
第 16 行代码使用 re 模块的 search 函数在 invoice_number 的值中寻找模式。如果模式出现在 invoice_number 值中,第 17 行代码就将这行写入输出文件。
要运行这个脚本,在命令行中输入以下命令,然后按回车键:
python 5csv_reader_value_matches_pattern.py supplier_data.csv\ output_files\5output.csv
你可以打开输出文件 5output.csv 来查看结果。
02. pandas
要使用 pandas 筛选出匹配于某个模式的行,在文本编辑器中输入下列代码,然后将文件保存为 pandas_value_matches_pattern.py(这个脚本读取 CSV 文件,将匹配于某个模式的行打印在屏幕上,并将同样的行写入输出文件):
#!/usr/bin/env python3 import pandas as pd import sys input_file = sys.argv[1] output_file = sys.argv[2] data_frame = pd.read_csv(input_file) data_frame_value_matches_pattern = data_frame.loc[data_frame['Invoice Number'].\ str.startswith("001-"), :] data_frame_value_matches_pattern.to_csv(output_file, index=False)
使用 pandas 时,可以使用 startwith 函数来搜索数据,不用再使用笨重冗长的正则表达式了。要运行这个脚本,在命令行中输入以下命令,然后按回车键:
python pandas_value_matches_pattern.py supplier_data.csv\ output_files\pandas_output.csv
你可以打开输出文件 pandas_output.csv 查看一下结果。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论