【免费】Python数据分析与脚本编写课程|第五节:处理多个文件
大家好,新的一周开始啦。上周有很多小伙伴反馈说内容很多,刚好我们今天的内容不是很多,并且和上周的学习有联系,大家可以有时间进行学习。还没有来及学习的小伙伴也可以回顾上周的内容哦。
在我们上周的课程中,小亚老师带大家学习了如何读取文件,并且从输出文件中解析到自己需要关注的值。
大家可能比较好奇,明明可以复制粘贴的内容,为什么一定要用代码来完成呢?那是因为如果你只有1或2个文件,这可能是一个非常合理的做法。但是如果你有100个文件要分析呢?如果你有1000个呢?在这种情况下,剪切和粘贴的方法将非常繁琐且耗时。
编写程序来分析数据的真正威力之一在于你可以像分析一个文件一样轻松地分析100个文件。所以今天小亚老师将带领大家解析蛋白质数据库(PDB)中一系列酶结构的PDB文件,并提取每个文件的分辨率数据和原子计数。这些PDB文件都保存在一个名为PDB_files的文件夹中,各位还没有下载的小伙伴可以看第一课的推送,有下载的方法。我们需要确保PDB_files文件夹与今天编写和执行代码在同一目录下。

当我们编写脚本时,我们希望它可以在任何操作系统上使用,因此我们将使用一个名为 os.path.join 的 python 函数,它允许我们以适用于 Windows、Mac OS 的通用方式定义文件路径或Linux。要从任何操作系统上的 Jupyter Notebook 访问此文件,我们可以使用 os 库中的 os.path.join 创建一个直接指向此文件的变量。为了获取与特定模式匹配的所有文件,我们将使用通配符 *。
在这里我们可以输入:
import osfile_location = os.path.join('PDB_files', '*.pdb')print(file_location)
这指定我们要查找名为 PDB_files 的目录中以“.pdb”结尾的所有文件。* 是通配符,可匹配任何字符或字符系列。
接下来我们将使用 glob 库中一个名为 glob 的函数。(由于函数和库具有相同的名称,大家可能会感觉困惑,但我们稍后会看到其他示例,但情况并不都是这样)函数 glob 的输出是符合输入中指定模式的所有文件名的列表,输入是我们刚才指定的文件位置(也就是file_location)。

大家可以看到,我们已经成功显示出了文件名称(filenames)。为了解析我们刚刚读入的每个文件,接下来我们使用嵌套 for 循环读取多个文件。
各位小伙伴可以输入:
for f in filenames:with open(f, 'r') as outfile:data = outfile.readlines()for line in data:if 'RESOLUTION.' in line:res_line = linewords = res_line.split()resolution = float(words[3])print(resolution)
我们来看一下每一行的意思,顺便复习一下之前学习的内容。
for f in filenames:这个循环遍历filenames列表中的每一个文件名。
with open(f, 'r') as outfile:使用open函数以只读模式('r')打开文件f,并将文件对象赋值给outfile。with语句确保文件在处理完成后会被自动关闭。
data = outfile.readlines()读取文件中的所有行,并将它们存储在列表data中。
for line in data:这个循环遍历data列表中的每一行line。
if 'RESOLUTION.' in line:检查当前行是否包含字符串'RESOLUTION.'。
res_line = line如果包含,将该行赋值给res_line变量。
words = res_line.split()使用split()函数将这一行按空白字符(空格、制表符等)分割成单词列表,并将其赋值给words变量。
resolution = float(words[3])从words列表中提取第4个单词(索引为3),并将其转换为浮点数,赋值给resolution变量。
print(resolution)打印提取的分辨率值。
在这段代码中,我们实际上使用了两个 for 循环(大家一定要注意缩进与格式哦),一个嵌套在另一个循环内。外部 for 循环对我们之前读取的文件名进行计数。内部 for 循环对每个文件中的行进行计数,就像我们上一节课的文件解析中所做的那样。

大家可以看到,我们显示出了一堆数字,然而,当前代码当前生成的输出没有那么有用。它没有向我们显示每个PDB文件中的分辨率(RESOLUTION)值来自哪个文件。
这个时候我们需要用到 os.path.basename,这是 os.path 中的另一个函数来获取文件名。这样我们就可以同时显示分子的名称和分辨率。
TIP:
如何看调用库中的所有函数?
使用 help() 函数
help() 函数可以提供模块的文档,包括其所有的函数和类。

使用 dir() 函数
dir() 函数可以列出一个模块的所有属性,包括函数、类和变量。

