# # dualloop # # File: matrix_preparation.py # # Authors: Deleted for purposes of anonymity # # Proprietor: Deleted for purposes of anonymity --- PROPRIETARY INFORMATION # # The software and its source code contain valuable trade secrets and shall be maintained in # confidence and treated as confidential information. The software may only be used for # evaluation and/or testing purposes, unless otherwise explicitly stated in the terms of a # license agreement or nondisclosure agreement with the proprietor of the software. # Any unauthorized publication, transfer to third parties, or duplication of the object or # source code---either totally or in part---is strictly prohibited. # # Copyright (c) 2019 Proprietor: Deleted for purposes of anonymity # All Rights Reserved. # # THE PROPRIETOR DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY # AND FITNESS FOR A PARTICULAR PURPOSE AND THE WARRANTY AGAINST LATENT # DEFECTS, WITH RESPECT TO THE PROGRAM AND ANY ACCOMPANYING DOCUMENTATION. # # NO LIABILITY FOR CONSEQUENTIAL DAMAGES: # IN NO EVENT SHALL THE PROPRIETOR OR ANY OF ITS SUBSIDIARIES BE # LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES # FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF INFORMATION, OR # OTHER PECUNIARY LOSS AND INDIRECT, CONSEQUENTIAL, INCIDENTAL, # ECONOMIC OR PUNITIVE DAMAGES) ARISING OUT OF THE USE OF OR INABILITY # TO USE THIS PROGRAM, EVEN IF the proprietor HAS BEEN ADVISED OF # THE POSSIBILITY OF SUCH DAMAGES. # # For purposes of anonymity, the identity of the proprietor is not given herewith. # The identity of the proprietor will be given once the review of the # conference submission is completed. # # THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. # import json import os import pickle import sys import time import pandas as pd import preprocessing as preprocess from snorkel.labeling import labeling_function from snorkel.labeling import PandasLFApplier import nltk nltk.download('wordnet') from fuzzywuzzy import fuzz import re import wordsegment wordsegment.load() from scipy import spatial import numpy as np import Levenshtein import textdistance ABSTAIN = -1 UNMATCHED = 0 MATCHED = 1 def read_config(config_file): with open(config_file, 'r') as f: config = json.load(f) return config # global list and map for ontologies source_ontology = [] target_ontology = [] def intersection(lst1, lst2): if lst1 == None or lst2 == None: return [] lst3 = [value for value in lst1 if value in lst2] return lst3 def calculate_cosine_similarity(s_embedding, t_embedding): if s_embedding is None or t_embedding is None: return None if len(s_embedding) == 0 or len(t_embedding) == 0: return None if np.count_nonzero(s_embedding) == 0 or np.count_nonzero(t_embedding) == 0: return None similarity = 1 - spatial.distance.cosine(s_embedding, t_embedding) return similarity @labeling_function() def LF_aml(row): if 'aml' not in row: return ABSTAIN return row.aml @labeling_function() def LF_logmap(row): if 'logmap' not in row: return ABSTAIN return row.logmap @labeling_function() def LF_yam(row): if 'yam' not in row: return ABSTAIN return row.yam @labeling_function() def LF_class_name_equal(row): x = int(row['x']) y = int(row['y']) source_class = source_ontology[x] target_class = target_ontology[y] if source_class.class_name.lower() == target_class.class_name.lower(): return MATCHED else: return ABSTAIN @labeling_function() def LF_class_name_stemmed_equal(row): x = int(row['x']) y = int(row['y']) source_class = source_ontology[x] target_class = target_ontology[y] if source_class.class_name_stemmed.lower() == target_class.class_name_stemmed.lower(): return MATCHED else: return ABSTAIN @labeling_function() def LF_acronyms(row): x = int(row['x']) y = int(row['y']) source_class = source_ontology[x] target_class = target_ontology[y] name_x = source_class.class_name name_y = target_class.class_name acro_x = source_class.acronym acro_y = target_class.acronym if name_x.lower() == acro_y.lower() or name_y.lower() == acro_x.lower(): return MATCHED else: return ABSTAIN @labeling_function() def LF_class_name_synonyms(row): x = int(row['x']) y = int(row['y']) source_class = source_ontology[x] target_class = target_ontology[y] a_class_synonyms = source_class.synonyms b_class_synonyms = target_class.synonyms if a_class_synonyms is None or b_class_synonyms is None: return ABSTAIN common = list(set(a_class_synonyms) & set(b_class_synonyms)) if len(common) > 0: return MATCHED return ABSTAIN @labeling_function() def LF_label_equal(row): x = int(row['x']) y = int(row['y']) source_class = source_ontology[x] target_class = target_ontology[y] if source_class.label == None or target_class.label == None: return ABSTAIN if source_class.label == '' or target_class.label == '': return ABSTAIN if source_class.label == target_class.label: return MATCHED else: return ABSTAIN @labeling_function() def LF_root_nouns_equal(row): x = int(row['x']) y = int(row['y']) source_class = source_ontology[x] target_class = target_ontology[y] if source_class.class_name_root == None or target_class.class_name_root == None: return ABSTAIN if source_class.class_name_root.lower() == target_class.class_name_root.lower() and fuzz.ratio( source_class.class_name_root, target_class.class_name_root) > 90: return MATCHED else: return ABSTAIN @labeling_function() def LF_class_name_distance(row): x = int(row['x']) y = int(row['y']) source_class = source_ontology[x] target_class = target_ontology[y] r = fuzz.ratio(source_class.class_name, target_class.class_name) if r > 90: return MATCHED if r < 30: return UNMATCHED else: return ABSTAIN @labeling_function() def LF_name_segment_overlap(row): x = int(row['x']) y = int(row['y']) source_class = source_ontology[x] target_class = target_ontology[y] if source_class.class_name_words == None or target_class.class_name_words == None: return ABSTAIN overlapset = intersection(source_class.class_name_words, target_class.class_name_words) if len(overlapset) >= 1: return MATCHED else: return ABSTAIN @labeling_function() def LF_label_words_overlap(row): x = int(row['x']) y = int(row['y']) source_class = source_ontology[x] target_class = target_ontology[y] if source_class.label_words == None or target_class.label_words == None: return ABSTAIN overlapset = intersection(source_class.label_words, target_class.label_words) if len(overlapset) >= 1: return MATCHED else: return ABSTAIN @labeling_function() def LF_subclasses_overlap(row): x = int(row['x']) y = int(row['y']) source_class = source_ontology[x] target_class = target_ontology[y] if source_class.subclasses == None or target_class.subclasses == None: return ABSTAIN overlapset = intersection(source_class.subclasses, target_class.subclasses) if len(overlapset) >= 1: return MATCHED else: return ABSTAIN @labeling_function() def LF_superclasses_overlap(row): x = int(row['x']) y = int(row['y']) source_class = source_ontology[x] target_class = target_ontology[y] if source_class.superclasses == None or target_class.superclasses == None: return ABSTAIN overlapset = intersection(source_class.superclasses, target_class.superclasses) if len(overlapset) >= 1: return MATCHED else: return ABSTAIN @labeling_function() def LF_properties_overlap(row): x = int(row['x']) y = int(row['y']) source_class = source_ontology[x] target_class = target_ontology[y] if source_class.properties == None or target_class.properties == None: return ABSTAIN overlapset = intersection(source_class.properties, target_class.properties) if len(overlapset) >= 1: return MATCHED else: return ABSTAIN @labeling_function() def LF_class_name_similarity(row): x = int(row['x']) y = int(row['y']) s = float(row['class_name_words_similarity_b']) if s == None: return ABSTAIN elif s > 0.95: return MATCHED elif s < 0.20: return UNMATCHED return ABSTAIN @labeling_function() def LF_label_similarity(row): x = int(row['x']) y = int(row['y']) s = float(row['label_words_similarity_b']) if s == None: return ABSTAIN elif s > 0.95: return MATCHED elif s < 0.20: return UNMATCHED return ABSTAIN @labeling_function() def LF_comment_similarity(row): x = int(row['x']) y = int(row['y']) s = float(row['comment_similarity_b']) if s == None: return ABSTAIN elif s > 0.95: return MATCHED elif s < 0.20: return UNMATCHED return ABSTAIN # calculate the distance between two strings def levenshtein_distance(string1, string2): return Levenshtein.distance(string1, string2) def hamming_distance(string1, string2): return textdistance.hamming.distance(string1, string2) def f_x1(row): x = int(row['x']) y = int(row['y']) source_class = source_ontology[x] target_class = target_ontology[y] source_class_name = source_class.class_name target_class_name = target_class.class_name return len(intersection(source_class_name, target_class_name)) def f_x2(row): x = int(row['x']) y = int(row['y']) source_class = source_ontology[x] target_class = target_ontology[y] source_class_name = source_class.class_name target_class_name = target_class.class_name return levenshtein_distance(source_class_name, target_class_name) def f_x3(row): x = int(row['x']) y = int(row['y']) source_class = source_ontology[x] target_class = target_ontology[y] source_class_name = source_class.class_name target_class_name = target_class.class_name return hamming_distance(source_class_name, target_class_name) # def f_x4(row): # x = int(row['x']) # y = int(row['y']) # source_class = source_ontology[x] # target_class = target_ontology[y] # # source_class_name = source_class.class_name # target_class_name = target_class.class_name # # sentence = '[CLS]' + source_class_name + '[SEP]' + target_class_name + '[SEP]' # # return sentence # def f_x5(row): # x = int(row['x']) # y = int(row['y']) # source_class = source_ontology[x] # target_class = target_ontology[y] # # return calculate_cosine_similarity(source_class.class_long_name_embedding, target_class.class_long_name_embedding) def apply_ffs(df, ffs): F = [] for feature_function in ffs: F.append(df.apply(feature_function, axis=1)) return pd.concat(F, axis=1).values lfs = [ LF_aml, LF_logmap, LF_yam, LF_class_name_equal, LF_class_name_stemmed_equal, LF_acronyms, LF_class_name_synonyms, LF_label_equal, LF_root_nouns_equal, LF_class_name_distance, LF_name_segment_overlap, LF_label_words_overlap, LF_subclasses_overlap, LF_superclasses_overlap, LF_properties_overlap, LF_class_name_similarity, LF_label_similarity, LF_comment_similarity ] if __name__ == '__main__': # Count the arguments arguments = len(sys.argv) - 1 if arguments < 1: print("please specify the data set [conference|ai4eu|nasa|anatomy]") exit() else: dataset_name = sys.argv[1] blocked_df = pd.read_csv('./results/' + dataset_name + '/' + dataset_name + '_blocked_top_k.csv') source_ontology = pickle.load(open('./results/' + dataset_name + '/' + dataset_name + "_source_ontology.pk", "rb")) target_ontology = pickle.load(open('./results/' + dataset_name + '/' + dataset_name + "_target_ontology.pk", "rb")) # take the existing features into the initial dataframe existing_features = ['x', 'y', 'label', 'aml', 'logmap', 'yam', 'num_common_words', 'class_name_words_similarity_a', 'class_name_words_similarity_b', 'label_words_similarity_a', 'label_words_similarity_b', 'comment_similarity_a', 'comment_similarity_b'] my_init_df = blocked_df[existing_features] # apply all labeling functions to get the label matrix start = time.time() applier = PandasLFApplier(lfs=lfs) label_matrix = applier.apply(df=blocked_df) end = time.time() print("Labeling Time: ", end - start, "s") # convert label matrix to dataframe label_columns = [lf.name for lf in lfs] my_label_df = pd.DataFrame(data=label_matrix, columns=label_columns) # my_label_df['label'] = blocked_df.label.values # my_label_df['x'] = blocked_df.x.values # my_label_df['y'] = blocked_df.y.values # prepare the feature dataframe with the extra features feature_functions = [f_x1, f_x2, f_x3] feature_columns = ['shared_word', 'levenshtein_distance', 'hamming_distance'] start = time.time() feature_matrix = apply_ffs(blocked_df, feature_functions) my_new_feature_df = pd.DataFrame(data=feature_matrix, columns=feature_columns) end = time.time() print("Feature Generation Time: ", end - start, "s") # merge the feature and label dataframe dfs = [my_init_df, my_label_df, my_new_feature_df] combined_dfs = pd.concat(dfs, axis=1) # make sure the result folder is created if not os.path.exists('./results/' + dataset_name): os.makedirs('./results/' + dataset_name) # save the dataframe combined_dfs.to_csv('./results/' + dataset_name + '/' + dataset_name + '_matrix.csv', index=False, header=True)