2017-03-03 6 views
0

문자열 목록이 큰 문자열에 가장 잘 맞도록 색인을 제공하는 함수가 필요합니다. 예를 들어문자열에 대한 문자열 목록 정렬에 대한 색인

:

text = 'Kir4.3 is a inwardly-rectifying potassium channel. Dextran-sulfate is useful in glucose-mediated channels.' 

문자열 목록 : : 문자열을 감안할 때

tok = ['Kir4.3', 'is', 'a', 'inwardly-rectifying', 'potassium', 'channel','.', 'Dextran-sulfate', 'is', 'useful' ,'in', 'glucose','-', 'mediated', 'channels','.'] 

이 기능은 산출하기 위해 만들 수 있습니다

indices = [7, 10, 12, 32, 42, 49, 51, 67, 70, 77, 80, 87, 88, 97, 105] 

설명 된대로 기능이 작동하는지

from re import split 
from numpy import vstack, zeros 
import numpy as np 

# I need a function which takes a string and the tokenized list 
# and returns the indices for which the tokens were split at 
def index_of_split(text_str, list_of_strings): 
    #????? 
    return indices 

# The text string, string token list, and character binary annotations 
# are all given 
text = 'Kir4.3 is a inwardly-rectifying potassium channel. Dextran-sulfate is useful in glucose-mediated channels.' 
tok = ['Kir4.3', 'is', 'a', 'inwardly-rectifying', 'potassium', 'channel','.', 'Dextran-sulfate', 'is', 'useful' ,'in', 'glucose','-', 'mediated', 'channels','.'] 
# (This binary array labels the following terms ['Kir4.3', 'Dextran-sulfate', 'glucose']) 
bin_ann = [1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] 

# Here we would apply our function 
indices = index_of_split(text, tok) 
# This list is the desired output 
#indices = [7, 10, 12, 32, 42, 49, 51, 67, 70, 77, 80, 87, 88, 97, 105] 

# We could now split the binary array based on these indices 
bin_ann_toked = np.split(bin_ann, indices) 
# and combine with the tokenized list 
tokenized_strings = np.vstack((tok, bin_ann_toked)).T 

# Then we can remove the trailing zeros, 
# which are likely caused from spaces, 
# or other non tokenized text 
for i, el in enumerate(tokenized_strings): 
    tokenized_strings[i][1] = el[1][:len(el[0])] 
print(tokenized_strings) 

주어진 다음과 같은 출력을 제공 할 것이다 : 여기


내가 점을 설명하기 위해 만든 스크립트입니다

[['Kir4.3' array([1, 1, 1, 1, 1, 1])] 
['is' array([0, 0])] 
['a' array([0])] 
['inwardly-rectifying' 
    array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])] 
['potassium' array([0, 0, 0, 0, 0, 0, 0, 0, 0])] 
['channel' array([0, 0, 0, 0, 0, 0, 0])] 
['.' array([0])] 
['Dextran-sulfate' array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])] 
['is' array([0, 0])] 
['useful' array([0, 0, 0, 0, 0, 0])] 
['in' array([0, 0])] 
['glucose' array([1, 1, 1, 1, 1, 1, 1])] 
['-' array([0])] 
['mediated' array([0, 0, 0, 0, 0, 0, 0, 0])] 
['channels' array([0, 0, 0, 0, 0, 0, 0, 0])] 
['.' array([0])]] 
+0

'포도당', '-', '중재'가없는 경우 왜 '덱스 트란 - 황산염'이 하이픈을 유지합니까? 이러한 상황이 언제 발생하는지 알지 못하면 함수를 하드 코딩해야합니다. –

답변

1
text = 'Kir4.3 is a inwardly-rectifying potassium channel. Dextran-sulfate is useful in glucose-mediated channels.' 

tok = ['Kir4.3', 'is', 'a', 'inwardly-rectifying', 'potassium', 'channel','.', 'Dextran-sulfate', 'is', 'useful' ,'in', 'glucose','-', 'mediated', 'channels','.'] 


ind = [0] 
for i,substring in enumerate(tok): 
    ind.append(text.find(substring,ind[i],len(text))) 

print ind[2:] 

의 결과는

[7, 10, 12, 32, 42, 49, 51, 67, 70, 77, 80, 87, 88, 97, 105] 
+0

