the_one_that_does_it.py 4.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. # %%
  2. import csv
  3. import json
  4. import openpyxl as op
  5. # BASIC CONFIGURATION
  6. DATA_FOLDER = './data/'
  7. OUTPUT_FOLDER = './output/'
  8. ONTO_FILENAME = 'manoscritti_dariah' # No extension!
  9. ent_filename = ONTO_FILENAME + '_entities.csv'
  10. rel_filename = ONTO_FILENAME + '_relations.csv'
  11. # PART I: parse xlsx to (multiple) csv
  12. # Excel configuration
  13. XLSX_FILENAME = 'Struttura_NEW.xlsx'
  14. ENTITIES_SHEETNAME = 'Entità'
  15. RELATIONS_SHEETNAME = 'Relazioni'
  16. # %%
  17. # Import the defining xlsx through openpyxl
  18. input_data = op.load_workbook(DATA_FOLDER + XLSX_FILENAME)
  19. # Read relevant sheets
  20. entities_sheet = input_data[ENTITIES_SHEETNAME]
  21. relations_sheet = input_data[RELATIONS_SHEETNAME]
  22. # Parse sheet data into a dict (assuming the xlsx has headers)
  23. entities_keys = [cell for cell in next(entities_sheet.values) if cell]
  24. raw_entities = [{key: row[ind] for ind, key in enumerate(entities_keys)} for row in entities_sheet.values][1:]
  25. #
  26. relations_keys = [cell for cell in next(relations_sheet.values) if cell]
  27. raw_relations = [{key: row[ind] for ind, key in enumerate(relations_keys)} for row in relations_sheet.values][1:]
  28. # %%
  29. # NOTE:
  30. # a. Non ci sono, al momento, constraint di unicità imposti tramite il "foglio master"
  31. # b. Non ci sono neanche constraint di esistenza, TRANNE l'id univoca, intesa NON come quella del sistema ma quella della comunità di riferimento, e tipica del settore di dominio considerato
  32. # c. Per identificare le informazioni 'atomiche' non si usa un campo dedicato, ma una logica. AL MOMENTO la logica è che si considera atomica una entità che non è mai 'prima' in una relazione. L'ORDINE DELLE RELAZIONI E' IMPORTANTE a differenza di quanto assumevo inizialmente.
  33. # d. Si effettua un controllo di unicità sulle entità, basato sul nome normalizzato (parole con iniziale maiuscola e il resto minuscolo, spazi ridotti a spazio singolo, strip()). Nessuna entità può avere nome vuoto.
  34. # e. Si effettua un controllo di unicità sulle relazioni, che però riguarda tutta la terna SOGGETTO-RELAZIONE-OGGETTO (normalizzata in modo simile ai nomi di entità, ma nella RELAZIONE gli spazi sono underscores e si usa lower() invece che title()). Nessuno dei membri della terna può essere vuoto, il nome della relazione inversa è opzionale.
  35. # f. Si effettuano controlli di consistenza sulle relazioni:
  36. # .f1. Nessuna relazione con entità non definite
  37. # .f2. Nessuna entità "orfana", ovvero non presente in alcuna relazione
  38. #
  39. # TODO: completare secondo le specifiche sopra
  40. # TODO: effettuare il merge con i "miei" CSV, che hanno informazioni in più!
  41. # Process entities:
  42. # 1. Filter out unnamed entities, find out aliases, normalize entity names, find out duplicates
  43. clean_entities = {}
  44. for ent in raw_entities:
  45. entity_names = ent['Concetto']
  46. if not isinstance(entity_names, str):
  47. continue
  48. aliases = [al.strip().title() for al in entity_names.split('\n') if al.strip()]
  49. if not aliases:
  50. continue
  51. entity_name = aliases[0]
  52. entity_same_as = aliases[1:]
  53. if clean_entities.get(entity_name):
  54. # DUPLICATE!
  55. clean_entities[entity_name].append({'Alias': aliases, 'Raw': ent})
  56. else:
  57. clean_entities[entity_name] = [{'Alias': aliases, 'Raw': ent}]
  58. all_entities = clean_entities.keys()
  59. duplicated_entities = [ent_name for ent_name, ent_val in clean_entities.items() if len(ent_val)>1]
  60. # %%
  61. # Process relations:
  62. # 1. Filter ill-formed relations and normalize entity names
  63. clean_relations = []
  64. for rel in raw_relations:
  65. subj = rel['Soggetto']
  66. obj = rel['Oggetto']
  67. if not isinstance(subj, str) or not isinstance(obj, str):
  68. continue
  69. subj = subj.strip().title()
  70. obj = obj.strip().title()
  71. if subj==obj:
  72. continue
  73. rel_name = rel['Relazione']
  74. if isinstance(rel_name, str):
  75. rel_name = rel_name.strip().lower()
  76. better_rel = {'Soggetto': subj, 'Relazione': rel_name, 'Oggetto': obj, 'Pair': tuple(set([subj, obj]))}
  77. clean_relations.append(better_rel)
  78. all_pairs = [rel['Pair'] for rel in clean_relations]
  79. all_cited_entities = set(sum([[rel['Soggetto'], rel['Oggetto']] for rel in clean_relations], []))
  80. undefined_entities = all_cited_entities - all_entities
  81. # %%