Я пытаюсь определить, какие метрики использовать для оценки «охвата» лексикона (списка слов) по отношению к ранжированному списку значимых ключевых слов, которые я извлек из двух разных коллекций текстов. Два списка не имеют общих терминов. Важно отметить, что только слова с самым высоким рейтингом должны считаться «правильными», в то время как слова с самым низким рейтингом должны считаться «неправильными».
Ниже приведен фиктивный пример с ранжированным списком ключевых слов и 4 различными лексиконами, каждый из которых содержит некоторые слова в списке.
rank keyword lexicon_1 lexicon_2 lexicon_3 lexicon_4
1 apple False True True False
2 orange False True True False
3 banana False False True False
4 pear False False True False
5 kiwifruit True False True False
6 watermelon True False True False
-----------------------------------------------------------
7 car False False False True
8 bus False False False True
9 truck True False False True
10 bike False True False True
Таким образом, интуиция заключается в том, что чем больше ключевых слов с высоким рейтингом (1-6) включено в лексикон, тем лучше, и чем меньше ключевых слов с более низким рейтингом (7-10), тем лучше.
Расчет точности (P), отзыва (R) и F-показателя (F) является одним из способов количественного определения и сравнения покрытия. Для этого истинные положительные значения (TP) - это когда лексикон содержит правильное слово, ложные положительные значения (FP), когда оно содержит неверное слово, истинные отрицательные значения (TN), когда исключается неправильное слово, и ложные отрицания (FN), когда исключается правильное слово. Имея это в виду, например, для lexicon_1
это дает:
TP=2, FP=1, TN=3, FN=4
P = 2 / (2 + 1) R = 2 / (2 + 4) F = 2 * 0.67 * 0.33 / (0.67 + 0.33)
= 0.67 = 0.33 = 0.44
Для lexicon_2
мы также получаем F=0.44
. Для lexicon_3
мы получаем F=1.00
, а для lexicon_4
мы получаем F=0
(как неопределено). Таким образом, мы можем видеть, что лексиконы 1
и 2
расположены между 3
(лучший) и 4
(худший), но это не учитывает тот факт, что lexicon_2
имеет слова с более высоким рейтингом, чем lexicon_1
и поэтому должен получить более благоприятную оценку.
Есть ли метрика, которая бы учитывала ранжирование слов в этих случаях? Мне известны average precision
и mean average precision
, которые учитывают ранжирование полученных результатов, но я не уверен, подходят ли эти показатели для данной ситуации.
РЕДАКТИРОВАТЬ 1:
Я реализовал мое понимание средней точности для этой ситуации:
def avep(df, lexicon_names):
"""
Calculate average precision for each lexicon from
pre-calculated precision and recall scores stored
in a DataFrame.
"""
aveps = {}
for l in lexicon_names:
ap = 0.0
for i in range(len(df)):
p_i = df.iloc[i]['p_' + l]
if i > 0:
dr_i = df.iloc[i]['r_' + l] - df.iloc[i - 1]['r_' + l]
else:
dr_i = 0.0
ap += p_i * dr_i
aveps[l] = ap
return aveps
Это дает мне следующие результаты:
Lexicon p r f AP
------- - - - --
lexicon_1 : 0.6666666666666666 0.2857142857142857 0.4 0.2857142857142857
lexicon_2 : 0.6666666666666666 0.2857142857142857 0.4 0.14285714285714285
lexicon_3 : 1.0 1.0 1.0 0.8571428571428571
lexicon_4 : 0.0 0.0 0.0 0.0
Но это дает лучший результат для lexicon_1
, чем lexicon_2
, что противоположно тому, что я хочу (и AP подозрительно равна отзыву для lexicon_1
и 2 x recall
для lexicon_2
). Кроме того, не уверены, что делать с первой строкой, где разница в возврате не определена (используется 0). Это дает значение менее 1,0 для «совершенного» * 1047 *.
Любые лучшие предложения будут высоко оценены!
РЕДАКТИРОВАТЬ 2:
Вот моя Python-реализация решения, предоставленного RobertBaron:
def coverage_metric(df, lexicon_names):
scores = {}
max_score = int(''.join([str(x) for x in df.index]))
for l in lexicon_names:
correct_score = int(''.join([str(x) for x in df.loc[df[l] == True].index]))
incorrect_score = int(''.join([str(x) for x in df.loc[df[l] == False].index]))
scores[l] = (correct_score - incorrect_score) / max_score
scores = sorted(scores.items(), key=lambda x: x[1], reverse=True)
return scores
Это реализация преобразования чисел, необходимого для решения RobertBaron (насколько я понимаю):
def int2base(n, b):
"""
Implementation of the algorith; described at http://www.cs.trincoll.edu/~ram/cpsc110/inclass/conversions.html
"""
x = ''
while n > 0:
d = int(n / b)
r = n % b
x += str(r)
n = d
return int(x)