도움을 주셔서 감사합니다.이 문제에 대한 매우 피닉스적이고 간단한 해결책입니다. 그러나 무차별 방식을 사용하는 솔루션은 매우 흥미롭고 목록에있는 문자열의 구조가 덜한 사람을 찾아 볼 가치가 있습니다. – chase

1

다음은 무차별 방식입니다. 모든 단어 일치를 찾아서 모든 조합에 점수를 매기는 점수를 얻습니다.

import numpy as np 
from scipy import signal 

def pen(l, r): 
    return (r-l)*(1-4*(l>r)) 

class template: 
    def __init__(self, template): 
     self.template = np.frombuffer(template.encode('utf32'), offset=4, 
             dtype=np.int32) 
     self.normalise = self.template*self.template 
    def match(self, other): 
     other = np.frombuffer(other.encode('utf32'), offset=4, dtype=np.int32)[::-1] 
     m = signal.convolve(self.template, other, 'valid') 
     t = signal.convolve(self.normalise, np.ones_like(other), 'valid') 
     delta = np.absolute(m - t) 
     md = min(delta) 
     return np.where(delta == md)[0], md 
    def brute(self, tok): 
     ms, md = self.match(tok[0]) 
     matches = [[-md, (tok[0], s, s+len(tok[0]))] for s in ms] 
     for t in tok[1:]: 
      ms, md = self.match(t) 
      matches = [[mo[0] - md - pen(mo[-1][-1], mn)] + mo[1:] 
         + [(t, mn, mn + len(t))] for mn in ms for mo in matches] 
     return sorted(matches, key=lambda x: x[0]) 
#   for t in tok[1:]: 
#    ms, md = self.match(t) 
#    matches = [[mo[0] - md] + mo[1:] 
#       + [(t, mn, mn + len(t))] for mn in ms for mo in matches 
#       if mo[-1][-1] <= mn] 
#   return sorted(matches, key=lambda x: x[0]) 

text = 'Kir4.3 is a inwardly-rectifying potassium channel. Dextran-sulfate is useful in glucose-mediated channels.' 
tok = ['Kir4.3', 'is', 'a', 'inwardly-rectifying', 'potassium', 'channel','.', 'Dextran-sulfate', 'is', 'useful' ,'in', 'glucose','-', 'mediated', 'channels','.'] 
tx = template(text) 
matches = tx.brute(tok) 
print(matches[-1]) 

# [-11, ('Kir4.3', 0, 6), ('is', 7, 9), ('a', 10, 11), ('inwardly-rectifying', 12, 31), ('potassium', 32, 41), ('channel', 42, 49), ('.', 49, 50), ('Dextran-sulfate', 51, 66), ('is', 67, 69), ('useful', 70, 76), ('in', 77, 79), ('glucose', 80, 87), ('-', 87, 88), ('mediated', 88, 96), ('channels', 97, 105), ('.', 105, 106)] 
+0

이것은 매우 유용하지만, 아직 어떤 일이 벌어지고 있는지 완전히 이해하지 못합니다. 나는 경기의 결과가 매우 큰 것으로 나타났습니다. 나는이 작업을 수십만 번 수행하게 될 것이기 때문에 내 희망은 오히려 빠를 것입니다. 그것들이 같은 순서로 존재한다는 것을 안다는 것이 문제가 되는가? 즉, 시퀀스가 ​​비슷하게 진행되어야합니다. 'tok'의 결합 된 텍스트와 'text' 문자열 사이에 몇 개의 문자가 누락되어 있습니다. – chase

+0

@chase 물론, 하나의 결과 만 보여주는 낙관적 인 버전 (주석 처리 된 버전)을 추가 했으므로 실제 문제에 얼마나 많은 유연성을 필요로하는지 실험해야합니다. –

+0

정말 고마워요! 이것은 정말 놀라운 알고리즘입니다. 앞으로는 DNA 정렬 알고리즘 등을 이해하기 위해 사용할 것입니다. 그러나이 특정 프로젝트의 경우 간단한 'text.find()'솔루션이 작동하며 약 50-100 배 빠릅니다. 하나의 일치 솔루션. 무차별 공격 모두 일치 : ~ 0.15 초 무차별 대입 1 대 ~ ~ 0.001 초 text.find : ~ 0.00001 초 (모든 무차별 대입보다 ~ 10,000x 빠름) – chase