加入收藏 | 设为首页 | 会员中心 | 我要投稿 阜阳站长网 (https://www.0558zz.com/)- 科技、建站、内容创作、云计算、网络安全!
当前位置: 首页 > 编程开发 > Python > 正文

如何在Python中有效地编码bigram计数和替换的字节对?

发布时间:2021-03-30 17:55:07 所属栏目:Python 来源:互联网
导读:在 Byte Pair Encoding算法中,有一个替换步骤,它将由空格分隔的字符串更改为bigrams. 即,给出一个str元组列表: [(t, h, i, s, ue000), (c, o, r, p, u, s, ue000), (i, n, ue000), (t, x, t, f, i, l, e

在 Byte Pair Encoding算法中,有一个替换步骤,它将由空格分隔的字符串更改为bigrams.

即,给出一个str元组列表:

[('t','h','i','s','ue000'),('c','o','r','p','u',('i','n',('t','x','t','f','l','e',('s','c',('b','a',('a','d',('f',('.','ue000')]

和一个字符串元组:(‘我’,’s’)

如何处理列表,使其迭代所有元组键,并用(‘is’)替换(‘i’,’s’),即输出Counter看起来像这样:

[('t','is',('is','ue000')]

我试过这个:

>>> cin
[('t','ue000')]
>>> [tuple(' '.join(i).replace(' '.join(qtuple),''.join(qtuple)).split()) for i in cin]
[('t','ue000')]

但是有没有比循环遍历每个单词更有效的方法,然后将它们更改为字符串以进行替换并再次拆分它们然后将它们转换回元组?

正则表达式替换会更快吗?有没有办法处理元组列表而不处理字符串?

我试过这个,似乎用str.replace替换字符串不是问题.它真的在计算双子座并提取它们:

import io
from collections import Counter

import time

infile = 'big.txt' # comes from norvig.com/big.txt

n = 2
with io.open(infile,encoding='utf8') as fin:
    text = fin.read().lower().replace(u' ',u"uE000")
    for j in range(1,6400):
        unused_char = unichr(ord(u'uE001') + j)

        start = time.time()
        char_bigrams = zip(*[text[i:] for i in range(n)])
        bigram_time = time.time() - start

        start = time.time()
        most_freq_bigram = Counter(filter(lambda x: u"uE000" not in x and 'n' not in x,char_bigrams)).most_common(1)[0][0]
        max_time = time.time() - start

        start = time.time()
        text = text.replace(''.join(most_freq_bigram),unused_char)
        replace_time = time.time() - start
        print j,''.join(most_freq_bigram),most_freq_bigram,bigram_time,max_time,replace_time
    print text

这是在norvig.com/big.txt测试的

[OUT]:

1 th (u't',u'h') 0.896255016327 3.28389787674 0.0253069400787
2 e (u'ue002',u'e') 1.47053217888 3.16544914246 0.0280749797821
3 in (u'i',u'n') 1.13404297829 3.10529899597 0.0245559215546
4 an (u'a',u'n') 1.20013689995 3.63801002502 0.0242891311646
5 er (u'e',u'r') 1.41387891769 3.13376092911 0.0237591266632
6 on (u'o',u'n') 1.22826981544 3.06997895241 0.0227301120758
7 re (u'r',u'e') 1.21916294098 2.97599196434 0.0238041877747
8 at (u'a',u't') 1.14608097076 2.97988891602 0.0226521492004
9 en (u'e',u'n') 1.20747494698 2.88649988174 0.019054889679
10 ed (u'e',u'd') 1.16296696663 2.8995718956 0.0198271274567
11 is (u'i',u's') 1.17692494392 3.02292394638 0.0228500366211
12 d (u'ue005',u'd') 1.13779211044 2.85169506073 0.0229239463806

我已经尝试过scikit-learn CountVectorizer,我似乎没有使用zip那么快,参见Fast/Optimize N-gram implementations in python

另外,如果没有它们在Counter步骤中进行过滤操作,则需要更长的时间.计数器操作每次迭代需要3秒=(

如何优化此操作?

Counter(filter(lambda x: u"uE000" not in x and 'n' not in x,char_bigrams)).most_common(1)[0][0]

解决方法

如果你将字符串元组保持为长度2,你可以像这样使用reduce:
def cons_2(word_list,t):
    j = ''.join(t)
    f = lambda acc,e: acc[:-1] + (j,) if (acc[-1] == t[0] and e == t[1]) else acc + (e,)
    return [reduce(f,i[1:],(i[0],)) for i in word_list]

print cons_2(cin,'s'))

不涉及替换,f应用于每个元素i,cin的值不会改变,而是生成并返回新的数组.

细节:

> reduce对每个数组元素i应用f并将值返回到累加器acc.
>减少参数:

> f:要应用的功能.
> i [1:]:数组迭代所有元素但第一个.
>(i [0],):累加器的初始值,它是一个元组,带有输入元组i的第一个值.

> f:是一个lambda函数,累加器acc和当前元素e作为输入:

>如果累加器的最后一个元素等于字符串元组的第一个元素,并且当前元素e等于字符串元组的第二个元素,则返回元组:acc [-1](j,)else继续正常连接:acc(e,).

对于字符串元组> 2这个想法是一样的,但我们必须管理元组的长度l.

def cons_n(word_list,t):
    l = len(t)
    j = ''.join(t)
    f = lambda acc,e: acc[:-l] + (j,e,) if acc[-l:] == t or acc[:l] == t else acc + (e,i[l:],(i[:l])) for i in word_list]

print cons_n(cin,'s'))

这应该适用于n长度的字符串元组.

细节:

>与上面相同的过程,但使用l:reduce将f应用于其余元素i [l:],并且累加器的初始值是具有前l个元素的元组:(i [:l]).
>向后和向前检查l元素是否等于字符串元组t,如果为true,则添加元组:acc [: – l](j,).

这是一种功能方法,没有数据被修改但是生成,因此同时拥有多个进程应该是安全的(理论上,我不是Python解释器的专家).

如果上面的代码对于没有进入函数式编程的人来说太奇怪了,这是另一种方法:

def cons_n_iter(tuple_list,tuple_seq):
     jnt = ''.join(tuple_seq)
     lnt = len(tuple_seq)
     res = []
     for word in tuple_list:
         acc = (word[:lnt])
         for letter in word[lnt:]:
             if acc[-lnt:] == tuple_seq or acc[:lnt] == tuple_seq:
                 acc = acc[:-lnt] + (jnt,letter,)
             else:
                 acc += (letter,)
         res += (acc,)
     return res

print cons_n_iter(cin,'s'))

逻辑与功能方法相同,累加器使用相同.在这种情况下,res累加器是显式的,因为在上面的例子中,reduce正在处理它.

(编辑:阜阳站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读