根据ID提取文件中相应行的python脚本实现与详细讲解

这个代码是一个处理数据入门级别的 python 脚本,我尽可能详细地解释一下,方便小白入门。

这个代码目的是根据提供的ID文件从大文件中提取这些ID的行,生成一个新的文件, 与 Excel 的 vlookup 函数功能相似,优点是自动化。另外Excel 处理大数据会卡,甚至卡死,这时必须要用代码。

使用软件

  • python 3.8 及以上版本

输入文件格式

  • ID 文件:第一列必须为需要提取的ID,可以包含其他无关列,以空格或制表符分隔。

  • 大文件:用于提取信息的文件,第一列为ID,ID不能重复,以空格或制表符分隔。

输出文件格式

输出文件为 ID 文件中的 ID 在大文件中的行。

运行代码

代码文件见:pick0.py

将两个输入文件和本程序放在同一文件夹下,运行命令示范如下:

1
python pick0.py id.txt bigfile.txt out.txt

参数说明

id.txt : 第一个参数为 ID文件名称

bigfile.txt:第二个参数为大文件名称

out.txt:第三个参数为输出文件名称

例子

举个简单的例子。

id 文件为 id.txt ,内容如下

YYJXNM518090007
YYJXNM518088704
YYJXNM518086910

大文件为 big.txt,内容如下

YYJXNM518090007 202733730005_R01C02 1
YYJXNM518087902 202733730005_R01C04 1
YYJXNM518091108 202733730005_R02C01 1
YYJXNM518089506 202733730005_R02C02 1
YYJXNM518088704 202733730005_R02C03 1
YYJXNM518089706 202733730005_R02C04 1
YYJXNM518087310 202733730005_R03C01 1
YYJXNM518083704 202733730005_R03C03 1
YYJXNM518088705 202733730005_R03C04 1
YYJXNM518086910 202733730005_R04C01 1

执行命令

1
python pick0.py id.txt big.txt out.txt

结果文件为 out.txt,内容如下,顺序与ID文件一致。

YYJXNM518090007 202733730005_R01C02 1
YYJXNM518088704 202733730005_R02C03 1
YYJXNM518086910 202733730005_R04C01 1

代码说明

注释说明

首先是两行注释,第一句以#!开头,后面接着的是我在linux系统中安装的python路径。

1
#!/mnt/data/zhouziwen/bin/miniConda/miniconda3/bin/python

