In [1]:
import re, collections
In [2]:
def get_stats(vocab):
    pairs = collections.defaultdict(int)
    for word, freq in vocab.items():
        symbols = word.split()
        for i in range(len(symbols)-1):
            pairs[symbols[i], symbols[i+1]] += freq
    return pairs
In [3]:
def merge_vocab(pair, v_in):
    v_out = {}
    bigram = re.escape(' '.join(pair))
    # 后向否定,前向否定
    # bigram 后面有非空格,前面有非空格时不匹配
    p = re.compile(r'(?<!\S)' + bigram + r'(?!\S)')
    for word in v_in:
        w_out = p.sub(''.join(pair), word)
        v_out[w_out]  = v_in[word]
    return v_out
In [4]:
vocab = {
    'l o w </w>': 5,
    'l o w e s t </w>': 2,
    'n e w e r </w>': 6,
    'w i d e r </w>': 3,
    'n e w </w>':2
}
num_merges = 8
for i in range(num_merges):
    pairs = get_stats(vocab)
    best = max(pairs, key=pairs.get)
    vocab = merge_vocab(best, vocab)
    print("="*100)
    print(best)
    print(vocab)
====================================================================================================
('e', 'r')
{'l o w </w>': 5, 'l o w e s t </w>': 2, 'n e w er </w>': 6, 'w i d er </w>': 3, 'n e w </w>': 2}
====================================================================================================
('er', '</w>')
{'l o w </w>': 5, 'l o w e s t </w>': 2, 'n e w er</w>': 6, 'w i d er</w>': 3, 'n e w </w>': 2}
====================================================================================================
('n', 'e')
{'l o w </w>': 5, 'l o w e s t </w>': 2, 'ne w er</w>': 6, 'w i d er</w>': 3, 'ne w </w>': 2}
====================================================================================================
('ne', 'w')
{'l o w </w>': 5, 'l o w e s t </w>': 2, 'new er</w>': 6, 'w i d er</w>': 3, 'new </w>': 2}
====================================================================================================
('l', 'o')
{'lo w </w>': 5, 'lo w e s t </w>': 2, 'new er</w>': 6, 'w i d er</w>': 3, 'new </w>': 2}
====================================================================================================
('lo', 'w')
{'low </w>': 5, 'low e s t </w>': 2, 'new er</w>': 6, 'w i d er</w>': 3, 'new </w>': 2}
====================================================================================================
('new', 'er</w>')
{'low </w>': 5, 'low e s t </w>': 2, 'newer</w>': 6, 'w i d er</w>': 3, 'new </w>': 2}
====================================================================================================
('low', '</w>')
{'low</w>': 5, 'low e s t </w>': 2, 'newer</w>': 6, 'w i d er</w>': 3, 'new </w>': 2}
In [ ]: