[英]filtering based on more than one factor in python
我有一個包含3列的文本文件,並希望基於第3列進行過濾。 第一列具有ID,第三列具有字符序列。 在第一列中,每個id重復,但在第三列中,每個重復序列的長度不同。 在某些情況下,由於沒有序列,因此將其替換為"not present"
。 我只想對每個id重復一個序列,並且該序列必須是最長的序列。
例:
RPL17 ENST00000584364 not present
RPL17 ENST00000579248 CTGCGTTGCTCCGAGGGCCCAATCCTCCTGCCATCGCCGCCATCCTGGCTTCGGGGGCGCCGGCCT
RPL17 ENST00000580210 GCCCGTGTGGCTACTTCTGTGGAAGCAGTGCTGTAGTTACTGGAAGATAAAAGGGAAAGCAAGCCCTTGGTGGGGGAAA
RPL18 ENST00000551749 not present
RPL18 ENST00000546623 not present
RPL18 ENST00000552588 TCTCTCTTTCCGGACCTGGCCGAGCAGGAGGCGCCATC
RPL18 ENST00000547897 ACCTGGCCGAGCAGGAGGCGCCATC
RPL18 ENST00000550645 GCCGAGCAGGAGGCGCCATC
RPL18 ENST00000552705 not present
結果:
RPL17 ENST00000580210 GCCCGTGTGGCTACTTCTGTGGAAGCAGTGCTGTAGTTACTGGAAGATAAAAGGGAAAGCAAGCCCTTGGTGGGGGAAA
RPL18 ENST00000552588 TCTCTCTTTCCGGACCTGGCCGAGCAGGAGGCGCCATC
我寫了這段代碼,中間部分做了幾次修改,但並沒有達到我想要的效果。
with open("file.txt") as f, open('test.txt', 'w') as outfile:
for line in f:
line=line.split(",")
.
.
.
outfile.writerow(entry)
看起來輸入文件是列格式。 因此,首先我們必須弄清楚哪些字段位於哪些列中,然后可以使用dict來確保對於給定的ID僅保留最長的序列。
這是我想您要的內容:
# 00000000001111111111222222222233333333334
# 01234567890123456789012345678901234567890
# RPL17 ENST00000584364 not present
from collections import OrderedDict
sequences = OrderedDict()
with open("file.txt") as f, open('test.txt', 'w') as outfile:
for line in f:
st_id = line[:8].strip()
sequence = line[24:].strip()
value, _ = sequences.get(st_id, ('', None))
if not value or value == 'not present' or len(sequence) > len(value):
sequences[st_id] = (sequence, line)
for _, line in sequences.values():
outfile.write(line)
from collections import defaultdict
d = defaultdict(list)
with open('you_data.txt') as f, open('out.txt', 'w') as out:
s_line = [line.split(' ')for line in f]
for k, v in s_line:
d[k].append(v)
# {'RPL18': ['ENST00000551749 not present\n', 'ENST00000546623 not present\n', 'ENST00000552588 TCTCTCTTTCCGGACCTGGCCGAGCAGGAGGCGCCATC\n', 'ENST00000547897 ACCTGGCCGAGCAGGAGGCGCCATC\n', 'ENST00000550645 GCCGAGCAGGAGGCGCCATC\n', 'ENST00000552705 not present']
for k, v in d.items():
long_v = sorted(v, key=len, reverse=True)[0]
out.write(' '.join([k, long_v]))
出:
RPL18 ENST00000552588 TCTCTCTTTCCGGACCTGGCCGAGCAGGAGGCGCCATC
RPL17 ENST00000580210 GCCCGTGTGGCTACTTCTGTGGAAGCAGTGCTGTAGTTACTGGAAGATAAAAGGGAAAGCAAGCCCTTGGTGGGGGAAA
我很確定這是您想要的,盡管我敢肯定可以將其清理掉。 max
與itemgetter
結合將返回具有最長序列的行的元組,並且由於這樣做是針對每個id的,因此它應該正是您想要的,並且可能是最快的排序方法。
我用逗號作為分隔符,因為您說過數據是用逗號分隔的,盡管您顯示給我們的內容是用空格分隔的,但是您可以將其更改為任何分隔符。 我用逗號分隔的輸出也可以,但是您也可以將其更改為您應該使用的輸出分隔符。
更新:上一行最后一行實際上並沒有正確設置行,並且在寫入行后我沒有將lines
重置為空,因此它無法正常工作。 另外,由於我會重復編寫代碼,因此將make_row
您需求的重要行放入函數( make_row
)中。
我已經用逗號分隔數據進行了測試,並且效果很好。
from operator import itemgetter
import csv
def make_row(lines):
return map(str.strip, max(lines, key=itemgetter(2)))
with open("file.txt") as f, open('test.txt', 'w') as outfile:
output = csv.writer(outfile)
id = ''
lines = []
for line in f:
current_line = line.split(",")
if current_line[0] != id and lines != []:
output.writerow(make_row(lines))
lines=[]
id = current_line[0]
if current_line[2].strip() != 'not present':
lines.append(current_line)
output.writerow(make_row(lines)) # to catch the last row
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.