658 lines
22 KiB
Python
658 lines
22 KiB
Python
import re
|
||
import unicodedata
|
||
import html
|
||
from unidecode import unidecode
|
||
import json
|
||
from sklearn.feature_extraction.text import CountVectorizer
|
||
from sklearn.metrics.pairwise import cosine_similarity
|
||
#import pandas as pd
|
||
|
||
def load_txt(file_path):
|
||
with open(file_path, 'r', encoding='utf-8') as file:
|
||
list_ = [line.strip() for line in file]
|
||
return list_
|
||
|
||
|
||
def load_json(file_path):
|
||
with open(file_path, 'r') as json_file:
|
||
json_dict = json.load(json_file)
|
||
return json_dict
|
||
|
||
categ_string = 'Laboratory|Univ/Inst|Hospital|Foundation|Specific|Museum'
|
||
|
||
def replace_double_consonants(text):
|
||
# This regex pattern matches any double consonant
|
||
pattern = r'([bcdfghjklmnpqrstvwxyz])\1'
|
||
# The replacement is the first captured group (the single consonant)
|
||
result = re.sub(pattern, r'\1', text, flags=re.IGNORECASE)
|
||
return result
|
||
|
||
remove_list = [replace_double_consonants(x) for x in load_txt('remove_list.txt')]
|
||
stop_words = load_txt('stop_words.txt')
|
||
university_terms = [replace_double_consonants(x) for x in load_txt('university_terms.txt')]
|
||
city_names = [replace_double_consonants(x) for x in load_txt('city_names.txt')]
|
||
|
||
categ_dicts = load_json('dix_categ.json')
|
||
|
||
|
||
def is_contained(s, w):
|
||
words = s.split() # Split the string 's' into a list of words
|
||
for word in words:
|
||
if word not in w: # If a word from 's' is not found in 'w'
|
||
return False # Return False immediately
|
||
return True # If all words from 's' are found in 'w', return True
|
||
|
||
def starts_with_any(string, prefixes):
|
||
for prefix in prefixes:
|
||
if string.startswith(prefix):
|
||
return [True, prefix]
|
||
return False
|
||
|
||
def remove_leading_numbers(s):
|
||
return re.sub(r'^\d+', '', s)
|
||
|
||
def remove_outer_parentheses(string):
|
||
"""Remove outer parentheses from the string if they enclose the entire string."""
|
||
if string.startswith('(') and string.endswith(')'):
|
||
return string[1:-1].strip()
|
||
return string
|
||
|
||
|
||
def insert_space_between_lower_and_upper(s):
|
||
"""
|
||
Inserts a space between a lowercase letter followed by an uppercase letter in a string.
|
||
|
||
Parameters:
|
||
s (str): The input string.
|
||
|
||
Returns:
|
||
str: The modified string with spaces inserted.
|
||
"""
|
||
# Use regex to insert space between lowercase and uppercase letters
|
||
modified_string = re.sub(r'([a-z])([A-Z])', r'\1 \2', s)
|
||
return modified_string
|
||
|
||
|
||
def index_multiple_matchings(pairs):
|
||
result_dict = {}
|
||
|
||
r_list = [pair[3] for pair in pairs]
|
||
modified_list = [item for sublist in r_list for item in sublist]
|
||
r = len(list(set(modified_list)))
|
||
|
||
for t in [pair[0] for pair in pairs]:
|
||
key = t
|
||
if key in result_dict and r>1:
|
||
result_dict[key] += 1
|
||
|
||
else:
|
||
result_dict[key] = 1
|
||
|
||
return result_dict
|
||
|
||
def avg_string(df, col):
|
||
avg = []
|
||
for i in range(len(df)):
|
||
avg.append(sum(len(s) for s in df[col].iloc[i])/len(df[col].iloc[i]))
|
||
return sum(avg)/len(avg)
|
||
|
||
#stop_words = ['from', 'the', 'of', 'at', 'de','for','et','für','des', 'in','as','a','and','fur','for','und']
|
||
|
||
|
||
def remove_stop_words(text):
|
||
words = text.split()
|
||
filtered_words = [word for word in words if word not in stop_words]
|
||
return ' '.join(filtered_words)
|
||
|
||
|
||
def remove_parentheses(text):
|
||
return re.sub(r'\([^()]*\)', '', text)
|
||
|
||
|
||
# def replace_umlauts(text):
|
||
# normalized_text = unicodedata.normalize('NFKD', text)
|
||
# replaced_text = ''.join(c for c in normalized_text if not unicodedata.combining(c))
|
||
# return replaced_text
|
||
|
||
def protect_phrases(input_string, phrases):
|
||
# Replace phrases with placeholders
|
||
placeholder_map = {}
|
||
for i, phrase in enumerate(phrases):
|
||
placeholder = f"__PLACEHOLDER_{i}__"
|
||
placeholder_map[placeholder] = phrase
|
||
input_string = input_string.replace(phrase, placeholder)
|
||
return input_string, placeholder_map
|
||
|
||
def restore_phrases(split_strings, placeholder_map):
|
||
# Restore placeholders with original phrases
|
||
restored_strings = []
|
||
for s in split_strings:
|
||
for placeholder, phrase in placeholder_map.items():
|
||
s = s.replace(placeholder, phrase)
|
||
restored_strings.append(s)
|
||
return restored_strings
|
||
|
||
def replace_comma_spaces(text):
|
||
return text.replace(' ', ' ').replace(' , ', ', ')
|
||
|
||
def split_string_with_protection(input_string, protected_phrases):
|
||
# Step 1: Protect specific phrases
|
||
input_string, placeholder_map = protect_phrases(input_string, protected_phrases)
|
||
|
||
# Step 2: Split the string on specified delimiters
|
||
split_strings = [s.strip() for s in re.split(r'[,;/]| – ', input_string) if s.strip()]
|
||
|
||
# Step 3: Restore protected phrases
|
||
split_strings = restore_phrases(split_strings, placeholder_map)
|
||
|
||
return split_strings
|
||
|
||
protected_phrases1 = [
|
||
phrase.format(x=x)
|
||
for x in city_names
|
||
for phrase in [
|
||
'university california, {x}',
|
||
# 'university california , {x}',
|
||
|
||
'university colege hospital, {x}',
|
||
# 'university colege hospital , {x}',
|
||
|
||
'national univ ireland, {x}',
|
||
# 'national univ ireland , {x}',
|
||
|
||
'national university ireland, {x}',
|
||
# 'national university ireland , {x}',
|
||
|
||
'university colege, {x}',
|
||
# 'university colege , {x}',
|
||
|
||
'university hospital, {x}',
|
||
# 'university hospital , {x}',
|
||
|
||
'imperial colege, {x}',
|
||
# 'imperial colege , {x}'
|
||
|
||
'city university, {x}',
|
||
# 'city university , {x}'
|
||
|
||
|
||
]
|
||
]
|
||
|
||
|
||
|
||
replacements = {'czechoslovak':'czech',
|
||
'saint' : 'st',
|
||
'aghia' : 'agia',
|
||
'universitatsklinikum' : 'universi hospital',
|
||
'universitetshospital' : 'universi hospital',
|
||
'universitatskinderklinik' : 'universi childrens hospital',
|
||
'universitatskliniken' : 'universi hospital',
|
||
'Universitätsklinik' : 'universi hospital',
|
||
'universitatsmedizin' : 'universi medicine',
|
||
'universitatsbibliothek' : 'universi library',
|
||
'nat.' : 'national',
|
||
'uni versity' : 'university',
|
||
'unive rsity' : 'university',
|
||
'univ ersity' : 'university',
|
||
'inst ' : 'institute ',
|
||
'adv ' : 'advanced ',
|
||
'univ ' : 'university ',
|
||
'stud ' : 'studies ',
|
||
'inst.' : 'institute',
|
||
'adv.' : 'advanced',
|
||
'univ.' : 'university',
|
||
'stud.' : 'studies',
|
||
'univercity' : 'university',
|
||
'univerisity' : 'university',
|
||
'universtiy' : 'university',
|
||
'univeristy' : 'university',
|
||
'universirty' : 'university',
|
||
'universiti' : 'university',
|
||
'universitiy' : 'university',
|
||
'universty' : 'university',
|
||
'techniche' : 'technological',
|
||
'univ col' : 'university colege',
|
||
'univ. col.' : 'university colege',
|
||
'univ. coll.' : 'university colege',
|
||
'col.' : 'colege',
|
||
'hipokration' : 'hipocration',
|
||
'belfield, dublin' : 'dublin',
|
||
'balsbridge, dublin' : 'dublin', #ballsbridge
|
||
'earlsfort terrace, dublin' : 'dublin',
|
||
'bon secours hospital, cork' : 'bon secours hospital cork',
|
||
'bon secours hospital, dublin' : 'bon secours hospital dublin',
|
||
'bon secours hospital, galway' : 'bon secours hospital galway',
|
||
'bon secours hospital, tralee' : 'bon secours hospital tralee',
|
||
'bon secours health system' : 'bon secours hospital dublin',
|
||
'bon secours hospital, glasnevin' : 'bon secours hospital dublin',
|
||
'imperial colege science, technology medicine' : 'imperial colege science technology medicine',
|
||
'ucl queen square institute neurology' : 'ucl, london',
|
||
'ucl institute neurology' : 'ucl, london',
|
||
'royal holoway, university london' : 'royal holoway universi london', #holloway
|
||
'city, university london' : 'city universi london',
|
||
'city university, london' : 'city universi london',
|
||
'aeginition' : 'eginition',
|
||
'national technical university, athens' : 'national technical university athens'
|
||
# 'harvard medical school' : 'harvard university'
|
||
|
||
|
||
|
||
}
|
||
|
||
|
||
def substrings_dict(string):
|
||
# Split the input string and clean each substring
|
||
# split_strings = split_string_with_protection(string.replace('univ coll', 'university college').replace('belfield, dublin', 'dublin').replace('ballsbridge, dublin', 'dublin').replace('earlsfort Terrace, dublin', 'dublin'), protected_phrases1)
|
||
|
||
for old, new in replacements.items():
|
||
string = string.replace(old, new)
|
||
string = string.replace('hospitalum','hospital').replace('hospitalen','hospital')
|
||
split_strings = split_string_with_protection(string, protected_phrases1)
|
||
|
||
# Define a set of university-related terms for later use
|
||
|
||
|
||
dict_string = {}
|
||
index = 0
|
||
for value in split_strings:
|
||
value = value.replace('.', ' ')
|
||
# Check if the substring contains any university-related terms
|
||
if not any(term in value.lower() for term in university_terms):
|
||
# Apply regex substitutions for common patterns
|
||
|
||
modified_value = re.sub(r'universi\w*', 'universi', value, flags=re.IGNORECASE)
|
||
modified_value = re.sub(r'institu\w*', 'institu', modified_value, flags=re.IGNORECASE)
|
||
modified_value = re.sub(r'centre\b', 'center', modified_value, flags=re.IGNORECASE)
|
||
modified_value = re.sub(r'\bsaint\b', 'st', modified_value, flags=re.IGNORECASE)
|
||
modified_value = re.sub(r'\btrinity col\b', 'trinity colege', modified_value, flags=re.IGNORECASE)
|
||
modified_value = re.sub(r'\btechnische\b', 'technological', modified_value, flags=re.IGNORECASE)
|
||
modified_value = re.sub(r'\bteknologi\b', 'technology', modified_value, flags=re.IGNORECASE)
|
||
modified_value = re.sub(r'\bpolitehnica\b', 'polytechnic', modified_value, flags=re.IGNORECASE)
|
||
|
||
|
||
|
||
# Add the modified substring to the dictionary
|
||
|
||
dict_string[index] = modified_value.lower().strip()
|
||
index += 1
|
||
# elif 'universitetskaya' in value.lower():
|
||
# index += 1
|
||
|
||
|
||
# Add the original substring to the dictionary
|
||
else:
|
||
dict_string[index] = value.lower().strip()
|
||
index += 1
|
||
|
||
return dict_string
|
||
|
||
|
||
|
||
def clean_string(input_string):
|
||
# Temporarily replace " - " with a unique placeholder
|
||
placeholder = "placeholder"
|
||
# input_string = input_string.replace(" - ", placeholder)
|
||
input_string = input_string.replace(" – ", placeholder)
|
||
|
||
# Unescape HTML entities and convert to lowercase
|
||
input_string = replace_comma_spaces(replace_double_consonants(unidecode(remove_parentheses(html.unescape(input_string.replace(" ́e","e").replace("'", ""))))).strip())
|
||
|
||
|
||
# Replace `–` with space (do not replace hyphen `-`)
|
||
result = re.sub(r'[\-]', ' ', input_string)
|
||
|
||
# Replace "saint" with "st"
|
||
result = re.sub(r'\bSaint\b', 'St', result)
|
||
result = re.sub(r'\bAghia\b', 'Agia', result)
|
||
result = re.sub(r'\bAghios\b', 'Agios', result)
|
||
|
||
|
||
# Remove characters that are not from the Latin alphabet, or allowed punctuation
|
||
result = replace_comma_spaces(re.sub(r'[^a-zA-Z\s,;/.]', '', result).strip())
|
||
|
||
# Restore the " - " sequence from the placeholder
|
||
result = result.replace(placeholder, " – ")
|
||
|
||
# Replace consecutive whitespace with a single space
|
||
result = re.sub(r'\s+', ' ', result)
|
||
#result = result.replace('ss', 's')
|
||
|
||
result = insert_space_between_lower_and_upper(result).lower()
|
||
result = remove_stop_words(result)
|
||
|
||
return result.strip() # Strip leading/trailing spaces
|
||
|
||
|
||
def clean_string_facts(input_string):
|
||
# Replace specified characters with space
|
||
input_string = remove_stop_words(unidecode(remove_parentheses(html.unescape(input_string.lower()))))
|
||
result = re.sub(r'[/\-,]', ' ', input_string)
|
||
result = re.sub(r'\bsaint\b', 'st', result)
|
||
|
||
# Remove characters that are not from the Latin alphabet or numbers
|
||
result = re.sub(r'[^a-zA-Z0-9\s;/-.]', '', result)
|
||
|
||
# Replace consecutive whitespace with a single space
|
||
result = re.sub(r'\s+', ' ', result)
|
||
|
||
return result
|
||
|
||
|
||
def str_radius_u(string):
|
||
string = string.lower()
|
||
radius = 3
|
||
|
||
str_list = string.split()
|
||
indices = []
|
||
result = []
|
||
|
||
for i, x in enumerate(str_list):
|
||
if is_contained('univers',x):
|
||
indices.append(i)
|
||
# elif is_contained('coll',x):
|
||
# indices.append(i)
|
||
|
||
for r0 in indices:
|
||
lmin =max(0,r0-radius)
|
||
lmax =min(r0+radius, len(str_list))
|
||
s = str_list[lmin:lmax+1]
|
||
|
||
result.append(' '.join(s))
|
||
|
||
return result
|
||
|
||
|
||
def str_radius_coll(string):
|
||
string = string.lower()
|
||
radius = 1
|
||
|
||
str_list = string.split()
|
||
indices = []
|
||
result = []
|
||
|
||
for i, x in enumerate(str_list):
|
||
if is_contained('col',x):
|
||
indices.append(i)
|
||
|
||
for r0 in indices:
|
||
lmin =max(0,r0-radius)
|
||
lmax =min(r0+radius, len(str_list))
|
||
s = str_list[lmin:lmax]
|
||
|
||
result.append(' '.join(s))
|
||
|
||
return result
|
||
|
||
|
||
def str_radius_h(string):
|
||
string = string.lower()
|
||
radius = 3
|
||
|
||
str_list = string.split()
|
||
indices = []
|
||
result = []
|
||
|
||
for i, x in enumerate(str_list):
|
||
if is_contained('hospital',x) or is_contained('hopita',x):
|
||
indices.append(i)
|
||
|
||
for r0 in indices:
|
||
lmin =max(0,r0-radius-1)
|
||
lmax =min(r0+radius, len(str_list))
|
||
s = str_list[lmin:lmax]
|
||
|
||
result.append(' '.join(s))
|
||
|
||
return result
|
||
|
||
|
||
def str_radius_c(string):
|
||
string = string.lower()
|
||
radius = 2
|
||
|
||
str_list = string.split()
|
||
indices = []
|
||
result = []
|
||
|
||
for i, x in enumerate(str_list):
|
||
if is_contained('clinic',x) or is_contained('klinik',x):
|
||
indices.append(i)
|
||
|
||
for r0 in indices:
|
||
lmin =max(0,r0-radius-1)
|
||
lmax =min(r0+radius, len(str_list))
|
||
s = str_list[lmin:lmax]
|
||
|
||
result.append(' '.join(s))
|
||
|
||
return result
|
||
|
||
def str_radius_r(string):
|
||
string = string.lower()
|
||
radius = 2
|
||
|
||
str_list = string.split()
|
||
indices = []
|
||
result = []
|
||
|
||
for i, x in enumerate(str_list):
|
||
if is_contained('research',x):
|
||
indices.append(i)
|
||
|
||
for r0 in indices:
|
||
lmin =max(0,r0-radius-1)
|
||
lmax =min(r0+radius, len(str_list))
|
||
s = str_list[lmin:lmax]
|
||
|
||
result.append(' '.join(s))
|
||
|
||
return result
|
||
|
||
def str_radius_spec(string):
|
||
spec = False
|
||
for x in string.split():
|
||
try:
|
||
if categ_dicts[x] == 'Specific':
|
||
spec = True
|
||
return x
|
||
except:
|
||
pass
|
||
if spec == False:
|
||
return string
|
||
|
||
|
||
def avg_string(df, col):
|
||
avg = []
|
||
for i in range(len(df)):
|
||
avg.append(sum(len(s) for s in df[col].iloc[i])/len(df[col].iloc[i]))
|
||
return sum(avg)/len(avg)
|
||
|
||
|
||
|
||
|
||
|
||
def shorten_keywords(affiliations_simple):
|
||
affiliations_simple_n = []
|
||
|
||
for aff in affiliations_simple:
|
||
inner = []
|
||
for str in aff:
|
||
if 'universi' in str:
|
||
inner.extend(str_radius_u(str))
|
||
elif 'col' in str and 'trinity' in str:
|
||
inner.extend(str_radius_coll(str))
|
||
elif 'hospital' in str or 'hopita' in str:
|
||
inner.extend(str_radius_h(str))
|
||
elif 'clinic' in str or 'klinik' in str:
|
||
inner.extend(str_radius_c(str))
|
||
elif 'research council' in str:
|
||
inner.extend(str_radius_r(str))
|
||
else:
|
||
inner.append(str_radius_spec(str))
|
||
|
||
affiliations_simple_n.append(inner)
|
||
|
||
return affiliations_simple_n
|
||
|
||
def shorten_keywords_spark(affiliations_simple):
|
||
affiliations_simple_n = []
|
||
|
||
for aff in affiliations_simple:
|
||
|
||
if 'universi' in aff:
|
||
affiliations_simple_n.extend(str_radius_u(aff))
|
||
elif 'col' in aff and 'trinity' in aff:
|
||
affiliations_simple_n.extend(str_radius_coll(aff))
|
||
elif 'hospital' in aff or 'hopita' in aff:
|
||
affiliations_simple_n.extend(str_radius_h(aff))
|
||
elif 'clinic' in aff or 'klinik' in aff:
|
||
affiliations_simple_n.extend(str_radius_c(aff))
|
||
elif 'research council' in aff:
|
||
affiliations_simple_n.extend(str_radius_r(aff))
|
||
else:
|
||
affiliations_simple_n.append(str_radius_spec(aff))
|
||
|
||
|
||
return affiliations_simple_n
|
||
|
||
|
||
def refine(list_, affil):
|
||
affil = affil.lower()
|
||
|
||
ids = []
|
||
|
||
for matched_org_list in list_:
|
||
|
||
id_list = []
|
||
|
||
for matched_org in matched_org_list:
|
||
|
||
if dix_mult[matched_org] == 'unique':
|
||
id_list.append(dix_acad[matched_org])
|
||
else:
|
||
city_found = False
|
||
for city in dix_city[matched_org]:
|
||
if city[0] in affil:
|
||
id_list.append(city[1])
|
||
city_found = True
|
||
break
|
||
|
||
if not city_found:
|
||
country_found = False
|
||
|
||
for country in dix_country[matched_org]:
|
||
if country[0] in list(country_mapping.keys()):
|
||
print(country[0])
|
||
if country[0] in affil or country_mapping[country[0]][0] in affil or country_mapping[country[0]][0] in affil:
|
||
id_list.append(country[1])
|
||
country_found = True
|
||
break
|
||
|
||
|
||
|
||
elif country[0] in affil:
|
||
print('country found',country[0])
|
||
|
||
id_list.append(country[1])
|
||
country_found = True
|
||
break
|
||
|
||
|
||
|
||
if not country_found:
|
||
id_list.append(dix_acad[matched_org])
|
||
|
||
|
||
|
||
ids.append(id_list)
|
||
return ids
|
||
|
||
def compute_cos(x,s):
|
||
vectorizer = CountVectorizer()
|
||
|
||
s_vector = vectorizer.fit_transform([s]).toarray() #Else we compute the similarity of s with the original affiiation name
|
||
x_vector = vectorizer.transform([x]).toarray()
|
||
|
||
# Compute similarity between the vectors
|
||
return cosine_similarity(x_vector, s_vector)[0][0]
|
||
|
||
|
||
# def find_ror(string, simU, simG):
|
||
# df = pd.DataFrame()
|
||
|
||
# df['Unique affiliations'] = [[string.lower()]]
|
||
# academia = create_df_algorithm(df)
|
||
|
||
|
||
# result = Aff_Ids(len(academia), academia,dix_acad, dix_mult, dix_city, dix_country, simU,simG)
|
||
# if len(result)>0:
|
||
|
||
# dict_aff_open = {x: y for x, y in zip(result['Original affiliations'], result['Matched organizations'])}
|
||
# dict_aff_id = {x: y for x, y in zip(result['Original affiliations'], result['unique ROR'])}
|
||
|
||
# dict_aff_score = {}
|
||
# for i in range(len(result)):
|
||
# if type(result['Similarity score'].iloc[i]) == list:
|
||
# dict_aff_score[result['Original affiliations'].iloc[i]] = result['Similarity score'].iloc[i]
|
||
# else:
|
||
# dict_aff_score[result['Original affiliations'].iloc[i]] = [result['Similarity score'].iloc[i]]
|
||
|
||
|
||
# pids = []
|
||
# for i in range(len(df)):
|
||
# pidsi = []
|
||
# for aff in df['Unique affiliations'].iloc[i]:
|
||
# if aff in list(dict_aff_id.keys()):
|
||
# pidsi = pidsi + dict_aff_id[aff]
|
||
# # elif 'unmatched organization(s)' not in pidsi:
|
||
# # pidsi = pidsi + ['unmatched organization(s)']
|
||
# pids.append(pidsi)
|
||
|
||
|
||
# names = []
|
||
# for i in range(len(df)):
|
||
# namesi = []
|
||
# for aff in df['Unique affiliations'].iloc[i]:
|
||
# if aff in list(dict_aff_open.keys()):
|
||
# try:
|
||
# namesi = namesi + dict_aff_open[aff]
|
||
# except TypeError:
|
||
# namesi = namesi + [dict_aff_open[aff]]
|
||
|
||
# names.append(namesi)
|
||
|
||
# scores = []
|
||
# for i in range(len(df)):
|
||
# scoresi = []
|
||
# for aff in df['Unique affiliations'].iloc[i]:
|
||
# if aff in list(dict_aff_score.keys()):
|
||
# scoresi = scoresi + dict_aff_score[aff]
|
||
|
||
# scores.append(scoresi)
|
||
|
||
|
||
# df['Matched organizations'] = names
|
||
# df['ROR'] = pids
|
||
# df['Scores'] = scores
|
||
|
||
|
||
|
||
# def update_Z(row):
|
||
# if len(row['ROR']) == 0 or len(row['Scores']) == 0:
|
||
# return []
|
||
|
||
# new_Z = []
|
||
# for ror, score in zip(row['ROR'], row['Scores']):
|
||
# entry = {'ROR_ID': ror, 'Confidence': score}
|
||
# new_Z.append(entry)
|
||
# return new_Z
|
||
|
||
# matching = df.apply(update_Z, axis=1)
|
||
|
||
# df['Matchings'] = matching
|
||
|
||
|
||
# return df['Matchings'].iloc[0]
|
||
# else:
|
||
# return 'no result' |