случайный массив масок python с некоторым правилом: нет двух (или не слишком много) смежных ложных значений

#python #random #mask

Вопрос:

Я хочу замаскировать часть слов в тексте

 ['First', 'Citizen:', 'Before', 'we', 'proceed', 'any', 'further,', 'hear', 'me', 'speak.', 'All:', 'Speak,', 'speak.', 'First', 'Citizen:', 'You', 'are', 'all', 'resolved', 'rather', 'to', 'die', 'than', 'to', 'famish?', 'All:', 'Resolved.', 'resolved.', 'First', 'Citizen:', 'First,', 'you', 'know', 'Caius', 'Marcius', 'is', 'chief', 'enemy', 'to', 'the', 'people.']
 

используя маску Python. Я реализую случайную маску Python

 mask = np.ones(LEN, dtype=int)
maskrate=0.2 # percentage of masked words <1
nbmask=int(np.floor(LEN*maskrate))
mask[-nbmask:] = 0
np.random.shuffle(mask)
mask = mask.astype(bool)
print (mask )

masked_words=[]

for a,b in zip(words, mask):
    print (a)
    if b:
        masked_words.append(a)
    else:
        masked_words.append('_')
 

Однако я хотел бы избежать того, чтобы слишком много слов подряд были замаскированы. Если это возможно численно, не следует маскировать два смежных слова. Например, что здесь происходит

 _ Citizen: _ we proceed _ further, _ me speak. All: _ speak. First Citizen: You are all resolved rather to die than _ _ All: _ resolved. First Citizen: First, you know Caius Marcius is chief enemy to the people.
 

Я бы хотел, чтобы случайность была немного более равномерно распределена …

Комментарии:

1. поскольку создание маски сразу не… предсказуемо, вы можете попытаться создать маску рекурсивно, по крайней мере, вы могли бы контролировать смежность замаскированных слов

Ответ №1:

Чтобы иметь больше контроля над случайностью значений в маске, я использую чистый Python, обычно numpy не так гибок. Рекомендуется рекурсивный подход.

 import random 

def gen_mask(n_w, mask_rate=.2):
    if mask_rate >= .5: raise Exception('mask rate always smaller than .5, thanks.')

    n_o = int(n_w * mask_rate)  # amount of words to be shaded words
    o_indexes = []
    while True:
        if len(o_indexes) == n_o:
            break
        r = random.randrange(0, n_w - 1)

        if r not in o_indexes:
            # adjacency condition
            if not r - 1 in o_indexes and not r   1 in o_indexes:
                o_indexes  = [r]
                o_indeces.sort()

    mask = [False] * n_w
    for o in o_indexes:
        mask[o] = True
    return mask


words = ['First', 'Citizen:', 'Before', 'we', 'proceed', 'any', 'further,', 'hear', 'me', 'speak.', 'All:', 'Speak,', 'speak.', 'First', 'Citizen:', 'You', 'are', 'all', 'resolved', 'rather', 'to', 'die', 'than', 'to', 'famish?', 'All:', 'Resolved.', 'resolved.', 'First', 'Citizen:', 'First,', 'you', 'know', 'Caius', 'Marcius', 'is', 'chief', 'enemy', 'to', 'the', 'people.']

n_w = len(words)
m_rate = .2
n_o = int(n_w*m_rate)

for i in range(2, 5):
    random.seed(10**i)
    mask = gen_mask(n_w, mask_rate=.2)
    print(' '.join(['_' if m else w for w, m in zip(words, mask)]))
 

Выход

 First Citizen: Before we proceed any further, _ me _ All: _ speak. First Citizen: You are all resolved rather to die _ to famish? _ Resolved. _ First _ First, you _ Caius Marcius is chief enemy to the people.
First Citizen: Before we _ any _ hear me speak. _ Speak, speak. First Citizen: You are all resolved rather to die _ to famish? _ Resolved. _ First _ First, you know Caius _ is chief enemy to the people.
_ Citizen: _ we proceed any further, _ me speak. All: _ speak. First Citizen: You _ all resolved _ to die than to famish? All: Resolved. resolved. First Citizen: First, you _ Caius Marcius is _ enemy to the people.
 

Замечание Ясно, что mask_rate значение никогда не должно быть равно или больше 0,5 (из-за условия смежности). Если равно 0,5, это просто «чередующаяся» маска

Комментарии:

1. Спасибо, однако это на самом деле не контролирует и не соблюдает %True: если не повезет, может быть намного больше пробелов, чем ожидалось…

2. количество пробелов зависит от количества слов и от mask_rate. Если сохранить эти параметры фиксированными, то сгенерированная маска всегда будет иметь постоянное количество пробелов, но в разных положениях и никогда не будет смежной. Я пропустил smt в вопросе или у вас есть пример, где он терпит неудачу?