添加这句话的目的是指定解释器,就是说用什么去执行这个脚本。添加这个命令后,在给这个程序添加执行权限后(如何添加执行权限见linux 的 chmod命令 ),可以将这个脚本视为正常的shell脚本执行,例子如下(需要先修改为你自己的python路径

1
./pick0.py id.txt bigfile.txt out.txt

如果你没看懂,不要紧,这个不重要,你就还是按照上面的运行代码部分写的运行命令去运行即可。

第二行注释是指定字符编码为 utf-8(字符编码的内容可以看看这篇博客,字符编码那点事) ,不然写中文注释会报错。

1
#coding=utf-8

导入模块

python 的模块就相当于 R中的安装包,这里我们使用一个内置模块sys,目的是可以输入参数。

1
import sys 

打开文件

这里我们使用 sys 模块的 sys.argv 导入外部参数,这里 sys.argv[1] 就是第一个参数,sys.argv[2] 就是第二个参数,以此类推。

在 python 中使用 open 函数打开文件,后面跟着 'r' 是读取文件,'w' 则是写入文件(没有则新建,已有该文件会直接覆盖),这两个分别是 readwrite 的缩写。open 函数更具体的说明见open() 函数-菜鸟教程

这里的意思就是说,将输入的第一个参数以只读模式打开,命名为 id ;同样将第二个参数以只读模式打开,命名为 bigfile ;将第三个参数以写入模型打开,命名为 outfile

1
2
3
id = open(sys.argv[1],'r')
bigfile = open(sys.argv[2],'r')
outfile = open(sys.argv[3],'w')

创建集合和字典

这里我们创建一个空的集合和一个空的字典,分别命名为 set1 和 dick,一行同时创建两个变量用分号隔开。

集合和字典都是 python的可变数据结构,底层都是采用了哈希表。集合是存储单个值,字典是存储键值对,二者的共同特点是键不能重复,键出现重复会直接覆盖旧的数据。这一块我一句两句讲不清楚,不知道的可以自行上网看一些python的资料,只需要输入python和数据结构两个关键字,就能找到一堆资料了。

我这里用集合和字典,主要是利用它们查询快的特点(查看某个值是否在集合/字典中)。

1
set1 = set();dick={}

遍历大文件

python 可以使用 for 循环对一个文件的所有行进行遍历。不同的层次结构用缩进表示,每次缩进必须为 4 个空格。

1
2
3
4
5
6
7
for i in bigfile:
f = i.split()
if f[0] not in dick:
dick[f[0]] = i
else:
print(f"Error: duplicated id {f[0]} in {sys.argv[2]}\n")
sys.exit(1)

下面我们一行一行来看,第一句是 for 循环,遍历所有行,每一行的内容为一个字符串,并且这里命名为i

1
for i in bigfile:

第二句话利用python字符串对象的 split()函数,将每一行的内容按照空白符(空格或制表符)进行分割,分隔结果为一个由各列内容组成的列表,命名为 fsplit() 函数的具体解释见split() 函数-菜鸟教程

1
f = i.split()

下面就是一个 if-else 结构,由于 python 索引是从0开始的,因此 f[0] 表示第一列的内容。

首先判断 f[0] 是否在 dick 字典中,in 表示 f[0] 是否在 dick 中,加 not 表示否定,也就是如果 f[0] 不在 dick 中的话,那么执行 dick[f[0]] = i,即在dick 字典中新增键为 f[0] ,值为 ii 为整行的内容)的一条记录。如果 f[0]dick 中,此时说明第一列存在重复ID,执行else 部分,else 部分首先用 print函数打印了一条报错信息,内部采用了 python新推出的 f-string ,用于格式化字符串(具体可见f-string格式化输出),简单地说,就是将{}的部分使用其中变量的内容,f-string不清楚可以先放一放;然后采用 sys.exit(1) 直接退出程序。

我再用人话说一遍目的,这里就是判断大文件的ID是否有重复,只要存在重复那么程序会直接报错终止。不存在重复的话,那么就会往dick字典中新增内容,键为ID,值为整行内容。

1
2
3
4
5
if f[0] not in dick:
dick[f[0]] = i
else:
print(f"Error: duplicated id {f[0]} in {sys.argv[2]}\n")
sys.exit(1)

遍历ID文件,生成结果文件

这里首先新增了两个数字变量和一个列表。这三个的目的是,not_in_num 是ID文件中的ID不在大文件中的数目,duplicate_id_num 是ID文件中剔除的重复ID的数目,not_in_list 是是ID文件中的ID不在大文件中的ID组成的列表。

1
2
3
not_in_num = 0
duplicate_id_num = 0
not_in_list = []

遍历ID文件,这里将一下流程,首先会对ID进行去重,然后判断ID是否在dick中,如果在,那么就将这个ID对应的大文件中的行内容写入到输出文件。

1
2
3
4
5
6
7
8
9
10
11
for i in id:
f = i.split()
if f[0] not in set1: #id文件去重
set1.add(f[0])
if f[0] in dick:
outfile.write(dick[f[0]])
else:
not_in_num += 1
not_in_list.append(f[0])
else:
duplicate_id_num += 1

如果ID文件中存在重复ID,打印信息

1
2
if duplicate_id_num > 0:
print(f"Warning: {duplicate_id_num} duplicated id in {sys.argv[1]}\n")

如果存在不在大文件中的ID,生成一个新的文件,pick0_not_in_id.txt,内容就是不在大文件中的ID,即 not_in_list 的内容。

1
2
3
4
5
6
if not_in_num > 0:
print(f"Warning: {not_in_num} id not in {sys.argv[2]}\n")
not_in_file = open('pick0_not_in_id.txt','w')
for i in not_in_list:
not_in_file.write(f"{i}\n")
not_in_file.close()

关闭文件

使用 open函数打开文件后,记得关闭文件,这是一个好习惯。写入的文件(即'w'模式)只有关闭了文件,才会真正写入到硬盘中。

1
2
3
id.close()
bigfile.close()
outfile.close()
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2019-2024 Vincere Zhou
  • 访问人数: | 浏览次数:

请我喝杯茶吧~

支付宝
微信