DEMNE 1.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. demne/REST_interface/README.md +49 -0
  2. demne/REST_interface/REST.ipynb +153 -0
  3. demne/REST_interface/REST_modules/__init__.py +5 -0
  4. demne/REST_interface/REST_modules/calculs/__init__.py +8 -0
  5. demne/REST_interface/REST_modules/calculs/bootstrap.py +140 -0
  6. demne/REST_interface/REST_modules/calculs/concordancer.py +138 -0
  7. demne/REST_interface/REST_modules/calculs/metrics.py +492 -0
  8. demne/REST_interface/REST_modules/calculs/ngram.py +103 -0
  9. demne/REST_interface/REST_modules/calculs/recommendations.py +204 -0
  10. demne/REST_interface/REST_modules/calculs/regex.py +158 -0
  11. demne/REST_interface/REST_modules/calculs/results.py +136 -0
  12. demne/REST_interface/REST_modules/calculs/tfidf.py +163 -0
  13. demne/REST_interface/REST_modules/categorization.py +94 -0
  14. demne/REST_interface/REST_modules/extraction/__init__.py +3 -0
  15. demne/REST_interface/REST_modules/extraction/brat.py +302 -0
  16. demne/REST_interface/REST_modules/extraction/normalisation.py +312 -0
  17. demne/REST_interface/REST_modules/extraction/saving.py +84 -0
  18. demne/REST_interface/REST_modules/initialization.py +177 -0
  19. demne/REST_interface/REST_modules/loading.py +67 -0
  20. demne/REST_interface/REST_modules/ui.py +1064 -0
  21. demne/REST_interface/REST_modules/visualization.py +177 -0
  22. demne/REST_interface/__init__.py +13 -0
  23. demne/REST_interface/convergence_analyzer.py +68 -0
  24. demne/REST_interface/demo_rest.py +98 -0
  25. demne/REST_interface/logo.png +0 -0
  26. demne/REST_interface/rest_annotator.py +157 -0
  27. demne/REST_interface/rest_decision_bridge.py +88 -0
  28. demne/REST_interface/rest_evaluator.py +100 -0
  29. demne/REST_interface/rest_pipeline.py +35 -0
  30. demne/REST_interface/templates/annotation_template.html +30 -0
  31. demne/REST_interface/templates/evaluation_form.html +19 -0
  32. demne/REST_interface/templates/results_dashboard.html +14 -0
  33. demne/__init__.py +29 -0
  34. demne/_brat.py +154 -0
  35. demne/_table.py +28 -0
  36. demne/_tracking.py +59 -0
  37. demne/cli.py +27 -0
  38. demne/data/demne_params.json +57 -0
  39. demne/decision_tree_builder.py +351 -0
  40. demne/frequency.py +200 -0
  41. demne/homogeneity.py +241 -0
  42. demne/ner_feasibility.py +109 -0
  43. demne/optimize_params.py +1130 -0
  44. demne/params.py +177 -0
  45. demne/py.typed +0 -0
  46. demne/risk_context.py +394 -0
  47. demne/routing.py +113 -0
  48. demne/templatability.py +270 -0
  49. demne/tfidf_coverage.py +186 -0
  50. demne/visualize_decision_tree.py +110 -0
  51. demne-1.3.0.dist-info/METADATA +201 -0
  52. demne-1.3.0.dist-info/RECORD +56 -0
  53. demne-1.3.0.dist-info/WHEEL +5 -0
  54. demne-1.3.0.dist-info/entry_points.txt +2 -0
  55. demne-1.3.0.dist-info/licenses/LICENSE +18 -0
  56. demne-1.3.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,49 @@
