AcroBERT / maddog.py
Lihuchen's picture
maddog.py
3df8e40
'''
from https://github.com/amirveyseh/MadDog under CC BY-NC-SA 4.0
'''
import string
if __name__ != "__main__":
import spacy.cli
spacy.cli.download("en_core_web_sm")
import spacy
nlp = spacy.load("en_core_web_sm")
with open('stopWords.txt') as file:
stop_words = [l.strip() for l in file.readlines()]
class Extractor:
def __init__(self):
pass
def short_extract(self, sentence, threshold, starting_lower_case, ignore_dot=False):
shorts = []
for i, t in enumerate(sentence):
if ignore_dot:
t = t.replace('.', '')
# t = t.replace('-','')
if len(t) == 0:
continue
# FIXED [issue: of an enhanced Node B ( eNB ) ]
if not starting_lower_case:
if t[0].isupper() and len([c for c in t if c.isupper()]) / len(t) > threshold and 2 <= len(t) <= 10:
shorts.append(i)
else:
if len([c for c in t if c.isupper()]) / len(t) > threshold and 2 <= len(t) <= 10:
shorts.append(i)
return shorts
def extract_cand_long(self, sentence, token, ind, ignore_punc=False, add_punc=False, small_window=False):
'''
extract candidate long form of the form "long form (short form)" or "short form (long form)"
:param sentence: tokenized sentence
:param token: acronym
:param ind: position of the acronym
:return: candidate long form, candidate is on left or right of the short form
'''
if not small_window:
long_cand_length = min([len(token) + 10, len(token) * 3])
else:
long_cand_length = min([len(token) + 5, len(token) * 2])
cand_long = []
cand_long_index = []
left = True
right_ind = 1
left_ind = 1
# FIXED [issue: ]
if add_punc:
excluded_puncs = ['=', ':']
else:
excluded_puncs = []
# FIXED [issue: such as Latent Semantic Analysis ( LSA ; )]
if ignore_punc:
while ind + right_ind < len(sentence) and sentence[ind + right_ind] in [p for p in string.punctuation if
p != '(' and p != ')' and p not in excluded_puncs]:
right_ind += 1
while ind - left_ind > 0 and sentence[ind - left_ind] in [p for p in string.punctuation if
p != '(' and p != ')' and p not in excluded_puncs]:
left_ind -= 1
####
if ind < len(sentence) - 2 - right_ind and (
sentence[ind + right_ind] == '(' or sentence[ind + right_ind] == '=' or sentence[
ind + right_ind] in excluded_puncs):
left = False
for j in range(ind + right_ind + 1, min([ind + right_ind + 1 + long_cand_length, len(sentence)])):
if sentence[j] != ')':
cand_long.append(sentence[j])
cand_long_index.append(j)
else:
break
elif 1 < ind - (left_ind - 1) and ind + right_ind < len(sentence) and (
(sentence[ind - left_ind] == '(' and sentence[ind + right_ind] == ')') or sentence[
ind - left_ind] in excluded_puncs):
for k in range(0, long_cand_length):
j = ind - left_ind - 1 - k
if j > -1:
cand_long.insert(0, sentence[j])
cand_long_index.insert(0, j)
return cand_long, cand_long_index, left
# FIXED [issue: The Stopping Trained in America PhDs from Leaving the Economy Act ( or STAPLE Act ) has bee introduced]
def extract_high_recall_cand_long(self, sentence, token, ind, small_window=False, left=False):
'''
Find the candidate long form for a give acronym for high recall extraction
example: The Stopping Trained in America PhDs from Leaving the Economy Act ( or STAPLE Act ) has bee introduced
:param sentence:
:param token:
:param ind:
:param small_window:
:return:
'''
long_cand_length = min([len(token) + 10, len(token) * 3])
cand_long = []
cand_long_index = []
if not left:
for j in range(ind + 1, min([ind + long_cand_length, len(sentence)])):
cand_long.append(sentence[j])
cand_long_index.append(j)
else:
for k in range(0, long_cand_length):
j = ind - 1 - k
if j > -1:
cand_long.insert(0, sentence[j])
cand_long_index.insert(0, j)
return cand_long, cand_long_index, left
def create_diction(self, sentence, labels, all_acronyms=True, tag='', map_chars=False, diction={}):
'''
convert sequential labels into {short-form: long-form} dictionary
:param sentence: tokenized sentence
:param labels: labels of form B-short, B-long, I-short, I-long, O
:return: dictionary
'''
shorts = []
longs = []
isShort = True
phr = []
for i in range(len(sentence)):
if labels[i] == 'O' or (isShort and 'long' in labels[i]) or (not isShort and 'short' in labels[i]) or (
labels[i].startswith('B')):
if len(phr):
if isShort:
shorts.append((phr[0], phr[-1]))
else:
longs.append((phr[0], phr[-1]))
phr = []
if 'short' in labels[i]:
isShort = True
phr.append(i)
if 'long' in labels[i]:
isShort = False
phr.append(i)
if len(phr):
if isShort:
shorts.append((phr[0], phr[-1]))
else:
longs.append((phr[0], phr[-1]))
acr_long = {}
for long in longs:
best_short = []
## check if the long form is already mapped in given diction
if long in diction and diction[long] in shorts:
best_short = diction[long]
best_dist = float('inf')
#### FIXED [issue: long form incorrectly mapped to the closest acronym in the sentence]
#### FIXED [issue: multiple short forms could be character matched with the long form]
if not best_short:
best_short_cands = []
for short in shorts:
long_form = self.character_match(sentence[short[0]], sentence[long[0]:long[1] + 1],
list(range(long[1] + 1 - long[0])), output_string=True,
is_candidate=False)
if long_form:
best_short_cands.append(short)
if len(best_short_cands) == 1:
best_short = best_short_cands[0]
#####
#### FIXED [QALD-6 (the workshop of question answering over linked-data 6) at ESWIC 2016]
if not best_short and map_chars:
best_short_cands = []
for short in shorts:
long_form = self.map_chars(sentence[short[0]], sentence[long[0]:long[1] + 1])
if long_form:
best_short_cands.append(short)
if len(best_short_cands) == 1:
best_short = best_short_cands[0]
####
#### FIXED [issue: US Securities and Exchange Commission EDGAR ( SEC ) database]
if not best_short:
best_short_cands = []
for short in shorts:
is_mapped = self.map_chars_with_capitals(sentence[short[0]], sentence[long[0]:long[1] + 1])
if is_mapped:
best_short_cands.append(short)
if len(best_short_cands) == 1:
best_short = best_short_cands[0]
####
# FIXED [issue: RNNs , Long Short - Term Memory ( LSTM ) architecture]
if not best_short and long[1] < len(sentence) - 2 and sentence[long[1] + 1] == '(' and 'short' in labels[
long[1] + 2]:
for short in shorts:
if short[0] == long[1] + 2:
best_short = short
break
if not best_short and long[0] > 1 and sentence[long[0] - 1] == '(' and 'short' in labels[long[0] - 2]:
for short in shorts:
if short[1] == long[0] - 2:
best_short = short
break
####
if not best_short:
for short in shorts:
if short[0] > long[1]:
dist = short[0] - long[1]
else:
dist = long[0] - short[1]
if dist < best_dist:
best_dist = dist
best_short = short
if best_short:
short_form_info = ' '.join(sentence[best_short[0]:best_short[1] + 1])
long_form_info = [' '.join(sentence[long[0]:long[1] + 1]), best_short, [long[0], long[1]], tag, 1]
if short_form_info in acr_long:
long_form_info[4] += 1
acr_long[short_form_info] = long_form_info
if all_acronyms:
for short in shorts:
acr = ' '.join(sentence[short[0]:short[1] + 1])
if acr not in acr_long:
acr_long[acr] = ['', short, [], tag, 1]
return acr_long
#### FIXED [QALD-6 (the workshop of question answering over linked-data 6) at ESWIC 2016]
def map_chars(self, acronym, long):
'''
This function evaluate the long for based on number of initials overlapping with the acronym and if it is above a threshold it assigns the long form the the acronym
:param acronym:
:param long:
:return:
'''
capitals = []
for c in acronym:
if c.isupper():
capitals.append(c.lower())
initials = [w[0].lower() for w in long]
ratio = len([c for c in initials if c in capitals]) / len(initials)
if ratio >= 0.6:
return long
else:
return None
#### FIXED [issue: US Securities and Exchange Commission EDGAR ( SEC ) database]
def map_chars_with_capitals(self, acronym, long):
'''
This function maps the acronym to the long-form which has the same initial capitals as the acronym
:param acronym:
:param long:
:return:
'''
capitals = []
for c in acronym:
if c.isupper():
capitals.append(c.lower())
long_capital_initials = []
for w in long:
if w[0].isupper():
long_capital_initials.append(w[0].lower())
if len(capitals) == len(long_capital_initials) and all(
capitals[i] == long_capital_initials[i] for i in range(len(capitals))):
return True
else:
return False
def schwartz_extract(self, sentence, shorts, remove_parentheses, ignore_hyphen=False, ignore_punc=False,
add_punc=False, small_window=False, no_stop_words=False, ignore_righthand=False,
map_chars=False,default_diction=False):
labels = ['O'] * len(sentence)
diction = {}
for i, t in enumerate(sentence):
if i in shorts:
labels[i] = 'B-short'
# FIXED [issue: We show that stochastic gradient Markov chain Monte Carlo ( SG - MCMC ) - a class of ]
if ignore_hyphen:
t = t.replace('-', '')
# FIXED [issue: such as Latent Semantic Analysis ( LSA ; )]
cand_long, cand_long_index, left = self.extract_cand_long(sentence, t, i, ignore_punc=ignore_punc,
add_punc=add_punc, small_window=small_window)
cand_long = ' '.join(cand_long)
long_form = ""
## findBestLongForm
if len(cand_long) > 0:
if left:
sIndex = len(t) - 1
lIndex = len(cand_long) - 1
while sIndex >= 0:
curChar = t[sIndex].lower()
if curChar.isdigit() or curChar.isalpha():
while (lIndex >= 0 and cand_long[lIndex].lower() != curChar) or (
sIndex == 0 and lIndex > 0 and (
cand_long[lIndex - 1].isdigit() or cand_long[lIndex - 1].isalpha())):
lIndex -= 1
if lIndex < 0:
break
lIndex -= 1
sIndex -= 1
if lIndex >= -1:
try:
lIndex = cand_long.rindex(" ", 0, lIndex + 1) + 1
except:
lIndex = 0
if cand_long:
cand_long = cand_long[lIndex:]
long_form = cand_long
else:
sIndex = 0
lIndex = 0
if t[0].lower() == cand_long[0].lower() or ignore_righthand:
while sIndex < len(t):
curChar = t[sIndex].lower()
if curChar.isdigit() or curChar.isalpha():
while (lIndex < len(cand_long) and cand_long[lIndex].lower() != curChar) or (
ignore_righthand and (sIndex == 0 and lIndex > 0 and (
cand_long[lIndex - 1].isdigit() or cand_long[lIndex - 1].isalpha()))) or (
lIndex != 0 and cand_long[lIndex - 1] != ' ' and ' ' in cand_long[
lIndex:] and
cand_long[cand_long[lIndex:].index(' ') + lIndex + 1].lower() == curChar):
lIndex += 1
if lIndex >= len(cand_long):
break
if lIndex >= len(cand_long):
break
lIndex += 1
sIndex += 1
if lIndex < len(cand_long):
try:
lIndex = cand_long[lIndex:].index(" ") + lIndex + 1
except:
lIndex = len(cand_long)
if cand_long:
cand_long = cand_long[:lIndex]
long_form = cand_long
# FIXED [issue : 'good results on the product review ( CR ) and on the question - type ( TREC ) tasks']
if remove_parentheses:
if '(' in long_form or ')' in long_form:
long_form = ''
# FIXED [issue: TN: The Number of ]
long_form = long_form.split()
if no_stop_words and long_form:
if long_form[0].lower() in stop_words:
long_form = []
if long_form:
if left:
long_form_index = cand_long_index[-len(long_form):]
else:
long_form_index = cand_long_index[:len(long_form)]
first = True
for j in range(len(sentence)):
if j in long_form_index:
if first:
labels[j] = 'B-long'
first = False
else:
labels[j] = 'I-long'
if default_diction:
diction[(long_form_index[0], long_form_index[-1])] = (i, i)
return self.create_diction(sentence, labels, tag='Schwartz', map_chars=map_chars, diction=diction)
def bounded_schwartz_extract(self, sentence, shorts, remove_parentheses, ignore_hyphen=False, ignore_punc=False,
add_punc=False, small_window=False, no_stop_words=False, ignore_righthand=False,
map_chars=False, high_recall=False, high_recall_left=False, tag='Bounded Schwartz',default_diction=False):
'''
This function uses the same rule as schwartz but for the format "long form (short form)" will select long forms that the last word in the long form is selected to form the acronym
example: User - guided Social Media Crawling method ( USMC ) that
:param remove_parentheses:
:param sentence:
:param shorts:
:return:
'''
labels = ['O'] * len(sentence)
diction = {}
for i, t in enumerate(sentence):
if i in shorts:
labels[i] = 'B-short'
# FIXED [issue: We show that stochastic gradient Markov chain Monte Carlo ( SG - MCMC ) - a class of ]
if ignore_hyphen:
t = t.replace('-', '')
# FIXED [issue: The Stopping Trained in America PhDs from Leaving the Economy Act ( or STAPLE Act ) has bee introduced]
if high_recall:
cand_long, cand_long_index, left = self.extract_high_recall_cand_long(sentence, t, i,
small_window=small_window,
left=high_recall_left)
else:
# FIXED [issue: such as Latent Semantic Analysis ( LSA ; )]
cand_long, cand_long_index, left = self.extract_cand_long(sentence, t, i, ignore_punc=ignore_punc,
add_punc=add_punc,
small_window=small_window)
cand_long = ' '.join(cand_long)
long_form = ""
## findBestLongForm
if len(cand_long) > 0:
if left:
sIndex = len(t) - 1
lIndex = len(cand_long) - 1
first_ind = len(cand_long)
while sIndex >= 0:
curChar = t[sIndex].lower()
if curChar.isdigit() or curChar.isalpha():
while (lIndex >= 0 and cand_long[lIndex].lower() != curChar) or (
sIndex == 0 and lIndex > 0 and (
cand_long[lIndex - 1].isdigit() or cand_long[lIndex - 1].isalpha())):
lIndex -= 1
if first_ind == len(cand_long):
first_ind = lIndex
if lIndex < 0:
break
lIndex -= 1
sIndex -= 1
if lIndex >= 0 or lIndex == -1 and cand_long[0].lower() == t[0].lower():
try:
lIndex = cand_long.rindex(" ", 0, lIndex + 1) + 1
try:
rIndex = cand_long[first_ind:].index(" ") + first_ind
except:
rIndex = len(cand_long)
except:
lIndex = 0
try:
rIndex = cand_long[first_ind:].index(" ") + first_ind
except:
rIndex = len(cand_long)
if cand_long:
index_map = {}
word_ind = 0
for ind, c in enumerate(cand_long):
if c == ' ':
word_ind += 1
index_map[ind] = word_ind
last_word_index = index_map[rIndex - 1]
cand_long = cand_long[lIndex:rIndex]
long_form = cand_long
else:
sIndex = 0
lIndex = 0
first_ind = -1
if t[0].lower() == cand_long[0].lower() or ignore_righthand:
while sIndex < len(t):
curChar = t[sIndex].lower()
if curChar.isdigit() or curChar.isalpha():
while (lIndex < len(cand_long) and cand_long[lIndex].lower() != curChar) or (
ignore_righthand and (sIndex == 0 and lIndex > 0 and (
cand_long[lIndex - 1].isdigit() or cand_long[lIndex - 1].isalpha()))) or (
lIndex != 0 and cand_long[lIndex - 1] != ' ' and ' ' in cand_long[
lIndex:] and
cand_long[cand_long[lIndex:].index(' ') + lIndex + 1].lower() == curChar):
lIndex += 1
if lIndex >= len(cand_long):
break
if first_ind == -1:
first_ind = lIndex
if lIndex >= len(cand_long):
break
lIndex += 1
sIndex += 1
if lIndex < len(cand_long) or (
first_ind < len(cand_long) and lIndex == len(cand_long) and cand_long[-1] == t[-1]):
try:
lIndex = cand_long[lIndex:].index(" ") + lIndex + 1
except:
lIndex = len(cand_long)
if cand_long:
if not ignore_righthand:
first_ind = 0
index_map = {}
word_ind = 0
for ind, c in enumerate(cand_long):
if c == ' ':
word_ind += 1
index_map[ind] = word_ind
first_word_index = index_map[first_ind]
cand_long = cand_long[first_ind:lIndex]
long_form = cand_long
# FIXED [issue : 'good results on the product review ( CR ) and on the question - type ( TREC ) tasks']
if remove_parentheses:
if '(' in long_form or ')' in long_form:
long_form = ''
# FIXED [issue: TN: The Number of ]
long_form = long_form.split()
if no_stop_words and long_form:
if long_form[0].lower() in stop_words:
long_form = []
if long_form:
if left:
long_form_index = cand_long_index[last_word_index - len(long_form) + 1:last_word_index + 1]
else:
long_form_index = cand_long_index[first_word_index:first_word_index + len(long_form)]
first = True
for j in range(len(sentence)):
if j in long_form_index:
if first:
labels[j] = 'B-long'
first = False
else:
labels[j] = 'I-long'
if default_diction:
diction[(long_form_index[0],long_form_index[-1])] = (i,i)
return self.create_diction(sentence, labels, tag=tag, map_chars=map_chars,diction=diction)
# FIXED [issue: The Stopping Trained in America PhDs from Leaving the Economy Act ( or STAPLE Act ) has bee introduced]
def high_recall_schwartz(self, sentence, shorts, remove_parentheses, ignore_hyphen=False, ignore_punc=False,
add_punc=False, small_window=False, no_stop_words=False, ignore_righthand=False,
map_chars=False):
'''
This function use bounded schwartz rules for acronyms which are not necessarily in parentheses
example: The Stopping Trained in America PhDs from Leaving the Economy Act ( or STAPLE Act ) has bee introduced
:param sentence:
:param shorts:
:param remove_parentheses:
:param ignore_hyphen:
:param ignore_punc:
:param add_punc:
:param small_window:
:param no_stop_words:
:param ignore_righthand:
:param map_chars:
:return:
'''
pairs_left = self.bounded_schwartz_extract(sentence, shorts, remove_parentheses, ignore_hyphen=True,
ignore_punc=ignore_punc, add_punc=add_punc,
small_window=small_window, no_stop_words=no_stop_words,
ignore_righthand=ignore_righthand, map_chars=True, high_recall=True,
high_recall_left=True, tag='High Recall Schwartz')
pairs_right = self.bounded_schwartz_extract(sentence, shorts, remove_parentheses, ignore_hyphen=True,
ignore_punc=ignore_punc, add_punc=add_punc,
small_window=small_window, no_stop_words=no_stop_words,
ignore_righthand=ignore_righthand, map_chars=True, high_recall=True,
high_recall_left=False, tag='High Recall Schwartz')
for acr, lf in pairs_right.items():
if len(lf[0]) > 0 and (acr not in pairs_left or len(pairs_left[acr][0]) == 0):
pairs_left[acr] = lf
res = {}
for acr, lf in pairs_left.items():
if acr == ''.join([w[0] for w in lf[0].split() if w[0].isupper()]) or acr.lower() == ''.join(
w[0] for w in lf[0].split() if w not in string.punctuation and w not in stop_words).lower():
res[acr] = lf
return res
def character_match(self, acronym, long, long_index, left=False, output_string=False, is_candidate=True):
capitals = []
long_form = []
for c in acronym:
if c.isupper():
capitals.append(c)
# FIXED [issue: different modern GAN architectures : Deep Convolutional ( DC ) GAN , Spectral Normalization ( SN ) GAN , and Spectral Normalization GAN with Gradient Penalty ( SNGP ) .]
if not is_candidate:
long_capital_initials = []
for w in long:
if w[0].isupper():
long_capital_initials.append(w[0])
####
if left:
capitals = capitals[::-1]
long = long[::-1]
long_index = long_index[::-1]
for j, c in enumerate(capitals):
if j >= len(long):
long_form = []
break
else:
if long[j][0].lower() == c.lower():
long_form.append(long_index[j])
else:
long_form = []
break
# FIXED [issue: different modern GAN architectures : Deep Convolutional ( DC ) GAN , Spectral Normalization ( SN ) GAN , and Spectral Normalization GAN with Gradient Penalty ( SNGP ) .]
if not is_candidate:
if len(long_capital_initials) != len(long_form) and len(long_capital_initials) > 0:
long_form = []
####
long_form.sort()
if output_string:
if long_form:
return long[long_form[0]:long_form[-1] + 1]
else:
return ""
else:
return long_form
# FIXED [issue: annotation software application , Text Annotation Graphs , or TAG , that provides a rich set of]
def high_recall_character_match(self, sentence, shorts, all_acronyms, ignore_hyphen=False, map_chars=False,default_diction=False):
'''
This function finds the long form of the acronyms that are not surrounded by parentheses in the text using scritc rule of character matching (the initial of the sequence of the words in the candidate long form should form the acronym)
example: annotation software application , Text Annotation Graphs , or TAG , that provides a rich set of ...
:param sentence:
:param shorts:
:param all_acronyms:
:return:
'''
labels = ['O'] * len(sentence)
diction = {}
for i, t in enumerate(sentence):
if i in shorts:
labels[i] = 'B-short'
# FIXED [issue: We show that stochastic gradient Markov chain Monte Carlo ( SG - MCMC ) - a class of ]
if ignore_hyphen:
t = t.replace('-', '')
capitals = []
for c in t:
if c.isupper():
capitals.append(c)
cand_long = sentence[max(i - len(capitals) - 10, 0):i]
long_form = ''
long_form_index = []
for j in range(max(len(cand_long) - len(capitals), 0)):
if ''.join(w[0] for w in cand_long[j:j + len(capitals)]) == t:
long_form = ' '.join(cand_long[j:j + len(capitals)])
long_form_index = list(range(max(max(i - len(capitals) - 10, 0) + j, 0),
max(max(i - len(capitals) - 10, 0) + j, 0) + len(capitals)))
break
if not long_form:
cand_long = sentence[i + 1:len(capitals) + i + 10]
for j in range(max(len(cand_long) - len(capitals), 0)):
if ''.join(w[0] for w in cand_long[j:j + len(capitals)]) == t:
long_form = ' '.join(cand_long[j:j + len(capitals)])
long_form_index = list(range(i + 1 + j, i + j + len(capitals) + 1))
break
long_form = long_form.split()
if long_form:
if long_form[0] in stop_words or long_form[-1] in stop_words:
long_form = []
if any(lf in string.punctuation for lf in long_form):
long_form = []
if __name__ != "__main__":
NPs = [np.text for np in nlp(' '.join(sentence)).noun_chunks]
long_form_str = ' '.join(long_form)
if all(long_form_str not in np for np in NPs):
long_form = []
if long_form:
for j in long_form_index:
labels[j] = 'I-long'
labels[long_form_index[0]] = 'B-long'
if default_diction:
diction[(long_form_index[0], long_form_index[-1])] = (i, i)
return self.create_diction(sentence, labels, all_acronyms=all_acronyms, tag='high recall character match',
map_chars=map_chars,diction=diction)
def character_match_extract(self, sentence, shorts, all_acronyms, check_all_capitals=False, ignore_hyphen=False,
ignore_punc=False, map_chars=False,default_diction=False):
labels = ['O'] * len(sentence)
diction = {}
for i, t in enumerate(sentence):
if i in shorts:
labels[i] = 'B-short'
# FIXED [issue: We show that stochastic gradient Markov chain Monte Carlo ( SG - MCMC ) - a class of ]
if ignore_hyphen:
t = t.replace('-', '')
# FIXED [issue: acronyms with lowercase letters, example: of an enhanced Node B ( eNB ) ]
if check_all_capitals:
if len(t) != len([c for c in t if c.isupper()]):
continue
# FIXED [issue: such as Latent Semantic Analysis ( LSA ; )]
cand_long, cand_long_index, left = self.extract_cand_long(sentence, t, i, ignore_punc=ignore_punc)
long_form = []
if cand_long:
long_form = self.character_match(t, cand_long, cand_long_index, left, is_candidate=True)
if long_form:
labels[long_form[0]] = 'B-long'
for l in long_form[1:]:
labels[l] = 'I-long'
if default_diction:
diction[(long_form[0], long_form[-1])] = (i, i)
return self.create_diction(sentence, labels, all_acronyms=all_acronyms, tag='character match',
map_chars=map_chars, diction=diction)
# FIXED [issue: roman numbers]
def filterout_roman_numbers(self, diction):
'''
This function removes roman numbers from the list of extracted acronyms. It removes only numbers from 1 to 20.
:param diction:
:return:
'''
acronyms = set(diction.keys())
for acr in acronyms:
# instead of all roman acronyms we remove only 1 to 20:
# if bool(re.search(r"^M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$", acr)):
if acr in ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII', 'XIII', 'XIV', 'XV',
'XVI', 'XVII', 'XVIII', 'XIX', 'XX']:
del diction[acr]
return diction
# FIXED [issue: 'In International Semantic Web Conference , ( ISWC ) ,']
def remove_punctuations(self, diction):
'''
Remove head+tailing punctuations
:param diction:
:return:
'''
for acr, info in diction.items():
if len(info[0]) > 0:
if info[0][0] in string.punctuation:
info[0] = info[0][2:]
info[2][0] = info[2][0] + 1
info[3] = 'remove punctuation'
if len(info[0]) > 0:
if info[0][-1] in string.punctuation:
info[0] = info[0][:-2]
info[2][1] = info[2][1] - 1
info[3] = 'remove punctuation'
return diction
# FIXED [issue: and Cantab Capital Institute for Mathematics of Information ( CCIMI )]
def initial_capitals_extract(self, sentence, shorts, all_acronyms, ignore_hyphen=False, map_chars=False,default_diction=False):
'''
This function captures long form which their initials is capital and could form the acronym in the format "long form (acronym)" or "(acronym) long form"
example:
:param sentence:
:param shorts:
:param all_acronyms:
:return:
'''
labels = ['O'] * len(sentence)
diction = {}
for i, t in enumerate(sentence):
if i in shorts:
labels[i] = 'B-short'
# FIXED [issue: We show that stochastic gradient Markov chain Monte Carlo ( SG - MCMC ) - a class of ]
if ignore_hyphen:
t = t.replace('-', '')
capitals = []
for c in t:
if c.isupper():
capitals.append(c)
cand_long, cand_long_index, left = self.extract_cand_long(sentence, t, i)
capital_initials = []
capital_initials_index = []
for j, w in enumerate(cand_long):
lll = labels[i + j - len(cand_long) - 1]
if w[0].isupper() and labels[i + j - len(cand_long) - 1] == 'O':
capital_initials.append(w[0])
capital_initials_index.append(j)
if ''.join(capital_initials) == t:
long_form = cand_long[capital_initials_index[0]:capital_initials_index[-1] + 1]
long_form_index = cand_long_index[capital_initials_index[0]:capital_initials_index[-1] + 1]
for lfi in long_form_index:
labels[lfi] = 'I-long'
labels[long_form_index[0]] = 'B-long'
if default_diction:
diction[(long_form_index[0], long_form_index[-1])] = (i, i)
return self.create_diction(sentence, labels, all_acronyms=all_acronyms, tag='Capital Initials',
map_chars=map_chars,diction=diction)
# FIXED [issue: for C - GAN indicates ]
def hyphen_in_acronym(self, sentence, shorts):
'''
This function merge two acronyms if there is a hyphen between them
example: for C - GAN indicates
:param sentence:
:param shorts:
:return:
'''
new_shorts = []
for short in shorts:
i = short + 1
next_hyphen = False
while i < len(sentence) and sentence[i] == '-':
next_hyphen = True
i += 1
j = short - 1
before_hyphen = False
while j > 0 and sentence[j] == '-':
before_hyphen = True
j -= 1
# FIXED [check length of the new acronym. issue: SPG - GCN)In Table]
# if i < len(sentence) and sentence[i].isupper() and len(sentence[i]) <= 2:
if i < len(sentence) and sentence[i].isupper() and next_hyphen:
for ind in range(short + 1, i + 1):
new_shorts += [ind]
# FIXED [check length of the new acronym. issue: SPG - GCN)In Table]
# if j > -1 and sentence[j].isupper() and len(sentence[j]) <= 2:
if j > -1 and sentence[j].isupper() and before_hyphen:
for ind in range(j, short):
new_shorts += [ind]
shorts.extend(new_shorts)
return shorts
# FIXED [issue: We show that stochastic gradient Markov chain Monte Carlo ( SG - MCMC ) - a class of ]
def merge_hyphened_acronyms(self, sentence, labels=[]):
'''
This function merge hyphened acronyms
example: We show that stochastic gradient Markov chain Monte Carlo ( SG - MCMC ) - a class of
:param sentence:
:return:
'''
new_sentence = []
new_labels = []
merge = False
shorts = self.short_extract(sentence, 0.6, True)
shorts += self.hyphen_in_acronym(sentence, shorts)
for i, t in enumerate(sentence):
if i in shorts and i - 1 in shorts and i + 1 in shorts and t == '-':
merge = True
if len(new_sentence) > 0:
new_sentence[-1] += '-'
else:
new_sentence += ['-']
continue
if merge:
if len(new_sentence) > 0:
new_sentence[-1] += t
else:
new_sentence += [t]
else:
new_sentence.append(t)
if labels:
new_labels.append(labels[i])
merge = False
return new_sentence, new_labels
# FIXED [issue: we use encoder RNN ( ER )]
def add_embedded_acronym(self, diction, shorts, sentence):
'''
This function will add the embeded acronyms into the dictionary
example: we use encoder RNN ( ER )
:param diction:
:param shorts:
:return:
'''
short_captured = []
long_captured = []
for acr, info in diction.items():
short_captured.append(info[1][0])
if info[2]:
long_captured.extend(list(range(info[2][0], info[2][1])))
for short in shorts:
if short not in short_captured and short in long_captured and sentence[short] not in diction:
diction[sentence[short]] = ['', (short, short), [], 'embedded acronym']
return diction
# FIXED [issue: acronym stands for template]
def extract_templates(self, sentence, shorts, map_chars=False):
'''
Extract acronym and long forms based on templates
example: PM stands for Product Manager
:param sentence:
:param shorts:
:return:
'''
labels = ['O'] * len(sentence)
for i, t in enumerate(sentence):
if i in shorts:
labels[i] = 'B-short'
capitals = []
for c in t:
if c.isupper():
capitals.append(c)
if i < len(sentence) - len(capitals) - 2:
if sentence[i + 1] == 'stands' and sentence[i + 2] == 'for':
if ''.join(w[0] for w in sentence[i + 3:i + 3 + len(capitals)]) == ''.join(capitals):
labels[i + 3:i + 3 + len(capitals)] = ['I-long'] * len(capitals)
labels[i + 3] = 'B-long'
return self.create_diction(sentence, labels, all_acronyms=False, tag='Template', map_chars=map_chars)
# FIXED [issue: preserve number of meanins extracted from other method]
def update_pair(self, old_pair, new_pair):
for acr, info in new_pair.items():
if acr not in old_pair:
old_pair[acr] = info
else:
info[4] = max(info[4],old_pair[acr][4])
old_pair[acr] = info
return old_pair
def extract(self, sentence, active_rules):
# FIXED [issue: of an enhanced Node B ( eNB ) ]
shorts = self.short_extract(sentence, 0.6, active_rules['starting_lower_case'],
ignore_dot=active_rules['ignore_dot'])
# FIXED [issue: acronyms like StESs]
if active_rules['low_short_threshold']:
shorts += self.short_extract(sentence, 0.50, active_rules['starting_lower_case'],
ignore_dot=active_rules['ignore_dot'])
####
# FIXED [issue: for C - GAN indicates ]
if active_rules['hyphen_in_acronym']:
shorts += self.hyphen_in_acronym(sentence, shorts)
####
pairs = {}
if active_rules['schwartz']:
# FIXED [issue: such as Latent Semantic Analysis ( LSA ; )]
pairs = self.schwartz_extract(sentence, shorts, active_rules['no_parentheses'],
ignore_punc=active_rules['ignore_punc_in_parentheses'],
add_punc=active_rules['extend_punc'],
small_window=active_rules['small_window'],
no_stop_words=active_rules['no_beginning_stop_word'],
ignore_righthand=active_rules['ignore_right_hand'],
map_chars=active_rules['map_chars'],
default_diction=active_rules['default_diction'])
# FIXED [issue: 'User - guided Social Media Crawling method ( USMC ) that']
if active_rules['bounded_schwartz']:
# FIXED [issue: such as Latent Semantic Analysis ( LSA ; )]
bounded_pairs = self.bounded_schwartz_extract(sentence, shorts, active_rules['no_parentheses'],
ignore_punc=active_rules['ignore_punc_in_parentheses'],
add_punc=active_rules['extend_punc'],
small_window=active_rules['small_window'],
no_stop_words=active_rules['no_beginning_stop_word'],
ignore_righthand=active_rules['ignore_right_hand'],
map_chars=active_rules['map_chars'],
default_diction=active_rules['default_diction'])
# pairs.update(bounded_pairs)
pairs = self.update_pair(pairs, bounded_pairs)
# FIXED [issue: The Stopping Trained in America PhDs from Leaving the Economy Act ( or STAPLE Act ) has bee introduced]
if active_rules['high_recall_schwartz']:
hr_paris = self.high_recall_schwartz(sentence, shorts, active_rules['no_parentheses'],
ignore_punc=active_rules['ignore_punc_in_parentheses'],
add_punc=active_rules['extend_punc'],
small_window=active_rules['small_window'],
no_stop_words=active_rules['no_beginning_stop_word'],
ignore_righthand=active_rules['ignore_right_hand'],
map_chars=active_rules['map_chars'],
default_diction=active_rules['default_diction'])
# pairs.update(hr_paris)
pairs = self.update_pair(pairs,hr_paris)
if active_rules['character']:
# FIXED [issue: acronyms with lowercase letters, example: of an enhanced Node B ( eNB ) ]
# FIXED [issue: such as Latent Semantic Analysis ( LSA ; )]
character_pairs = self.character_match_extract(sentence, shorts, not active_rules['schwartz'],
check_all_capitals=active_rules['check_all_capitals'],
ignore_punc=active_rules['ignore_punc_in_parentheses'],
map_chars=active_rules['map_chars'],
default_diction=active_rules['default_diction'])
# pairs.update(character_pairs)
pairs = self.update_pair(pairs, character_pairs)
# FIXED [issue: annotation software application , Text Annotation Graphs , or TAG , that provides a rich set of]
if active_rules['high_recall_character_match']:
character_pairs = self.high_recall_character_match(sentence, shorts, not active_rules['schwartz'],
map_chars=active_rules['map_chars'],default_diction=active_rules['default_diction'])
acronyms = character_pairs.keys()
for acr in acronyms:
if acr not in pairs or len(pairs[acr][0]) == 0:
pairs[acr] = character_pairs[acr]
# FIXED [issue: and Cantab Capital Institute for Mathematics of Information ( CCIMI )]
if active_rules['initial_capitals']:
character_pairs = self.initial_capitals_extract(sentence, shorts, not active_rules['schwartz'],
map_chars=active_rules['map_chars'],default_diction=active_rules['default_diction'])
# pairs.update(character_pairs)
pairs = self.update_pair(pairs,character_pairs)
# FIXED [issue: acronym stands for long form]
if active_rules['template']:
template_pairs = self.extract_templates(sentence, shorts, map_chars=active_rules['map_chars'])
# pairs.update(template_pairs)
pairs = self.update_pair(pairs,template_pairs)
# FIXED [issue: we use encoder RNN ( ER )]
if active_rules['capture_embedded_acronym']:
pairs = self.add_embedded_acronym(pairs, shorts, sentence)
# FIXED [issue: roman numbers]
if active_rules['roman']:
pairs = self.filterout_roman_numbers(pairs)
# FIXED [issue: 'In International Semantic Web Conference , ( ISWC ) ,']
if active_rules['remove_punctuation']:
pairs = self.remove_punctuations(pairs)
return pairs
failures = []
sucess = []
for i in range(len(gold_label)):
gold_diction = self.create_diction(dataset[i]['token'], gold_label[i], tag='gold')
pred_diction = pred_dictions[i]
if gold_diction.keys() != pred_diction.keys() or set(v[0] for v in gold_diction.values()) != set(
v[0] for v in pred_diction.values()):
failures.append([gold_diction, pred_diction, dataset[i]['token'], dataset[i]['id']])
else:
sucess.append([gold_diction, pred_diction, dataset[i]['token'], dataset[i]['id']])
failure_ratio = 'Failures: {:.2%}'.format(len(failures) / len(dataset)) + '\n'
print(failure_ratio)
results += failure_ratio
return failures, sucess, results