Наивным, O(n^2)
решением было бы перебрать все кортежи во всех списках (значениях словаря) случайно сгенерированных данных и проверить, соответствуют ли эти кортежи любому из кортежей в любом из списков золота. данные. Это было бы неэффективно для большого набора данных, так как в худшем случае, когда нет совпадений, вам нужно перебрать все наборы данных золотых данных для каждого набора в рандомизированных наборах.
Более быстрый метод - использовать структуру данных, которая позволяет искать в среднем регистре O(1)
(в отличие от поиска O(n)
в списке). Python поддерживает следующие типы: dictionary
и set
.
A set
- это набор элементов, где каждый элемент обычно содержит один элемент данных. dictionary
более подходит, когда есть две связанные части данных. Здесь у вас есть два связанных / связанных элемента, а именно имя и кортежи.
Поскольку именно кортежи вы будете постоянно проверять на наличие в словаре, было бы эффективно, если бы вы хранили их в следующем формате, так как вы можете очень эффективно запрашивать любой кортеж. Кроме того, когда вы обнаружите кортеж и захотите узнать его имя, вы можете сразу же его найти.
{(123,456):'some_name',
(234,567):'another_name')}
Чтобы преобразовать ваш my_gold_mentions
словарь в формат, который я предлагаю, вы можете использовать этот словарь-понимание:
{tup:name for name, tups in my_gold_mentions.items() for tup in tups}
, что дает:
{(6532, 6538): 'Anakin',
(6590, 6592): 'Anakin',
(6673, 6675): 'Anakin',
(3600, 3602): 'He',
(3609, 3612): 'He'}
Теперь, когда вы создали более качественную структуру данных (назовем это tup_gold_mentions
), вы можете эффективно выполнить задачу:
TP = FN = FP = 0
for name, tups in my_coref.items():
for tup in tups:
if tup in tup_gold_mentions:
if name == tup_gold_mentions[tup]:
TP += 1
else:
FN += 1
FP += 1
else:
FN += 1
Который, с my_coref
как:
{'Anakin': [(6532, 6538),
(123, 45)],
'Bob': [(3600, 3602)],
'Jim': [(12, 34)]}
дает правильные результаты:
>>> TP
1
>>> FP
1
>>> FN
3