1
+
2
+ ![Logo](logo.png)
3
+
4
+
5
+ # REST-interface
6
+
7
+ REST is a jupyter interface that helps the user to assess the application of rules-based method, regarding entities of interest highlighted in a corpus.
8
+
9
+ In information extraction tasks, both machine learning and rules are available methods. Although the two processes are well-known and used, there is no obvious way or good practice to decide which one is the most appropriate for each project.
10
+
11
+ Using highlights from the BRAT annotation tool, REST is part of an approach to evaluate a rules-based system quickly.
12
+
13
+
14
+
15
+
16
+
17
+
18
+ ## Video presentation
19
+
20
+ An explanation of REST-interface is available here :
21
+ [Video presentation](https://vimeo.com/1005460293?share=copy)
22
+
23
+
24
+ ## Getting started
25
+
26
+ ### 1. Clone the Repository
27
+
28
+ First, clone the repository to your local machine:
29
+ ```bash
30
+ git clone https://github.com/GuiGuiBazin/REST-interface.git
31
+ ```
32
+ ### 2. Install Dependencies
33
+ Install the required packages listed in requirements.txt:
34
+ ```bash
35
+ pip install -r requirements.txt
36
+ ```
37
+ ### 3. Download the spaCy Model
38
+ Download the spaCy model required by the project:
39
+ ```bash
40
+ python -m spacy download fr_core_news_sm
41
+ ```
42
+
43
+ ### Notes:
44
+ - Spacy model download is absolutly necessary for the current version of REST. More models for other languages will be integrated in later updates.
45
+ - If you encounter any issues with dependencies, check that your environment matches the versions specified in requirements.txt.
46
+ ## Acknowledgements
47
+
48
+ I would like to thank Emmanuelle Kempf and Xavier Tannier for supervising this project.
49
+
@@ -0,0 +1,153 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "f3f05c88",
6
+ "metadata": {},
7
+ "source": [
8
+ "# REST Interface\n",
9
+ "## Introduction\n",
10
+ "This notebook launches the REST interface, which evaluates a method system based on BRAT annotations.\n",
11
+ "\n",
12
+ "### Prerequisites\n",
13
+ "- Clone the repository:\n",
14
+ " ```bash\n",
15
+ " git clone https://github.com/GuiGuiBazin/REST-interface.git\n",
16
+ " ```\n",
17
+ "- Install the dependencies:\n",
18
+ " ```bash\n",
19
+ " pip install -r requirements.txt\n",
20
+ " ```\n",
21
+ "- Download the required spaCy model:\n",
22
+ " ```bash\n",
23
+ " python -m spacy download fr_core_news_sm\n",
24
+ " ```\n",
25
+ "\n",
26
+ "This notebook assumes that dependencies are correctly installed and that the modules are accessible in the `REST_modules` folder."
27
+ ]
28
+ },
29
+ {
30
+ "cell_type": "markdown",
31
+ "id": "3a5a0d25",
32
+ "metadata": {},
33
+ "source": [
34
+ "## I - Imports"
35
+ ]
36
+ },
37
+ {
38
+ "cell_type": "code",
39
+ "execution_count": 1,
40
+ "id": "f0b2d71a",
41
+ "metadata": {},
42
+ "outputs": [
43
+ {
44
+ "name": "stderr",
45
+ "output_type": "stream",
46
+ "text": [
47
+ "D:\\1_CLEM\\ESIEE SCHOOL\\PARCOURS RECHERCHE\\Le juste usage des LLM et méthode NLP en cancélorlogie\\DEMNE-Determination-of-Extraction-Methode-for-Named-Entity\\.venv\\Lib\\site-packages\\torch\\cuda\\__init__.py:61: FutureWarning: The pynvml package is deprecated. Please install nvidia-ml-py instead. If you did not install pynvml directly, please report this to the maintainers of the package that installed pynvml for you.\n",
48
+ " import pynvml # type: ignore[import]\n"
49
+ ]
50
+ }
51
+ ],
52
+ "source": [
53
+ "# Import necessary modules\n",
54
+ "%load_ext autoreload\n",
55
+ "%autoreload 2\n",
56
+ "from REST_modules import *"
57
+ ]
58
+ },
59
+ {
60
+ "cell_type": "markdown",
61
+ "id": "3c3e4f99",
62
+ "metadata": {},
63
+ "source": [
64
+ "## II - Launch the REST Interface"
65
+ ]
66
+ },
67
+ {
68
+ "cell_type": "code",
69
+ "execution_count": 2,
70
+ "id": "58776351",
71
+ "metadata": {},
72
+ "outputs": [
73
+ {
74
+ "name": "stdout",
75
+ "output_type": "stream",
76
+ "text": [
77
+ "DEBUG: Running updated calculate_df_metrics\n"
78
+ ]
79
+ },
80
+ {
81
+ "data": {
82
+ "text/html": [
83
+ "<style>.widget-dropdown select, .widget-dropdown .widget-readout { font-size: 14px !important; }</style>"
84
+ ],
85
+ "text/plain": [
86
+ "<IPython.core.display.HTML object>"
87
+ ]
88
+ },
89
+ "metadata": {},
90
+ "output_type": "display_data"
91
+ },
92
+ {
93
+ "name": "stdout",
94
+ "output_type": "stream",
95
+ "text": [
96
+ "DEBUG: Running updated calculate_df_metrics\n"
97
+ ]
98
+ },
99
+ {
100
+ "data": {
101
+ "application/vnd.jupyter.widget-view+json": {
102
+ "model_id": "801d849a820c4a968c50d26499bfd373",
103
+ "version_major": 2,
104
+ "version_minor": 0
105
+ },
106
+ "text/plain": [
107
+ "VBox(children=(HTML(value='', layout=Layout(height='10px')), HTML(value='', layout=Layout(height='10px')), HBo…"
108
+ ]
109
+ },
110
+ "metadata": {},
111
+ "output_type": "display_data"
112
+ }
113
+ ],
114
+ "source": [
115
+ "# Launch the REST interface\n",
116
+ "launch_rest()"
117
+ ]
118
+ },
119
+ {
120
+ "cell_type": "markdown",
121
+ "id": "cce1e551",
122
+ "metadata": {},
123
+ "source": [
124
+ "## III - Additional Notes\n",
125
+ "- If you encounter any issues, verify the dependency versions in the `requirements.txt` file.\n",
126
+ "- Ensure that the spaCy model is correctly downloaded (see the Introduction section).\n",
127
+ "- For further questions, refer to the documentation in the GitHub repository's README.md."
128
+ ]
129
+ }
130
+ ],
131
+ "metadata": {
132
+ "kernelspec": {
133
+ "display_name": "Python 3 (ipykernel)",
134
+ "language": "python",
135
+ "name": "python3"
136
+ },
137
+ "language_info": {
138
+ "codemirror_mode": {
139
+ "name": "ipython",
140
+ "version": 3
141
+ },
142
+ "file_extension": ".py",
143
+ "mimetype": "text/x-python",
144
+ "name": "python",
145
+ "nbconvert_exporter": "python",
146
+ "pygments_lexer": "ipython3",
147
+ "version": "3.12.12"
148
+ },
149
+ "toc-showmarkdowntxt": false
150
+ },
151
+ "nbformat": 4,
152
+ "nbformat_minor": 5
153
+ }
@@ -0,0 +1,5 @@
1
+ from .categorization import *
2
+ from .initialization import *
3
+ from .loading import *
4
+ from .ui import *
5
+ from .visualization import *
@@ -0,0 +1,8 @@
1
+ from .bootstrap import *
2
+ from .concordancer import *
3
+ from .metrics import *
4
+ from .ngram import *
5
+ from .recommendations import *
6
+ from .regex import *
7
+ from .results import *
8
+ from .tfidf import *
@@ -0,0 +1,140 @@
1
+ import random
2
+
3
+ import numpy as np
4
+
5
+
6
+ def retrieve_bootstrap_data(df, _current_entity, df_metrics_locations):
7
+ """
8
+ Retrieve the number of TP, FP and FN present in each file.
9
+
10
+ Parameters :
11
+ df (dataframe) : Dataframe containing the annotated words, their occurrences, places and related entity.
12
+ current_entity (str) : current working entity selected.
13
+ df_metrics_locations (dataframe) : contains the locations of each categorized word, and whether they are true positive, false positive or false negative.
14
+
15
+ Return :
16
+ (dict) : dictionnary containing each file and their associated TP, FP and FN.
17
+ """
18
+ bootstrap_data = {}
19
+ # Retrieve of TP, TP(corr) and FP
20
+ for file in df_metrics_locations["file"].unique():
21
+ tp = df_metrics_locations[
22
+ (df_metrics_locations["file"] == file) & (df_metrics_locations["result"] == "TP")
23
+ ].shape[0]
24
+ tpcorr = df_metrics_locations[
25
+ (df_metrics_locations["file"] == file) & (df_metrics_locations["result"] == "TP(corr)")
26
+ ].shape[0]
27
+ fp = df_metrics_locations[
28
+ (df_metrics_locations["file"] == file) & (df_metrics_locations["result"] == "FP")
29
+ ].shape[0]
30
+ bootstrap_data[file] = {"TP": (tp + tpcorr), "FP": fp, "FN": 0}
31
+
32
+ # Retrieve of FN
33
+ for _index, row in df.iterrows():
34
+ if "category?" in row["category"]:
35
+ for place in row["places"]:
36
+ file = place[0] + ".txt"
37
+ if file in bootstrap_data:
38
+ bootstrap_data[file]["FN"] += 1
39
+ else:
40
+ bootstrap_data[file] = {"TP": 0, "FP": 0, "FN": 1}
41
+
42
+ return bootstrap_data
43
+
44
+
45
+ def calculate_metrics(tp, fp, fn):
46
+ """
47
+ Calculate the precision, recall and f1 from the metrics.
48
+
49
+ Parameters :
50
+ TP (int) : number of true positive (TP).
51
+ FP (int) : number of false positive (FP).
52
+ FN (int) : number of false negative (FN).
53
+
54
+ Returns :
55
+ (list) : list containg the calculated precision, recall and f1 values.
56
+
57
+ """
58
+ precision = tp / (tp + fp) if (tp + fp) > 0 else 0
59
+ recall = tp / (tp + fn) if (tp + fn) > 0 else 0
60
+ f1 = (2 * precision * recall) / (precision + recall) if (precision + recall) else 0
61
+ return precision, recall, f1
62
+
63
+
64
+ def estimate_confidence_intervals_bootstrap(
65
+ df, current_entity, df_metrics_locations, draw_number=1000, alpha=5.0
66
+ ):
67
+ """
68
+ Calculate the confidence intervals for each entity's metrics (precision and recall) by bootstrapping on the files.
69
+
70
+ Parameters :
71
+ df (dataframe) : Dataframe containing the annotated words, their occurrences, places and related entity.
72
+ current_entity (str) : current working entity selected.
73
+ df_metrics_locations (dataframe) : contains the locations of each categorized word, and whether they are true positive, false positive or false negative.
74
+ draw_number (int) : number of times that we draw files.
75
+ alpha (int) : represents the percentage of the distribution that falls outside the confidence interval, with a default value of 5.0
76
+
77
+ Return :
78
+ bootstrap_results (dict) : dictionnary of the confidence intervals of the metrics (precision and recall) calculated by bootstrap
79
+ """
80
+
81
+ bootstrap_data = retrieve_bootstrap_data(df, current_entity, df_metrics_locations)
82
+ files = list(bootstrap_data.keys())
83
+ precisions = []
84
+ recalls = []
85
+ f1s = []
86
+
87
+ for _ in range(draw_number):
88
+ sample_files = random.choices(files, k=len(files))
89
+ total_tp = 0
90
+ total_fp = 0
91
+ total_fn = 0
92
+
93
+ for file in sample_files:
94
+ total_tp += bootstrap_data[file]["TP"]
95
+ total_fp += bootstrap_data[file]["FP"]
96
+ total_fn += bootstrap_data[file]["FN"]
97
+
98
+ precision, recall, f1 = calculate_metrics(total_tp, total_fp, total_fn)
99
+ precisions.append(precision)
100
+ recalls.append(recall)
101
+ f1s.append(f1)
102
+
103
+ lower_p = alpha / 2
104
+ upper_p = 100 - (alpha / 2)
105
+
106
+ precision_conf_interval = (
107
+ np.percentile(precisions, lower_p),
108
+ np.percentile(precisions, upper_p),
109
+ )
110
+ precision_mean = np.mean(precisions)
111
+ precision_median = np.median(precisions)
112
+ recall_conf_interval = (
113
+ np.percentile(recalls, lower_p),
114
+ np.percentile(recalls, upper_p),
115
+ )
116
+ recall_mean = np.mean(recalls)
117
+ recall_median = np.median(recalls)
118
+ f1_conf_interval = (np.percentile(f1s, lower_p), np.percentile(f1s, upper_p))
119
+ f1_mean = np.mean(f1s)
120
+ f1_median = np.median(f1s)
121
+
122
+ bootstrap_results = {
123
+ "precision": {
124
+ "precision_conf_interval": precision_conf_interval,
125
+ "mean": precision_mean,
126
+ "median": precision_median,
127
+ },
128
+ "recall": {
129
+ "recall_conf_interval": recall_conf_interval,
130
+ "mean": recall_mean,
131
+ "median": recall_median,
132
+ },
133
+ "f1": {
134
+ "f1_conf_interval": f1_conf_interval,
135
+ "mean": f1_mean,
136
+ "median": f1_median,
137
+ },
138
+ }
139
+
140
+ return bootstrap_results
@@ -0,0 +1,138 @@
1
+ import os
2
+ import re
3
+
4
+ import pandas as pd
5
+ from ipydatagrid import DataGrid, Expr, TextRenderer
6
+
7
+
8
+ def get_annotations(docs):
9
+ """
10
+ Retrieve the annotations from the different files.
11
+
12
+ Parameters :
13
+ docs (generator) : contains all the informations extracted from the .ann files.
14
+
15
+ Return :
16
+ (list) : contains the informations related to each annotation (text, place, document,entity).
17
+ """
18
+ annotations = []
19
+ for doc in docs:
20
+ for ent in doc["entities"]:
21
+ annotations.append(
22
+ (
23
+ doc["num_ann"] + ".txt",
24
+ ent["label"],
25
+ ent["text"],
26
+ ent["fragments"][0]["begin"],
27
+ ent["fragments"][0]["end"],
28
+ )
29
+ )
30
+ return annotations
31
+
32
+
33
+ def get_matches(path, pattern):
34
+ """
35
+ Check the occurrences of a pattern in all the .txt files from the given path.
36
+
37
+ Parameters :
38
+ path (string) : path of the current working directory.
39
+ pattern (string) : word(s) that are searched in the texts.
40
+
41
+ Return :
42
+ (list) : contains the sentences in which the pattern is present, as well as the filename and the place in the text.
43
+ """
44
+ matches = []
45
+ for file_name in os.listdir(path):
46
+ if file_name.endswith(".txt"):
47
+ with open(os.path.join(path, file_name), newline="", encoding="utf-8") as file:
48
+ text = file.read().lower()
49
+ for match in re.finditer(pattern, text):
50
+ place_start = match.start()
51
+ place_end = match.end()
52
+ sentence = "..." + text[match.start() - 70 : match.end() + 60] + "..."
53
+ matches.append((pattern, sentence, file_name, place_start, place_end))
54
+ return matches
55
+
56
+
57
+ def cut_sentence(word, sentence):
58
+ """
59
+ Split the sentence in 3 parts, before and after the word of interest.
60
+
61
+ Parameters :
62
+ word (string) : word where the sentence needs to be split.
63
+ sentence (string) : sentence to split in 3 parts.
64
+
65
+ Return :
66
+ (strings) : the text before the word of interest, the word of interest, and the text after the word of interest.
67
+ """
68
+ cut = sentence.lower().split(word)
69
+ words_before = cut[0][-70:].rjust(70)
70
+ if len(cut[0]) > 70:
71
+ words_before = "..." + words_before
72
+ try:
73
+ words_after = cut[1].strip()
74
+ except IndexError:
75
+ words_after = ""
76
+ return words_before, word, words_after
77
+
78
+
79
+ def background_color_concordancer(cell):
80
+ if cell.value != "Not annotated":
81
+ return "#006400"
82
+ else:
83
+ return "#db8519"
84
+
85
+
86
+ def calculate_concordancer(pattern, current_entity, path, docs):
87
+ """
88
+ Creates a concordancer (datagrid) where the occurrences of a word in the text files are searched, and check if these occurrences corresponds to existing annotations.
89
+
90
+ Parameters :
91
+ pattern (string) : word(s) that are searched in the texts.
92
+ current_entity (string) : the current selected entity.
93
+ path (string) : path of the current working directory.
94
+ docs (generator) : contains all the informations extracted from the .ann files.
95
+
96
+ Return :
97
+ (datagrid) : datagrid containing the result of the concordancer.
98
+ """
99
+
100
+ matches = get_matches(path, pattern)
101
+ annotations = get_annotations(docs)
102
+
103
+ res_concordancier = []
104
+ for match in matches:
105
+ res = cut_sentence(match[0], match[1])
106
+ in_no_annotation = True
107
+ for annotation in annotations:
108
+ if match[2] == annotation[0]:
109
+ if annotation[3] <= match[3] and match[4] <= annotation[4]:
110
+ if annotation[1].lower() == current_entity:
111
+ res_concordancier.append((res[0], res[1], res[2], current_entity))
112
+ else:
113
+ res_concordancier.append((res[0], res[1], res[2], annotation[1]))
114
+ in_no_annotation = False
115
+ break
116
+ if in_no_annotation:
117
+ res_concordancier.append((res[0], res[1], res[2], "Not annotated"))
118
+
119
+ dg_res_concordancer = DataGrid(
120
+ pd.DataFrame(res_concordancier, columns=["words before", "word", "words after", "entity"]),
121
+ layout={"height": "350px", "width": "1165px"},
122
+ base_row_size=25,
123
+ column_widths={
124
+ "words before": 440,
125
+ "word": 110,
126
+ "words after": 380,
127
+ "entity": 150,
128
+ },
129
+ )
130
+ renderers = {
131
+ "words before": TextRenderer(horizontal_alignment="right"),
132
+ "word": TextRenderer(horizontal_alignment="center"),
133
+ "entity": TextRenderer(background_color=Expr(background_color_concordancer)),
134
+ }
135
+
136
+ dg_res_concordancer.renderers = renderers
137
+
138
+ return dg_res_concordancer