我们可以修改代码:
for f in filenames:file_name = os.path.basename(f)split_filename = file_name.split('.')molecule_name = split_filename[0]with open(f,"r") as outfile:data = outfile.readlines()for line in data:if 'RESOLUTION.' in line:res_line = linewords = res_line.split()resolution = float(words[3])print(molecule_name, ": ", resolution, " Angstroms", sep = "")
让我们再来理解一下新增代码的意思:
file_name = os.path.basename(f)
使用os.path.basename(f)获取文件f的基本文件名(去除路径),并将其赋值给file_name。
split_filename = file_name.split('.')
将file_name按照点号(.)分割成一个列表,并将结果赋值给split_filename。
molecule_name = split_filename[0]
获取分割后的列表的第一个元素(即文件名的主干部分),并将其赋值给molecule_name。
print(molecule_name, ": ", resolution, " Angstroms", sep = "")
打印出分子名称molecule_name、分辨率值resolution和单位”Angstroms”(表示单位"埃(Å)),使用sep=“"来确保没有额外的分隔符(如空格)。
TIP:
在 print() 函数中,sep 参数用来指定打印多个对象时使用的分隔符。默认情况下,print() 函数使用空格作为分隔符。如果想用其他字符或没有分隔符,可以通过设置 sep 参数来实现。
在我们的代码中,sep="" 的作用是确保在打印 molecule_name、: 、resolution 和 " Angstroms" 之间没有额外的空格。
到这里,我们的课程来到了最后一步,保存我们提取的内容并生成文件。这样我们就可以与其他小伙伴分享我们的结果。
就像我们读取文件一样,我们也有两种方式将输出写入文件。在这里我们推荐使用上下文管理器(也就从一开始就使用 with 关键字)。这个方法的优点是,为文件生成输入的所有步骤都缩进到初始 with 语句下,并且当完成 with 语句下缩进的所有操作时,文件将自动关闭。
我们继续优化我们的代码:
with open('resolutions.txt', 'w+') as datafile:for f in filenames:file_name = os.path.basename(f)split_filename = file_name.split('.')molecule_name = split_filename[0]with open(f,"r") as outfile:data = outfile.readlines()for line in data:if 'RESOLUTION.' in line:res_line = linewords = res_line.split()resolution = float(words[3])datafile.write(F'{molecule_name} \t {resolution} \n')
我们来看下新增代码的意思:
with open('resolutions.txt', 'w+') as datafile:
以读写模式(’w+’)打开一个名为’resolutions.txt'的文件,并将文件对象赋值给datafile。如果文件不存在,将创建一个新文件。如果文件已存在,将清空文件内容。with语句确保文件在处理完成后会被自动关闭。
datafile.write(F'{molecule_name} \t {resolution} \n')
将分子名称molecule_name、制表符\t、分辨率值resolution和换行符\n写入到datafile文件中。
TIP:
我们还可以使用 a for 附加到现有文件或 a+。w+ 和 a+ 之间的区别在于,如果文件已存在,w+ 将覆盖该文件,而 a+ 将保留已存在的内容,仅向文件添加其他文本。
Python 只能将字符串写入文件。在下一个单元格中,我们要打印两个变量的内容,分子名称和分辨率。要将我们现在拥有的内容转换为字符串,需要在打印的行前面放置一个大写的 F,并将要打印的内容括在单引号中。每个 Python 变量都放在大括号 {} 中。为了更整洁,我们将使用制表符将 PDB ID 与分辨率分开。我们使用特殊字符 \t 来插入制表符。在文件写入行中,请注意行末尾的 \n。这是换行符。如果没有它,我们文件中的文本就会全部挤在一行上。
运行此命令后,各位同学可以在运行代码的目录中查找并找到“resolutions.txt”文件。然后在文本编辑器中打开它并查看该文件。

今天的所有课程到这里就结束啦,下面是练习时间哦!
练习题
我们刚才提取的是 PDB 文件中的分辨率(resolutions),如果我们要提取 PDB 文件中一系列酶的编号(也就是EC编号,关键词是“EC:”),并将其写入文本文件。我们需要怎么做呢?换句话说,我们这次的任务是解析 data/PDB_files 文件夹中的文件并编写一个名为 EC_class.txt 的新文件,其中包含每种酶的 PDB ID 和 EC 类别。
当我们编写代码时,将必须执行的操作分解为步骤会很有帮助。总的来说,我们希望从文件中获取信息。如果考虑完成这项任务所需的步骤,可能会有一个如下的顺序:
1.打开文件进行读取。
2.读取文件中的数据。
3.循环遍历文件中的行。
4.阅读文件以获取我们想要的信息。
5.提取所需的信息并将其写入文件。
各位小伙伴可以一步步来,首先考虑第 1 步必须做什么,并为此编写代码。接下来,考虑如何执行步骤 2 并为此编写代码。大家记得使用打印语句(print)对每个步骤进行故障排除。
这些步骤是相互关联的,因此您可以先写好第一段代码,然后再继续往下写。
我们下期公布答案哦!预告一下,下期我们就要正式处理数据,将带大家使用Pandas进行数据处理。希望大家可以再复习一下文件的提取与打开,为后续的课程打好基础。



沪公网安备 31011002003500