返回介绍

2.2 筛选特定的行

发布于 2024-01-27 22:10:03 字数 8609 浏览 0 评论 0 收藏 0

有些时候,你并不需要文件中所有的数据。例如,你可能只需要一个包含特定词或数字的行的子集,或者是与某个具体日期关联的行的子集。在这些情况下,可以用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文