sampling-mining-workflows-dsl 0.0.1__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.
- sampling_mining_workflows_dsl/ __init__.py +0 -0
- sampling_mining_workflows_dsl/CompleteWorkflow.py +23 -0
- sampling_mining_workflows_dsl/Workflow.py +242 -0
- sampling_mining_workflows_dsl/WorkflowBuilder.py +11 -0
- sampling_mining_workflows_dsl/analysis/ChiSquareAnalysis.py +37 -0
- sampling_mining_workflows_dsl/analysis/CochranTest.py +44 -0
- sampling_mining_workflows_dsl/analysis/CochranWorkflowAnalysis.py +37 -0
- sampling_mining_workflows_dsl/analysis/CoverageTest.py +60 -0
- sampling_mining_workflows_dsl/analysis/DistributionWorkflowAnalysis.py +57 -0
- sampling_mining_workflows_dsl/analysis/HistAnalysis.py +201 -0
- sampling_mining_workflows_dsl/analysis/HistWorkflowAnalysis.py +72 -0
- sampling_mining_workflows_dsl/analysis/KSWorkflowAnalysis.py +217 -0
- sampling_mining_workflows_dsl/analysis/WorkflowAnalysis.py +7 -0
- sampling_mining_workflows_dsl/analysis/YamaneTest.py +16 -0
- sampling_mining_workflows_dsl/analysis/YamaneWorkflowAnalysis.py +27 -0
- sampling_mining_workflows_dsl/analysis/kolmogorov_smirnov.py +31 -0
- sampling_mining_workflows_dsl/constraint/BoolComparator.py +23 -0
- sampling_mining_workflows_dsl/constraint/BoolConstraint.py +50 -0
- sampling_mining_workflows_dsl/constraint/BoolConstraintString.py +66 -0
- sampling_mining_workflows_dsl/constraint/Comparator.py +16 -0
- sampling_mining_workflows_dsl/constraint/Constraint.py +23 -0
- sampling_mining_workflows_dsl/constraint/NaturalComparator.py +17 -0
- sampling_mining_workflows_dsl/element/Element.py +45 -0
- sampling_mining_workflows_dsl/element/Loader.py +17 -0
- sampling_mining_workflows_dsl/element/Repository.py +28 -0
- sampling_mining_workflows_dsl/element/Set.py +210 -0
- sampling_mining_workflows_dsl/element/Writer.py +9 -0
- sampling_mining_workflows_dsl/element/loader/CsvLoader.py +67 -0
- sampling_mining_workflows_dsl/element/loader/JsonLoader.py +84 -0
- sampling_mining_workflows_dsl/element/loader/LoaderFactory.py +14 -0
- sampling_mining_workflows_dsl/element/writer/CsvWriter.py +46 -0
- sampling_mining_workflows_dsl/element/writer/JsonWriter.py +58 -0
- sampling_mining_workflows_dsl/element/writer/WriterFactory.py +7 -0
- sampling_mining_workflows_dsl/exec_visualizer/WorkflowVisualizer.py +189 -0
- sampling_mining_workflows_dsl/github_seart/loader.py +17 -0
- sampling_mining_workflows_dsl/github_seart/metadata.py +106 -0
- sampling_mining_workflows_dsl/metadata/Metadata.py +117 -0
- sampling_mining_workflows_dsl/metadata/MetadataBoolean.py +14 -0
- sampling_mining_workflows_dsl/metadata/MetadataDate.py +75 -0
- sampling_mining_workflows_dsl/metadata/MetadataDict.py +33 -0
- sampling_mining_workflows_dsl/metadata/MetadataList.py +32 -0
- sampling_mining_workflows_dsl/metadata/MetadataNumber.py +29 -0
- sampling_mining_workflows_dsl/metadata/MetadataString.py +13 -0
- sampling_mining_workflows_dsl/metadata/MetadataValue.py +24 -0
- sampling_mining_workflows_dsl/operator/Operator.py +165 -0
- sampling_mining_workflows_dsl/operator/OperatorBuilder.py +191 -0
- sampling_mining_workflows_dsl/operator/OperatorFactory.py +76 -0
- sampling_mining_workflows_dsl/operator/clustering/GroupingOperator.py +36 -0
- sampling_mining_workflows_dsl/operator/clustering/SubWorkflowOperatorBuilder.py +76 -0
- sampling_mining_workflows_dsl/operator/selection/SelectionOperator.py +5 -0
- sampling_mining_workflows_dsl/operator/selection/filter/FilterOperator.py +30 -0
- sampling_mining_workflows_dsl/operator/selection/sampling/SamplingOperator.py +11 -0
- sampling_mining_workflows_dsl/operator/selection/sampling/automatic/AutomaticSamplingOperator.py +9 -0
- sampling_mining_workflows_dsl/operator/selection/sampling/automatic/RandomSelectionOperator.py +24 -0
- sampling_mining_workflows_dsl/operator/selection/sampling/automatic/RandomSelectionPartitionOperator.py +62 -0
- sampling_mining_workflows_dsl/operator/selection/sampling/automatic/SystematicRandomSelectionOperator.py +14 -0
- sampling_mining_workflows_dsl/operator/selection/sampling/automatic/SystematicSelectionOperator.py +31 -0
- sampling_mining_workflows_dsl/operator/selection/sampling/manual/InteractiveManualSamplingOperator.py +40 -0
- sampling_mining_workflows_dsl/operator/selection/sampling/manual/ManualSamplingOperator.py +28 -0
- sampling_mining_workflows_dsl/operator/set_algebra/ExternalSetOperator.py +33 -0
- sampling_mining_workflows_dsl/operator/set_algebra/InternalSetOperator.py +47 -0
- sampling_mining_workflows_dsl/operator/set_algebra/SetOperator.py +30 -0
- sampling_mining_workflows_dsl/operator/set_algebra/external_set_operator/DifferenceOperator.py +17 -0
- sampling_mining_workflows_dsl/operator/set_algebra/external_set_operator/IntersectionOperator.py +19 -0
- sampling_mining_workflows_dsl/operator/set_algebra/external_set_operator/UnionOperator.py +17 -0
- sampling_mining_workflows_dsl/operator/set_algebra/internal_set_operator/DifferenceOperator.py +17 -0
- sampling_mining_workflows_dsl/operator/set_algebra/internal_set_operator/IntersectionOperator.py +18 -0
- sampling_mining_workflows_dsl/operator/set_algebra/internal_set_operator/UnionOperator.py +17 -0
- sampling_mining_workflows_dsl/operator/set_algebra/set_operator/DifferenceOperator.py +15 -0
- sampling_mining_workflows_dsl/operator/set_algebra/set_operator/IntersectionOperator.py +18 -0
- sampling_mining_workflows_dsl/operator/set_algebra/set_operator/UnionOperator.py +17 -0
- sampling_mining_workflows_dsl/test/ __init__.py +0 -0
- sampling_mining_workflows_dsl/test/Workflow_simple.py +38 -0
- sampling_mining_workflows_dsl/test/input.json +401 -0
- sampling_mining_workflows_dsl/toolbox.py +42 -0
- sampling_mining_workflows_dsl-0.0.1.dist-info/METADATA +236 -0
- sampling_mining_workflows_dsl-0.0.1.dist-info/RECORD +79 -0
- sampling_mining_workflows_dsl-0.0.1.dist-info/WHEEL +4 -0
- sampling_mining_workflows_dsl-0.0.1.dist-info/licenses/LICENSE.txt +674 -0
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from typing import TypeVar
|
|
2
|
+
|
|
3
|
+
T = TypeVar("T")
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class CompleteWorkflow:
|
|
7
|
+
def __init__(self, workflow):
|
|
8
|
+
if not workflow.is_complete():
|
|
9
|
+
raise ValueError(
|
|
10
|
+
"Workflow is incomplete. Ensure it has an input, output, and at least one operator."
|
|
11
|
+
)
|
|
12
|
+
self._workflow = workflow
|
|
13
|
+
|
|
14
|
+
def execute_workflow(self):
|
|
15
|
+
self._workflow.execute_workflow()
|
|
16
|
+
return self
|
|
17
|
+
|
|
18
|
+
def analyze_workflow(self, metadata):
|
|
19
|
+
self._workflow.analyze_workflow(metadata)
|
|
20
|
+
return self
|
|
21
|
+
|
|
22
|
+
def __str__(self):
|
|
23
|
+
return str(self._workflow)
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
from typing import TypeVar, cast
|
|
2
|
+
|
|
3
|
+
from sampling_mining_workflows_dsl import CompleteWorkflow
|
|
4
|
+
from sampling_mining_workflows_dsl.analysis.DistributionWorkflowAnalysis import (
|
|
5
|
+
DistributionWorkflowAnalysis,
|
|
6
|
+
)
|
|
7
|
+
from sampling_mining_workflows_dsl.analysis.HistWorkflowAnalysis import HistWorkflowAnalysis
|
|
8
|
+
from sampling_mining_workflows_dsl.analysis.YamaneWorkflowAnalysis import YamaneWorkflowAnalysis
|
|
9
|
+
from sampling_mining_workflows_dsl.constraint.Constraint import Constraint
|
|
10
|
+
from sampling_mining_workflows_dsl.element.Element import Element
|
|
11
|
+
from sampling_mining_workflows_dsl.element.Loader import Loader
|
|
12
|
+
from sampling_mining_workflows_dsl.element.Set import Set
|
|
13
|
+
from sampling_mining_workflows_dsl.element.Writer import Writer
|
|
14
|
+
from sampling_mining_workflows_dsl.metadata.Metadata import Metadata
|
|
15
|
+
from sampling_mining_workflows_dsl.operator.clustering.GroupingOperator import GroupingOperator
|
|
16
|
+
from sampling_mining_workflows_dsl.operator.Operator import Operator
|
|
17
|
+
from sampling_mining_workflows_dsl.operator.selection.filter.FilterOperator import FilterOperator
|
|
18
|
+
from sampling_mining_workflows_dsl.operator.selection.sampling.automatic.RandomSelectionOperator import (
|
|
19
|
+
RandomSelectionOperator,
|
|
20
|
+
)
|
|
21
|
+
from sampling_mining_workflows_dsl.operator.selection.sampling.manual.ManualSamplingOperator import (
|
|
22
|
+
ManualSamplingOperator,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
T = TypeVar("T")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Workflow:
|
|
29
|
+
def __init__(self):
|
|
30
|
+
self._input: Set | None = None
|
|
31
|
+
self._output: Set | None = None
|
|
32
|
+
self._output_writer: Writer | None = None
|
|
33
|
+
self._root: Operator | None = None
|
|
34
|
+
self._last_operator: Operator | None = None
|
|
35
|
+
self._metadata: list[Metadata] = []
|
|
36
|
+
|
|
37
|
+
def get_all_Metadata(self) -> list[Metadata]:
|
|
38
|
+
return self._metadata
|
|
39
|
+
|
|
40
|
+
def add_metadata_type(self, metadata: Metadata) -> "Workflow":
|
|
41
|
+
self._metadata.append(metadata)
|
|
42
|
+
return self
|
|
43
|
+
|
|
44
|
+
def grouping_operator(self, *workflows: "Workflow") -> "Workflow":
|
|
45
|
+
if not workflows:
|
|
46
|
+
raise ValueError("At least one workflow must be provided.")
|
|
47
|
+
|
|
48
|
+
# Create a GroupingOperator with the provided sub workflows
|
|
49
|
+
grouping_operator = GroupingOperator(self, *workflows)
|
|
50
|
+
|
|
51
|
+
# Add the grouping operator to the current workflow
|
|
52
|
+
self.add_operator(cast("Operator", grouping_operator))
|
|
53
|
+
return self
|
|
54
|
+
|
|
55
|
+
def random_selection_operator(self, cardinality: int, seed: int = -1) -> "Workflow":
|
|
56
|
+
random_selection_operator = RandomSelectionOperator(
|
|
57
|
+
self, cardinality=cardinality, seed=seed
|
|
58
|
+
)
|
|
59
|
+
self.add_operator(cast("Operator", random_selection_operator))
|
|
60
|
+
return self
|
|
61
|
+
|
|
62
|
+
def filter_operator(self, constraint: Constraint):
|
|
63
|
+
filter_operator = FilterOperator(self, constraint)
|
|
64
|
+
self.add_operator(cast("Operator", filter_operator))
|
|
65
|
+
return self
|
|
66
|
+
|
|
67
|
+
def manual_sampling_operator(self, *ids: T) -> "Workflow":
|
|
68
|
+
if not ids:
|
|
69
|
+
raise ValueError(
|
|
70
|
+
"At least one element must be provided for manual sampling."
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
manual_sampling_operator = ManualSamplingOperator(self, *ids)
|
|
74
|
+
self.add_operator(cast("Operator", manual_sampling_operator))
|
|
75
|
+
return self
|
|
76
|
+
|
|
77
|
+
def get_all_set_from_workflow(self, index=0):
|
|
78
|
+
sets = {}
|
|
79
|
+
if index==0:
|
|
80
|
+
sets[index] = (self._input,None)
|
|
81
|
+
index += 1
|
|
82
|
+
|
|
83
|
+
op = self.get_root()
|
|
84
|
+
while op is not None:
|
|
85
|
+
if not isinstance(op, GroupingOperator):
|
|
86
|
+
if hasattr(op, "_output") and op._output is not None:
|
|
87
|
+
sets[index] = (op._output,op) # Fix: use index as key, not the Set object
|
|
88
|
+
index += 1
|
|
89
|
+
else:
|
|
90
|
+
for internal_w in op.get_workflows():
|
|
91
|
+
grouping_sets = internal_w.get_all_set_from_workflow(index)
|
|
92
|
+
index = index + len(grouping_sets)
|
|
93
|
+
sets.update(grouping_sets) # Fix: use update() instead of extend()
|
|
94
|
+
op = op.get_next_operator()
|
|
95
|
+
return sets
|
|
96
|
+
|
|
97
|
+
def get_internal_set_by_index(self,index):
|
|
98
|
+
return self.get_all_set_from_workflow()[index]
|
|
99
|
+
|
|
100
|
+
def get_internal_set_by_id(self, set_id: str) -> Set | None:
|
|
101
|
+
current: Operator= self._root
|
|
102
|
+
while current is not None:
|
|
103
|
+
output:Set = current.get_output()
|
|
104
|
+
if not output is None and output.get_id() == set_id:
|
|
105
|
+
return output
|
|
106
|
+
if current.isinstance(GroupingOperator):
|
|
107
|
+
for w in current.get_workflows():
|
|
108
|
+
internal_set = w.get_internal_set_by_id(set_id)
|
|
109
|
+
if internal_set is not None:
|
|
110
|
+
return internal_set
|
|
111
|
+
current = current._next_operator
|
|
112
|
+
return None
|
|
113
|
+
|
|
114
|
+
def input(self, loader: Loader) -> "Workflow":
|
|
115
|
+
self._metadata = list(loader.metadatas.values())
|
|
116
|
+
self._input = loader.load_set()
|
|
117
|
+
return self
|
|
118
|
+
|
|
119
|
+
def add_metadata(self, loader: Loader) -> "Workflow":
|
|
120
|
+
# Add metadata value to last declared operator
|
|
121
|
+
current_operator: Operator = self.get_last_operator()
|
|
122
|
+
if current_operator:
|
|
123
|
+
current_operator.add_metadata_loader(loader)
|
|
124
|
+
return self
|
|
125
|
+
|
|
126
|
+
def output(self, writer: Writer) -> "Workflow":
|
|
127
|
+
self._output_writer = writer
|
|
128
|
+
last_operator = self.get_last_operator()
|
|
129
|
+
if last_operator:
|
|
130
|
+
last_operator.output(writer)
|
|
131
|
+
return self
|
|
132
|
+
|
|
133
|
+
def is_complete(self) -> bool:
|
|
134
|
+
return (
|
|
135
|
+
self._root is not None
|
|
136
|
+
and self._input is not None
|
|
137
|
+
and self._output_writer is not None
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
def add_operator(self, operator: Operator):
|
|
141
|
+
# If the workflow is empty, set the root operator
|
|
142
|
+
if self._root is None:
|
|
143
|
+
self._root = operator
|
|
144
|
+
self._last_operator = operator
|
|
145
|
+
|
|
146
|
+
# If the workflow already has operators, append the new operator to the end
|
|
147
|
+
else:
|
|
148
|
+
self._last_operator._next_operator = operator
|
|
149
|
+
operator._previous_operator = self._last_operator
|
|
150
|
+
operator.input_set(self._last_operator.get_output())
|
|
151
|
+
self._last_operator.output_set(operator.get_output())
|
|
152
|
+
self._last_operator = operator
|
|
153
|
+
|
|
154
|
+
if self.is_complete():
|
|
155
|
+
return CompleteWorkflow(self)
|
|
156
|
+
return None
|
|
157
|
+
|
|
158
|
+
def set_workflow_input(self, input_set: Set | None) -> "Workflow":
|
|
159
|
+
self._input = input_set
|
|
160
|
+
if self._root is not None:
|
|
161
|
+
self._root.input_set(input_set)
|
|
162
|
+
return self
|
|
163
|
+
|
|
164
|
+
def set_root_input(self, input_set: Set | None) -> "Workflow":
|
|
165
|
+
if self._root is None:
|
|
166
|
+
raise ValueError("Cannot set root input when no root operator is defined.")
|
|
167
|
+
self._root.input_set(input_set)
|
|
168
|
+
return self
|
|
169
|
+
|
|
170
|
+
def get_workflow_input(self) -> Element | None:
|
|
171
|
+
return self._input
|
|
172
|
+
|
|
173
|
+
def set_workflow_output(self, output_element: Element) -> "Workflow":
|
|
174
|
+
self._output = output_element
|
|
175
|
+
return self
|
|
176
|
+
|
|
177
|
+
def get_workflow_output(self) -> Set | None:
|
|
178
|
+
return self._output
|
|
179
|
+
|
|
180
|
+
def get_root(self) -> Operator | None:
|
|
181
|
+
return self._root
|
|
182
|
+
|
|
183
|
+
def get_last_operator(self) -> Operator | None:
|
|
184
|
+
if self._root is None:
|
|
185
|
+
return None
|
|
186
|
+
current = self._root
|
|
187
|
+
while current._next_operator is not None:
|
|
188
|
+
current = current._next_operator
|
|
189
|
+
return current
|
|
190
|
+
|
|
191
|
+
def get_operator_by_position(self, position: int) -> Operator | None:
|
|
192
|
+
if position < 0:
|
|
193
|
+
return None
|
|
194
|
+
current = self._root
|
|
195
|
+
index = 0
|
|
196
|
+
while current is not None:
|
|
197
|
+
if index == position:
|
|
198
|
+
return current
|
|
199
|
+
current = current._next_operator
|
|
200
|
+
index += 1
|
|
201
|
+
return None
|
|
202
|
+
|
|
203
|
+
def execute_workflow(self) -> "Workflow":
|
|
204
|
+
root = self._root
|
|
205
|
+
root.input_set(self._input)
|
|
206
|
+
root.execute()
|
|
207
|
+
self._output = self._last_operator.get_output()
|
|
208
|
+
return self
|
|
209
|
+
|
|
210
|
+
def print(self) -> "Workflow":
|
|
211
|
+
print(self)
|
|
212
|
+
return self
|
|
213
|
+
|
|
214
|
+
def analyze_workflow(self, metadata: Metadata[T]) -> "Workflow":
|
|
215
|
+
# Perform analysis on a given metadata
|
|
216
|
+
# workflow_analysis = HistWorkflowAnalysis(metadata)
|
|
217
|
+
workflow_distrib_analysis = DistributionWorkflowAnalysis(metadata=metadata)
|
|
218
|
+
workflow_distrib_analysis.analyze(self)
|
|
219
|
+
|
|
220
|
+
workflow_yamane_analysis = YamaneWorkflowAnalysis()
|
|
221
|
+
workflow_yamane_analysis.analyze(self)
|
|
222
|
+
|
|
223
|
+
workflow_hist_analysis = HistWorkflowAnalysis(metadata=metadata)
|
|
224
|
+
workflow_hist_analysis.analyze(self)
|
|
225
|
+
return self
|
|
226
|
+
|
|
227
|
+
# --- Methods for workflow printing ---
|
|
228
|
+
|
|
229
|
+
def __str__(self) -> str:
|
|
230
|
+
return self.to_string(0)
|
|
231
|
+
|
|
232
|
+
def to_string(self, level: int):
|
|
233
|
+
indent = " " * level
|
|
234
|
+
res = f"{indent}Workflow: [[[\n"
|
|
235
|
+
# res = ""
|
|
236
|
+
if self._root is not None:
|
|
237
|
+
res += self._root.to_string(level)
|
|
238
|
+
else:
|
|
239
|
+
res += f"{indent}No operators defined in this workflow.\n"
|
|
240
|
+
|
|
241
|
+
res += "\n" + indent + "]]]\n"
|
|
242
|
+
return res
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from sampling_mining_workflows_dsl.operator.OperatorBuilder import OperatorBuilder
|
|
2
|
+
from sampling_mining_workflows_dsl.Workflow import Workflow
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class WorkflowBuilder:
|
|
6
|
+
def __init__(self):
|
|
7
|
+
self.workflow = Workflow()
|
|
8
|
+
|
|
9
|
+
def input(self, loader) -> "OperatorBuilder":
|
|
10
|
+
self.workflow.input(loader)
|
|
11
|
+
return OperatorBuilder(self.workflow)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from collections import Counter
|
|
2
|
+
|
|
3
|
+
from scipy.stats import chisquare
|
|
4
|
+
|
|
5
|
+
from sampling_mining_workflows_dsl.element.Set import Set
|
|
6
|
+
from sampling_mining_workflows_dsl.metadata.Metadata import Metadata
|
|
7
|
+
|
|
8
|
+
class ChiSquareAnalysis:
|
|
9
|
+
def __init__(self, metadata: Metadata[str]):
|
|
10
|
+
self.metadata = metadata
|
|
11
|
+
|
|
12
|
+
def analyze(self, set_1: Set, set_2: Set):
|
|
13
|
+
# Extract keywords from both sets
|
|
14
|
+
keywords_1 = self.extract_keywords(set_1)
|
|
15
|
+
keywords_2 = self.extract_keywords(set_2)
|
|
16
|
+
|
|
17
|
+
all_labels = sorted(set(keywords_1 + keywords_2))
|
|
18
|
+
|
|
19
|
+
pop_counts = [Counter(keywords_1).get(label, 0) for label in all_labels]
|
|
20
|
+
sample_counts = [Counter(keywords_2).get(label, 0) for label in all_labels]
|
|
21
|
+
|
|
22
|
+
total_pop = sum(pop_counts)
|
|
23
|
+
total_sample = sum(sample_counts)
|
|
24
|
+
scaled_pop = [x * (total_sample / total_pop) for x in pop_counts]
|
|
25
|
+
|
|
26
|
+
chi2, p = chisquare(f_obs=sample_counts, f_exp=scaled_pop)
|
|
27
|
+
|
|
28
|
+
print("Chi2:", chi2)
|
|
29
|
+
print("p-value:", p)
|
|
30
|
+
|
|
31
|
+
def extract_keywords(self, s: Set):
|
|
32
|
+
keywords = []
|
|
33
|
+
for element in s.get_elements():
|
|
34
|
+
metadata_value = element.get_metadata_value(self.metadata)
|
|
35
|
+
if metadata_value:
|
|
36
|
+
keywords.extend(metadata_value.get_value())
|
|
37
|
+
return keywords
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
3
|
+
from sampling_mining_workflows_dsl.operator.selection.sampling.automatic.RandomSelectionOperator import RandomSelectionOperator
|
|
4
|
+
from scipy.stats import norm
|
|
5
|
+
|
|
6
|
+
class CochranTest:
|
|
7
|
+
def __init__(self, op :RandomSelectionOperator,confidence_level=0.95,margin_error=0.05,p=0.5):
|
|
8
|
+
self.op: RandomSelectionOperator = op
|
|
9
|
+
self.confidence_level=confidence_level
|
|
10
|
+
self.e=margin_error
|
|
11
|
+
self.p=p
|
|
12
|
+
"""
|
|
13
|
+
Calculate sample size using Cochran's formula.
|
|
14
|
+
|
|
15
|
+
Parameters:
|
|
16
|
+
confidence_level (float): Confidence level (e.g. 0.95 for 95%)
|
|
17
|
+
p (float): Estimated proportion of the population (use 0.5 if unknown)
|
|
18
|
+
e (float): Margin of error (e.g. 0.05 for 5%)
|
|
19
|
+
population (int or None): Population size, optional for finite correction
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
float: Required sample size
|
|
23
|
+
"""
|
|
24
|
+
def cochran_sample_size(self):
|
|
25
|
+
sampling_frame_size = self.op.get_input().size()
|
|
26
|
+
|
|
27
|
+
# Get Z-value for given confidence level
|
|
28
|
+
z = norm.ppf(1 - (1 - self.confidence_level) / 2)
|
|
29
|
+
|
|
30
|
+
# Cochran's initial sample size
|
|
31
|
+
n0 = (z**2 * self.p * (1 - self.p)) / (self.e**2)
|
|
32
|
+
|
|
33
|
+
# Adjust for finite population if given
|
|
34
|
+
if sampling_frame_size:
|
|
35
|
+
n = n0 / (1 + (n0 - 1) / sampling_frame_size)
|
|
36
|
+
return n
|
|
37
|
+
else:
|
|
38
|
+
return n0
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def is_representative(self) -> bool:
|
|
42
|
+
required_sample_size = self.cochran_sample_size()
|
|
43
|
+
sample_size = self.op.get_cardinality()
|
|
44
|
+
return sample_size >= required_sample_size
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from sampling_mining_workflows_dsl.Workflow import Workflow
|
|
2
|
+
from sampling_mining_workflows_dsl.analysis.WorkflowAnalysis import WorkflowAnalysis
|
|
3
|
+
from sampling_mining_workflows_dsl.operator.selection.sampling.automatic.RandomSelectionOperator import RandomSelectionOperator
|
|
4
|
+
from sampling_mining_workflows_dsl.analysis.CochranTest import CochranTest
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class CochranWorkflowAnalysis(WorkflowAnalysis):
|
|
8
|
+
def __init__(self,confidence_level=0.95,margin_error=0.05,p=0.5):
|
|
9
|
+
self.confidence_level=confidence_level
|
|
10
|
+
self.margin_error=margin_error
|
|
11
|
+
self.p=p
|
|
12
|
+
|
|
13
|
+
def analyze(self,workflow : Workflow):
|
|
14
|
+
#dict set_num --> (set,op)
|
|
15
|
+
set_op_dict = workflow.get_all_set_from_workflow()
|
|
16
|
+
for (set_nb,value) in set_op_dict.items():
|
|
17
|
+
set_,op = value
|
|
18
|
+
if isinstance(op,RandomSelectionOperator):
|
|
19
|
+
print(f"Set #{set_nb} produced by a random selection operator, checking sample size")
|
|
20
|
+
cochran_test = CochranTest(op,self.confidence_level,self.margin_error,self.p)
|
|
21
|
+
required_sample_size = cochran_test.cochran_sample_size()
|
|
22
|
+
actual_sample_size = op.get_cardinality()
|
|
23
|
+
print(f"Cochran's Test Analysis for set {set_nb}:")
|
|
24
|
+
print("Required Sample Size:", required_sample_size)
|
|
25
|
+
print("Actual Sample Size:", actual_sample_size)
|
|
26
|
+
|
|
27
|
+
if cochran_test.is_representative():
|
|
28
|
+
print("The sample pass Cochran's test.")
|
|
29
|
+
else:
|
|
30
|
+
print("The sample do not pass Cochran's test.")
|
|
31
|
+
|
|
32
|
+
print("------------------------------------------")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from collections import Counter
|
|
2
|
+
|
|
3
|
+
from sampling_mining_workflows_dsl.element.Set import Set
|
|
4
|
+
from sampling_mining_workflows_dsl.metadata.Metadata import Metadata
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class CoverageTest:
|
|
8
|
+
def __init__(self, metadata: Metadata, set_1: Set, set_2: Set):
|
|
9
|
+
self.metadata = metadata
|
|
10
|
+
self.set_1 = set_1
|
|
11
|
+
self.set_2 = set_2
|
|
12
|
+
|
|
13
|
+
def compute_coverage(self, top_x: int = None) -> float:
|
|
14
|
+
counter = Counter()
|
|
15
|
+
for element in self.set_1.get_elements():
|
|
16
|
+
values = element.get_metadata_value(self.metadata).get_value()
|
|
17
|
+
counter.update(self.flatten(values))
|
|
18
|
+
|
|
19
|
+
if top_x is not None:
|
|
20
|
+
top_values = {item for item, _ in counter.most_common(top_x)}
|
|
21
|
+
else:
|
|
22
|
+
top_values = set(counter.elements())
|
|
23
|
+
|
|
24
|
+
set_1_unique = {
|
|
25
|
+
v
|
|
26
|
+
for element in self.set_1.get_elements()
|
|
27
|
+
for v in self.flatten(element.get_metadata_value(self.metadata).get_value())
|
|
28
|
+
if v in top_values
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
set_2_unique = {
|
|
32
|
+
v
|
|
33
|
+
for element in self.set_2.get_elements()
|
|
34
|
+
for v in self.flatten(element.get_metadata_value(self.metadata).get_value())
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if not set_1_unique:
|
|
38
|
+
print(
|
|
39
|
+
f"No value for {self.metadata.name}. Couverture = 0.0"
|
|
40
|
+
)
|
|
41
|
+
return 0.0
|
|
42
|
+
|
|
43
|
+
intersection = set_1_unique.intersection(set_2_unique)
|
|
44
|
+
coverage = len(intersection) / len(set_1_unique)
|
|
45
|
+
|
|
46
|
+
print(
|
|
47
|
+
f"Coverage for {self.metadata.name} (top {top_x if top_x is not None else 'all'}): {coverage:.2f}"
|
|
48
|
+
)
|
|
49
|
+
return coverage
|
|
50
|
+
|
|
51
|
+
def flatten(self, values):
|
|
52
|
+
if isinstance(values, list):
|
|
53
|
+
result = []
|
|
54
|
+
for v in values:
|
|
55
|
+
if isinstance(v, list):
|
|
56
|
+
result.extend(v)
|
|
57
|
+
else:
|
|
58
|
+
result.append(v)
|
|
59
|
+
return result
|
|
60
|
+
return [values]
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
3
|
+
|
|
4
|
+
from sampling_mining_workflows_dsl.analysis.kolmogorov_smirnov import kolmogorov_smirnov
|
|
5
|
+
from sampling_mining_workflows_dsl.metadata.Metadata import Metadata
|
|
6
|
+
from sampling_mining_workflows_dsl.operator.clustering.GroupingOperator import GroupingOperator
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from sampling_mining_workflows_dsl.element.Set import Set
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DistributionWorkflowAnalysis:
|
|
13
|
+
def __init__(self, metadata: Metadata[int]):
|
|
14
|
+
self.map: dict[str, Set] = {}
|
|
15
|
+
self.metadata = metadata
|
|
16
|
+
|
|
17
|
+
def analyze(self, workflow):
|
|
18
|
+
# Retrieve the root operator from the workflow
|
|
19
|
+
root_operator = workflow.get_root()
|
|
20
|
+
self.populate_map(root_operator, "")
|
|
21
|
+
analyzer = kolmogorov_smirnov(self.metadata)
|
|
22
|
+
entries = list(self.map.items())
|
|
23
|
+
|
|
24
|
+
print("Kolmogorov-Smirnov Test:")
|
|
25
|
+
|
|
26
|
+
for i in range(len(entries) - 1):
|
|
27
|
+
for j in range(i + 1, len(entries)):
|
|
28
|
+
name = f"{entries[i][0]} /// {entries[j][0]}"
|
|
29
|
+
result = analyzer.analyze(entries[i][1], entries[j][1])
|
|
30
|
+
|
|
31
|
+
print(name)
|
|
32
|
+
print(result)
|
|
33
|
+
print("------------------------------------------")
|
|
34
|
+
|
|
35
|
+
def populate_map(self, workflow, prefix: str):
|
|
36
|
+
op = workflow.get_workflow_root_operator()
|
|
37
|
+
self.map[f"{prefix}input"] = op.get_input()
|
|
38
|
+
count = 1
|
|
39
|
+
|
|
40
|
+
while op is not None:
|
|
41
|
+
if isinstance(op, GroupingOperator):
|
|
42
|
+
grouping_operator: GroupingOperator = op
|
|
43
|
+
self.map[f"{prefix}operator_{count}_merged"] = (
|
|
44
|
+
grouping_operator.get_merged_output()
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
child_count = 1
|
|
48
|
+
for internal_w in grouping_operator.get_workflows():
|
|
49
|
+
self.populate_map(
|
|
50
|
+
internal_w, f"{prefix}operator_{count}_Child_{child_count}_"
|
|
51
|
+
)
|
|
52
|
+
child_count += 1
|
|
53
|
+
else:
|
|
54
|
+
self.map[f"{prefix}operator_{count}"] = op.get_output()
|
|
55
|
+
|
|
56
|
+
count += 1
|
|
57
|
+
op = op.get_next_operator()
|