0

我是 python 新手,为两个制表符分隔的输入文件创建了两个数组。我正在寻找一种方法来将一个数组的列(元素)与另一个数组的元素进行数字比较。有没有办法做到这一点。到目前为止,我的代码如下

#!/usr/bin/python
import sys
from array import *
#print len(sys.argv)
if len(sys.argv) != 4:
 print 'Usage: python scores.py <infile1> <infile2> <outfile>'
 sys.exit(1)

f1 = open ("12877overlappedallvariants.gvf", "r")
f2 = open ("unmatched.12877overlappedallvariants.gvf", "r")
f3 = open ("out.txt", "w")

for line in f1.readlines():
 cols = line.split('\t')
 #print cols[5:6]


for line in f2.readlines():
 cols1 = line.split('\t')
 #print cols1[5:6]

我尝试了下面的代码部分,但不起作用

slice1 = cols[5:6]
slice2 = cols1[5:6]
new_list = []
for element in slice1:
 if element in slice2:
  new_list.append(element)
  print new_list  

我正在尝试查看 array1 的元素 5 是否等于、大于或小于 array2 的元素 5。任何帮助表示赞赏。谢谢。

4

3 回答 3

1

值得注意的是,这些是列表,而不是数组。它们是有区别的。

每次循环时都会覆盖cols- 这意味着您只会获得最后一行数据 - 列表理解是为了在这里获取您想要的所有数据,或者更好的是,根本不存储数据 - 执行你想要的操作就可以了。

您比较的主要问题是您正在获取列表切片,而不仅仅是获取您需要的元素。这使您尝试做的事情过于复杂。

因此,正如我在评论中提到的,您可以对初始代码进行很多改进——主要是with语句和csv模块。

所以首先,使用with语句打开你的文件。我们csv.reader()也使用"excel-tab"方言,因为它是一个制表符分隔的文件,并csv.QUOTE_NONNUMERIC告诉它值是数字,所以我们以后不必将它们从字符串转换。请注意,如果只有某些值是数字,您要么需要引用所有非数字值才能使用此方法,要么显式转换这些值而不使用它。

with open("file1.tsv") as file1, open("file2.tsv") as file2:
    rows = csv.reader(file2, dialect="excel-tab", quoting=csv.QUOTE_NONNUMERIC)
    rows1 = csv.reader(file2, dialect="excel-tab", quoting=csv.QUOTE_NONNUMERIC)

要执行您的检查,只需执行以下操作(从with上面的块中继续):

    for cols, cols1 in zip(rows, rows1): #Use itertools.izip() in 2.x for efficiency.
        first = cols[4]
        second = cols1[4]

        if first < second:
            ...
        elif first == second:
            ...
        else: #first > second
            ...

请注意使用 zip 一次循环遍历两个文件。我们需要遍历文件,因为它们一次返回一行,每一行是每一列的数据列表。然后,您可以随心所欲地处理数据。我已经给出了一个比较第五个值的例子(注意索引4- python 被0索引 - 即第一个值是0,所以第五个是4)。

通过在遍历文件时执行所有这些操作,我们确保不必创建列表并临时存储数据——如果我们最终处理大文件,这很有用。

如果您稍后需要使用该数据,并且希望将其作为一个列表,您可以简单地创建两个rows对象列表,方法是list()csv.reader()s.

于 2012-06-20T13:44:57.360 回答
0

您需要注意几件事——首先,在读取文件后,您只存储了最后一行(在一个名为“cols”的变量中,不少于;)。像这样的循环:

lines1=f1.readlines()
lines2=f2.readlines()

for f1line,f2line in zip(lines1,lines2):
    #compare here

可能更合适。这会将两个文件的全部内容读入内存——当然有一些方法可以做到这一点,而无需一次读取那么多数据,但有时这是最简单的。 zip可能有点混乱,但基本上,它将 file1 的第一行与 file2 的第一行匹配,然后是两个文件的第二行,依此类推......

正如@Lattyware 的评论中所指出的,上述内容等同于:

for f1line,f2line in zip(f1,f2):
    #compare here

因为文件可以被迭代。在 python 2 中,它仍然会同时读取/存储两个文件,但在 python 3 中,它一次只会产生一行。最后,如果您不想将文件的所有内容存储在 python 2 中,您可以使用itertools.izip

import itertools
for f1line,f2line in itertools.izip(f1,f2):
    #compare here    

它的工作原理与它一样zip,只是它一次产生一个元素。这里的缺点是itertools.izip当您迁移到 python 3 时它会消失......但是,在这种情况下,2to3应该进行适当的转换。(有关更多信息,请参阅评论)。

至于比较,这在很大程度上取决于文件包含的内容。如果它包含数字,你可以这样做......

 for f1line,f2line in zip(lines1,lines2):
     row1=map(float,f1line.split())
     row2=map(float,f2line.split())
     #compare the 5th element
     if(row1[4]==row2[4]):
         #equal
     elif(row1[4]>row2[4]):
         ... 

如果你没有这个map(float,...)位,python 会做一个字符串比较。

python 还具有cmp 函数,如果您想现在比较并稍后使用比较结果,这可能很有用。

于 2012-06-20T13:50:42.410 回答
0

我会这样写:

import csv

file1 = csv.reader(open('name1'), delimiter='\t')
file2 = csv.reader(open('name2'), delimiter='\t')

for row1, row2 in zip(file1, file2):
    print cmp(row1[5], row2[5])

`

cmp 为 lt 返回 -1,为 eq 返回 0,或为 gt 返回 1

如果 row?[5] 是数字,那么...

print cmp(float(row1[5]), float(row2[5])) # or int, or any other dtype
于 2012-06-20T13:50:45.577 回答