[英]Comparing items in large list - finding items differing in 1 letter by length - Python
我正在尋找解決我一直困在Python中的問題。 我有一個文件,只有一欄,其中包含大約。 6,000行。 對於每一行,每個項目都是唯一的(已過濾此文件以刪除40,000行文件中的重復項)。 每行中的項目的長度各不相同,其中某些項目的長度與其他項目的長度相等。
單行示例:
IGHV3-30/33rn-IGHJ4-CARDPSLSSMITFGGVIVTRGYFDYW
或更多帶有制表符的示例,其中制表符在第三個“-”之后(不同的第一部分)分開:
IGHV3-23-IGHJ4 CAKDRGYTGYGVYFDYW
IGHV4-39-IGHJ4 CARHDILTGYSYYFDYW
IGHV3-23-IGHJ3 CAKSGGWYLSDAFDIW
IGHV4-39-IGHJ4 CARTGFGELGFDYW
IGHV1-2-IGHJ2 CARDSDYDWYFDLW
IGHV1-8-IGHJ3 CARGQTYYDILTGPSDAFDIW
IGHV4-39-IGHJ5 CARSTGDWFDPW
IGHV3-9-IGHJ3 CANVPIYSSSYDAFDIW
IGHV3-23-IGHJ4 CAKDWELYYFDYW
IGHV3-23-IGHJ4 CAKDRGYTGFGVYFDYW
IGHV4-39-IGHJ4 CARHLGYNNSWYPFDYW
IGHV1-2-IGHJ4 CAREGYNWNDEGRFDYW
IGHV3-23-IGHJ3 CAKSSGWYLSDAFDIW
IGHV4-39-IGHJ4 CARYLGYNSNWYPFDYW
IGHV3-23-IGHJ6 CAKEGCSSGCPYYYYGMDVW
IGHV3-23-IGHJ3 CAKWGPDAFDIW
IGHV3-11-IGHJ CATSGGSP
IGHV3-11-IGHJ4 CARDGDGYNDYW
IGHV1-2-IGHJ4 CARRIGYSSGSEDYW
IGHV1-2-IGHJ4 CARDIAVPGHGDYW
IGHV6-1-IGHJ4 CASGGAVPGYYFDYW
在第一列中,有一些不同的項目。 在第二列中,每個項目都是唯一的。 第一列項目需要匹配,然后第二列項目需要以最小不匹配2進行排序。理想情況下,這可以與Levenshtein模塊一起使用,因為我可以放入最大值,但是我需要兩個字符串。 有沒有一種方法可以在一個列表中的每個項目上使用Levenshtein?
我需要做的是打開此文件(我認為先按長度排序可能會有所幫助,但是我不確定)。 在將所有項目按長度分組之后,我需要將這些項目分類為相差1個字符的組(第三個“-”之前的字符串必須相同,其中“-”之后的字符串僅應相差1個字符) 。)
我認為我遇到的問題是關於生成適當的for循環以遍歷項目長度的問題。
到目前為止,我擁有的代碼:
import sys
import os
import Levenshtein
inp = sys.argv[1] # Input file containing single column of items
with open(inp, "r") as f1:
vj = [line.strip() for line in f1]
lengths = []
for k in vj:
i = len(k)
lengths.append(i)
lengths_sort = sorted(lengths, reverse = True)
uniq_len = []
for i in lengths_sort:
if i not in uniq_len:
uniq_len.append(i)
print uniq_len #For QC purposes
def get_new_list(strings, counts, outlist=[]):
for s in strings:
if len(s) == counts[0]:
outlist.append(s)
return outlist
new_vj = get_new_list(vj, uniq_len, outlist=[])
print new_vj
ham = Levenshtein.hamming(new_vj[0], new_vj[1])
print ham
所以我一直在尋找的輸出是好的,但是還沒有完成:
[46, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18]
46
['IGHV3-30/33rn-IGHJ4-CAKDPSLSSMITFGGVIVTRGYFDYW', 'IGHV3-30/33rn-IGHJ4-CARDPSLSSMITFGGVIVTRGYFDYW']
1
有兩個長度為46的項目(巧合的是,第三個“-”之前的字符串是相同的;很好),它們在兩個字符串之間僅相差一個字符。
我的麻煩是,1.如何遍歷uniq_len列表中的數字作為“字符串”列表中匹配長度的輸入(請參見代碼中的函數)。 2.我想為每個不同的長度創建一個新列表。 3.如果每個新列表中都有多個項目,則所有項目的差異僅相差1個字符。
注意:“-”是使用UNIX paste -d-命令創建的,具有3個文件(每個文件包含1列)來創建此文件。 將這些文件與\\ t一起作為分隔符創建3列會更容易嗎?
因此,打開文件,刪除行,然后可以將第一列,第二列匹配,看看第三列是否相差一個或多個字符?
感謝所有幫助。
更新:修改為處理可變數量的“ id”子字段,並將結果打印為單個字符串。 請注意,在輸入的末尾添加了幾個測試用例,以使其中一些具有不同數量的前導字段構成id(即2而不是3)。
我還重命名了num_mismatches()
函數hamming_distance()
因為它就是這樣。
使用以下輸入:
IGHV3-23-IGHJ4-CAKDRGYTGYGVYFDYW
IGHV4-39-IGHJ4-CARHDILTGYSYYFDYW
IGHV3-23-IGHJ3-CAKSGGWYLSDAFDIW
IGHV4-39-IGHJ4-CARTGFGELGFDYW
IGHV1-2-IGHJ2-CARDSDYDWYFDLW
IGHV1-8-IGHJ3-CARGQTYYDILTGPSDAFDIW
IGHV4-39-IGHJ5-CARSTGDWFDPW
IGHV3-9-IGHJ3-CANVPIYSSSYDAFDIW
IGHV3-23-IGHJ4-CAKDWELYYFDYW
IGHV3-23-IGHJ4-CAKDRGYTGFGVYFDYW
IGHV4-39-IGHJ4-CARHLGYNNSWYPFDYW
IGHV1-2-IGHJ4-CAREGYNWNDEGRFDYW
IGHV3-23-IGHJ3-CAKSSGWYLSDAFDIW
IGHV4-39-IGHJ4-CARYLGYNSNWYPFDYW
IGHV3-23-IGHJ6-CAKEGCSSGCPYYYYGMDVW
IGHV3-23-IGHJ3-CAKWGPDAFDIW
IGHV3-11-IGHJ-CATSGGSP
IGHV3-11-IGHJ4-CARDGDGYNDYW
IGHV1-2-IGHJ4-CARRIGYSSGSEDYW
IGHV1-2-IGHJ4-CARDIAVPGHGDYW
IGHV6-1-IGHJ4-CASGGAVPGYYFDYW
IGHV1-2-CAREGYNWNDEGRFDYW
IGHV4-39-CARSTGDWFDPW
IGHV1-2-CARDSDYDWYFDLW
和這個腳本:
from collections import defaultdict
from itertools import izip, tee
import os
import sys
# http://en.wikipedia.org/wiki/Hamming_distance#Algorithm_example
def hamming_distance(s1, s2):
""" Count number of mismatched characters in equal length strings. """
if not isinstance(s1, basestring): raise ValueError('s1 is not a string')
if not isinstance(s2, basestring): raise ValueError('s2 is not a string')
if len(s1) != len(s2): raise ValueError('string lengths do not match')
return sum(a != b for a, b in izip(s1, s2))
def pairwise(iterable): # itertools recipe
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return izip(a, b)
inp = sys.argv[1] # Input file
unique = defaultdict(list)
with open(inp, 'rb') as file:
for fields in (line.strip().split('-') for line in file):
id = '-'.join(fields[:-1]) # recombine all but last field into an id
unique[id].append(fields[-1]) # accumulate ending fields with same id
for id in sorted(unique):
final_fields = unique[id]
final_fields.sort(key=lambda field: len(field)) # sort by length
print id + ':' + '-'.join(final_fields)
if len(final_fields) > 1: # at least one pair to compare for mismatches?
for a, b in pairwise(final_fields):
if len(a) == len(b) and hamming_distance(a, b) < 2:
print ' {!r} and {!r} differ by < 2 characters'.format(a, b)
輸出:
IGHV1-2:CARDSDYDWYFDLW-CAREGYNWNDEGRFDYW
IGHV1-2-IGHJ2:CARDSDYDWYFDLW
IGHV1-2-IGHJ4:CARDIAVPGHGDYW-CARRIGYSSGSEDYW-CAREGYNWNDEGRFDYW
IGHV1-8-IGHJ3:CARGQTYYDILTGPSDAFDIW
IGHV3-11-IGHJ:CATSGGSP
IGHV3-11-IGHJ4:CARDGDGYNDYW
IGHV3-23-IGHJ3:CAKWGPDAFDIW-CAKSGGWYLSDAFDIW-CAKSSGWYLSDAFDIW
'CAKSGGWYLSDAFDIW' and 'CAKSSGWYLSDAFDIW' differ by < 2 characters
IGHV3-23-IGHJ4:CAKDWELYYFDYW-CAKDRGYTGYGVYFDYW-CAKDRGYTGFGVYFDYW
'CAKDRGYTGYGVYFDYW' and 'CAKDRGYTGFGVYFDYW' differ by < 2 characters
IGHV3-23-IGHJ6:CAKEGCSSGCPYYYYGMDVW
IGHV3-9-IGHJ3:CANVPIYSSSYDAFDIW
IGHV4-39:CARSTGDWFDPW
IGHV4-39-IGHJ4:CARTGFGELGFDYW-CARHDILTGYSYYFDYW-CARHLGYNNSWYPFDYW-CARYLGYNSNWYPFDYW
IGHV4-39-IGHJ5:CARSTGDWFDPW
IGHV6-1-IGHJ4:CASGGAVPGYYFDYW
希望此更新對您有所幫助...
假設您要按A)列的長度,B)該列的Levenshtein距離與上方或下方的col進行排序。
問題立即表明,levenshtein距離在2個相對物體之間。 即, Levenshtein(a, b)
不像len(a)
這樣的單聲道屬性。 levenshtein距離的值隨着列表中各行相對於彼此位置的變化而變化。
Python 2.X支持較早的cmp
vs key
參數進行排序。 這是低效的,因為每次進行排序時都必須重新評估它。 但是,Levenshtein排序相對於條目上方和下方的項目。
例如,讓我們對示例數據進行矩陣處理:
txt='''\
IGHV3-23-IGHJ4 CAKDRGYTGYGVYFDYW
IGHV4-39-IGHJ4 CARHDILTGYSYYFDYW
IGHV3-23-IGHJ3 CAKSGGWYLSDAFDIW
IGHV4-39-IGHJ4 CARTGFGELGFDYW
IGHV1-2-IGHJ2 CARDSDYDWYFDLW
IGHV1-8-IGHJ3 CARGQTYYDILTGPSDAFDIW
IGHV4-39-IGHJ5 CARSTGDWFDPW
IGHV3-9-IGHJ3 CANVPIYSSSYDAFDIW
IGHV3-23-IGHJ4 CAKDWELYYFDYW
IGHV3-23-IGHJ4 CAKDRGYTGFGVYFDYW
IGHV4-39-IGHJ4 CARHLGYNNSWYPFDYW
IGHV1-2-IGHJ4 CAREGYNWNDEGRFDYW
IGHV3-23-IGHJ3 CAKSSGWYLSDAFDIW
IGHV4-39-IGHJ4 CARYLGYNSNWYPFDYW
IGHV3-23-IGHJ6 CAKEGCSSGCPYYYYGMDVW
IGHV3-23-IGHJ3 CAKWGPDAFDIW
IGHV3-11-IGHJ CATSGGSP
IGHV3-11-IGHJ4 CARDGDGYNDYW
IGHV1-2-IGHJ4 CARRIGYSSGSEDYW
IGHV1-2-IGHJ4 CARDIAVPGHGDYW
IGHV6-1-IGHJ4 CASGGAVPGYYFDYW'''
data=[line.split() for line in txt.splitlines()]
# [['IGHV3-23-IGHJ4', 'CAKDRGYTGYGVYFDYW'], ['IGHV4-39-IGHJ4', 'CARHDILTGYSYYFDYW'], ['IGHV3-23-IGHJ3', 'CAKSGGWYLSDAFDIW'], ['IGHV4-39-IGHJ4', 'CARTGFGELGFDYW'], ['IGHV1-2-IGHJ2', 'CARDSDYDWYFDLW'], ['IGHV1-8-IGHJ3', 'CARGQTYYDILTGPSDAFDIW'], ['IGHV4-39-IGHJ5', 'CARSTGDWFDPW'], ['IGHV3-9-IGHJ3', 'CANVPIYSSSYDAFDIW'], ['IGHV3-23-IGHJ4', 'CAKDWELYYFDYW'], ['IGHV3-23-IGHJ4', 'CAKDRGYTGFGVYFDYW'], ['IGHV4-39-IGHJ4', 'CARHLGYNNSWYPFDYW'], ['IGHV1-2-IGHJ4', 'CAREGYNWNDEGRFDYW'], ['IGHV3-23-IGHJ3', 'CAKSSGWYLSDAFDIW'], ['IGHV4-39-IGHJ4', 'CARYLGYNSNWYPFDYW'], ['IGHV3-23-IGHJ6', 'CAKEGCSSGCPYYYYGMDVW'], ['IGHV3-23-IGHJ3', 'CAKWGPDAFDIW'], ['IGHV3-11-IGHJ', 'CATSGGSP'], ['IGHV3-11-IGHJ4', 'CARDGDGYNDYW'], ['IGHV1-2-IGHJ4', 'CARRIGYSSGSEDYW'], ['IGHV1-2-IGHJ4', 'CARDIAVPGHGDYW'], ['IGHV6-1-IGHJ4', 'CASGGAVPGYYFDYW']]
現在將這些行按row[1]
長度排序:
data.sort(key=lambda l: len(l[1]))
現在根據條目的levenshtein距離進行排序。 請注意,由於levenstein基於兩個值,因此您需要使用cmp
:
data.sort(cmp=levenshtein)
# [['IGHV3-11-IGHJ', 'CATSGGSP'], ['IGHV4-39-IGHJ5', 'CARSTGDWFDPW'], ['IGHV3-23-IGHJ3', 'CAKWGPDAFDIW'], ['IGHV3-11-IGHJ4', 'CARDGDGYNDYW'], ['IGHV3-23-IGHJ4', 'CAKDWELYYFDYW'], ['IGHV4-39-IGHJ4', 'CARTGFGELGFDYW'], ['IGHV1-2-IGHJ2', 'CARDSDYDWYFDLW'], ['IGHV1-2-IGHJ4', 'CARDIAVPGHGDYW'], ['IGHV1-2-IGHJ4', 'CARRIGYSSGSEDYW'], ['IGHV6-1-IGHJ4', 'CASGGAVPGYYFDYW'], ['IGHV3-23-IGHJ3', 'CAKSGGWYLSDAFDIW'], ['IGHV3-23-IGHJ3', 'CAKSSGWYLSDAFDIW'], ['IGHV3-23-IGHJ4', 'CAKDRGYTGYGVYFDYW'], ['IGHV4-39-IGHJ4', 'CARHDILTGYSYYFDYW'], ['IGHV3-9-IGHJ3', 'CANVPIYSSSYDAFDIW'], ['IGHV3-23-IGHJ4', 'CAKDRGYTGFGVYFDYW'], ['IGHV4-39-IGHJ4', 'CARHLGYNNSWYPFDYW'], ['IGHV1-2-IGHJ4', 'CAREGYNWNDEGRFDYW'], ['IGHV4-39-IGHJ4', 'CARYLGYNSNWYPFDYW'], ['IGHV3-23-IGHJ6', 'CAKEGCSSGCPYYYYGMDVW'], ['IGHV1-8-IGHJ3', 'CARGQTYYDILTGPSDAFDIW']]
如果要將兩個元素排序cmp
更改為鍵類型(對於不支持cmp的Python 3),則可以生成比較對象:
def cmp_to_key(mycmp):
'Convert a cmp= function into a key= function'
class K(object):
def __init__(self, obj, *args):
self.obj = obj
def __lt__(self, other):
return mycmp(self.obj, other.obj) < 0
def __gt__(self, other):
return mycmp(self.obj, other.obj) > 0
def __eq__(self, other):
return mycmp(self.obj, other.obj) == 0
def __le__(self, other):
return mycmp(self.obj, other.obj) <= 0
def __ge__(self, other):
return mycmp(self.obj, other.obj) >= 0
def __ne__(self, other):
return mycmp(self.obj, other.obj) != 0
return K
您使用data.sort(key=cmp_to_key(levenshtein))
排序
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.