validmind 2.1.1__py3-none-any.whl → 2.2.4__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 (113) hide show
  1. validmind/__version__.py +1 -1
  2. validmind/ai.py +72 -49
  3. validmind/api_client.py +42 -16
  4. validmind/client.py +68 -25
  5. validmind/datasets/llm/rag/__init__.py +11 -0
  6. validmind/datasets/llm/rag/datasets/rfp_existing_questions_client_1.csv +30 -0
  7. validmind/datasets/llm/rag/datasets/rfp_existing_questions_client_2.csv +30 -0
  8. validmind/datasets/llm/rag/datasets/rfp_existing_questions_client_3.csv +53 -0
  9. validmind/datasets/llm/rag/datasets/rfp_existing_questions_client_4.csv +53 -0
  10. validmind/datasets/llm/rag/datasets/rfp_existing_questions_client_5.csv +53 -0
  11. validmind/datasets/llm/rag/rfp.py +41 -0
  12. validmind/errors.py +1 -1
  13. validmind/html_templates/__init__.py +0 -0
  14. validmind/html_templates/content_blocks.py +89 -14
  15. validmind/models/__init__.py +7 -4
  16. validmind/models/foundation.py +8 -34
  17. validmind/models/function.py +51 -0
  18. validmind/models/huggingface.py +16 -46
  19. validmind/models/metadata.py +42 -0
  20. validmind/models/pipeline.py +66 -0
  21. validmind/models/pytorch.py +8 -42
  22. validmind/models/r_model.py +33 -82
  23. validmind/models/sklearn.py +39 -38
  24. validmind/template.py +8 -26
  25. validmind/tests/__init__.py +43 -20
  26. validmind/tests/data_validation/ANOVAOneWayTable.py +1 -1
  27. validmind/tests/data_validation/ChiSquaredFeaturesTable.py +1 -1
  28. validmind/tests/data_validation/DescriptiveStatistics.py +2 -4
  29. validmind/tests/data_validation/Duplicates.py +1 -1
  30. validmind/tests/data_validation/IsolationForestOutliers.py +2 -2
  31. validmind/tests/data_validation/LaggedCorrelationHeatmap.py +1 -1
  32. validmind/tests/data_validation/TargetRateBarPlots.py +1 -1
  33. validmind/tests/data_validation/nlp/LanguageDetection.py +59 -0
  34. validmind/tests/data_validation/nlp/PolarityAndSubjectivity.py +48 -0
  35. validmind/tests/data_validation/nlp/Punctuations.py +11 -12
  36. validmind/tests/data_validation/nlp/Sentiment.py +57 -0
  37. validmind/tests/data_validation/nlp/Toxicity.py +45 -0
  38. validmind/tests/decorator.py +12 -7
  39. validmind/tests/model_validation/BertScore.py +100 -98
  40. validmind/tests/model_validation/BleuScore.py +93 -64
  41. validmind/tests/model_validation/ContextualRecall.py +74 -91
  42. validmind/tests/model_validation/MeteorScore.py +86 -74
  43. validmind/tests/model_validation/RegardScore.py +103 -121
  44. validmind/tests/model_validation/RougeScore.py +118 -0
  45. validmind/tests/model_validation/TokenDisparity.py +84 -121
  46. validmind/tests/model_validation/ToxicityScore.py +109 -123
  47. validmind/tests/model_validation/embeddings/CosineSimilarityComparison.py +96 -0
  48. validmind/tests/model_validation/embeddings/CosineSimilarityHeatmap.py +71 -0
  49. validmind/tests/model_validation/embeddings/EuclideanDistanceComparison.py +92 -0
  50. validmind/tests/model_validation/embeddings/EuclideanDistanceHeatmap.py +69 -0
  51. validmind/tests/model_validation/embeddings/PCAComponentsPairwisePlots.py +78 -0
  52. validmind/tests/model_validation/embeddings/StabilityAnalysis.py +35 -23
  53. validmind/tests/model_validation/embeddings/StabilityAnalysisKeyword.py +3 -0
  54. validmind/tests/model_validation/embeddings/StabilityAnalysisRandomNoise.py +7 -1
  55. validmind/tests/model_validation/embeddings/StabilityAnalysisSynonyms.py +3 -0
  56. validmind/tests/model_validation/embeddings/StabilityAnalysisTranslation.py +3 -0
  57. validmind/tests/model_validation/embeddings/TSNEComponentsPairwisePlots.py +99 -0
  58. validmind/tests/model_validation/ragas/AnswerCorrectness.py +131 -0
  59. validmind/tests/model_validation/ragas/AnswerRelevance.py +134 -0
  60. validmind/tests/model_validation/ragas/AnswerSimilarity.py +119 -0
  61. validmind/tests/model_validation/ragas/AspectCritique.py +167 -0
  62. validmind/tests/model_validation/ragas/ContextEntityRecall.py +133 -0
  63. validmind/tests/model_validation/ragas/ContextPrecision.py +123 -0
  64. validmind/tests/model_validation/ragas/ContextRecall.py +123 -0
  65. validmind/tests/model_validation/ragas/ContextRelevancy.py +114 -0
  66. validmind/tests/model_validation/ragas/Faithfulness.py +119 -0
  67. validmind/tests/model_validation/ragas/utils.py +66 -0
  68. validmind/tests/model_validation/sklearn/OverfitDiagnosis.py +3 -7
  69. validmind/tests/model_validation/sklearn/PermutationFeatureImportance.py +8 -9
  70. validmind/tests/model_validation/sklearn/PopulationStabilityIndex.py +5 -10
  71. validmind/tests/model_validation/sklearn/PrecisionRecallCurve.py +3 -2
  72. validmind/tests/model_validation/sklearn/ROCCurve.py +2 -1
  73. validmind/tests/model_validation/sklearn/RegressionR2Square.py +1 -1
  74. validmind/tests/model_validation/sklearn/RobustnessDiagnosis.py +2 -3
  75. validmind/tests/model_validation/sklearn/SHAPGlobalImportance.py +7 -11
  76. validmind/tests/model_validation/sklearn/WeakspotsDiagnosis.py +3 -4
  77. validmind/tests/model_validation/statsmodels/RegressionModelForecastPlot.py +1 -1
  78. validmind/tests/model_validation/statsmodels/RegressionModelForecastPlotLevels.py +1 -1
  79. validmind/tests/model_validation/statsmodels/RegressionModelInsampleComparison.py +1 -1
  80. validmind/tests/model_validation/statsmodels/RegressionModelOutsampleComparison.py +1 -1
  81. validmind/tests/model_validation/statsmodels/RegressionModelSummary.py +1 -1
  82. validmind/tests/model_validation/statsmodels/RegressionModelsCoeffs.py +1 -1
  83. validmind/tests/model_validation/statsmodels/RegressionModelsPerformance.py +1 -1
  84. validmind/tests/model_validation/statsmodels/ScorecardHistogram.py +5 -6
  85. validmind/unit_metrics/__init__.py +26 -49
  86. validmind/unit_metrics/composite.py +13 -7
  87. validmind/unit_metrics/regression/sklearn/AdjustedRSquaredScore.py +1 -1
  88. validmind/utils.py +99 -6
  89. validmind/vm_models/__init__.py +1 -1
  90. validmind/vm_models/dataset/__init__.py +7 -0
  91. validmind/vm_models/dataset/dataset.py +560 -0
  92. validmind/vm_models/dataset/utils.py +146 -0
  93. validmind/vm_models/model.py +97 -72
  94. validmind/vm_models/test/metric.py +9 -24
  95. validmind/vm_models/test/result_wrapper.py +124 -28
  96. validmind/vm_models/test/threshold_test.py +10 -28
  97. validmind/vm_models/test_context.py +1 -1
  98. validmind/vm_models/test_suite/summary.py +3 -4
  99. {validmind-2.1.1.dist-info → validmind-2.2.4.dist-info}/METADATA +5 -3
  100. {validmind-2.1.1.dist-info → validmind-2.2.4.dist-info}/RECORD +103 -78
  101. validmind/models/catboost.py +0 -33
  102. validmind/models/statsmodels.py +0 -50
  103. validmind/models/xgboost.py +0 -30
  104. validmind/tests/model_validation/BertScoreAggregate.py +0 -90
  105. validmind/tests/model_validation/RegardHistogram.py +0 -148
  106. validmind/tests/model_validation/RougeMetrics.py +0 -147
  107. validmind/tests/model_validation/RougeMetricsAggregate.py +0 -133
  108. validmind/tests/model_validation/SelfCheckNLIScore.py +0 -112
  109. validmind/tests/model_validation/ToxicityHistogram.py +0 -136
  110. validmind/vm_models/dataset.py +0 -1303
  111. {validmind-2.1.1.dist-info → validmind-2.2.4.dist-info}/LICENSE +0 -0
  112. {validmind-2.1.1.dist-info → validmind-2.2.4.dist-info}/WHEEL +0 -0
  113. {validmind-2.1.1.dist-info → validmind-2.2.4.dist-info}/entry_points.txt +0 -0
validmind/template.py CHANGED
@@ -2,20 +2,15 @@
2
2
  # See the LICENSE file in the root of this repository for details.
3
3
  # SPDX-License-Identifier: AGPL-3.0 AND ValidMind Commercial
4
4
 
5
- from pprint import pformat
6
-
7
- import mistune
8
- from IPython.display import display
9
5
  from ipywidgets import HTML, Accordion, VBox
10
6
 
11
7
  from .html_templates.content_blocks import (
12
8
  failed_content_block_html,
13
9
  non_test_content_block_html,
14
- test_content_block_html,
15
10
  )
16
11
  from .logging import get_logger
17
12
  from .tests import LoadTestError, describe_test
18
- from .utils import is_notebook
13
+ from .utils import display, is_notebook
19
14
  from .vm_models import TestSuite
20
15
 
21
16
  logger = get_logger(__name__)
@@ -26,6 +21,7 @@ CONTENT_TYPE_MAP = {
26
21
  "metadata_text": "Metadata Text",
27
22
  "dynamic": "Dynamic Content",
28
23
  "text": "Text",
24
+ "risk_assessment": "Risk Assessment",
29
25
  }
30
26
 
31
27
 
@@ -66,29 +62,12 @@ def _create_content_widget(content):
66
62
  )
67
63
 
68
64
  try:
69
- test_deets = describe_test(test_id=content["content_id"], raw=True)
65
+ test_html = describe_test(test_id=content["content_id"], show=False)
70
66
  except LoadTestError:
71
67
  return HTML(failed_content_block_html.format(test_id=content["content_id"]))
72
68
 
73
69
  return Accordion(
74
- children=[
75
- HTML(
76
- test_content_block_html.format(
77
- title=test_deets["Name"],
78
- description=mistune.html(test_deets["Description"]),
79
- required_inputs=", ".join(
80
- test_deets["Required Inputs"] or ["None"]
81
- ),
82
- params_table="\n".join(
83
- [
84
- f"<tr><td>{param}</td><td>{pformat(value, indent=4)}</td></tr>"
85
- for param, value in test_deets["Params"].items()
86
- ]
87
- ),
88
- table_display="table" if test_deets["Params"] else "none",
89
- )
90
- )
91
- ],
70
+ children=[HTML(test_html)],
92
71
  titles=[f"{content_type} Block: '{content['content_id']}'"],
93
72
  )
94
73
 
@@ -117,7 +96,10 @@ def _create_sub_section_widget(sub_sections, section_number):
117
96
  contents_widget,
118
97
  )
119
98
  else:
120
- accordion.children = (*accordion.children, HTML("<p>Empty Section</p>"))
99
+ accordion.children = (
100
+ *accordion.children,
101
+ HTML("<p>Empty Section</p>"),
102
+ )
121
103
 
122
104
  accordion.set_title(
123
105
  i, f"{section_number}.{i + 1}. {section['title']} ('{section['id']}')"
@@ -6,22 +6,29 @@
6
6
 
7
7
  import importlib
8
8
  import inspect
9
+ import json
9
10
  import sys
10
11
  from pathlib import Path
11
12
  from pprint import pformat
12
13
  from typing import Dict
14
+ from uuid import uuid4
13
15
 
14
- import mistune
15
16
  import pandas as pd
16
- from IPython.display import display
17
- from ipywidgets import HTML
17
+ from ipywidgets import HTML, Accordion
18
18
 
19
19
  from ..errors import LoadTestError
20
20
  from ..html_templates.content_blocks import test_content_block_html
21
21
  from ..logging import get_logger
22
22
  from ..unit_metrics import run_metric
23
23
  from ..unit_metrics.composite import load_composite_metric
24
- from ..utils import format_dataframe, fuzzy_match, test_id_to_name
24
+ from ..utils import (
25
+ NumpyEncoder,
26
+ display,
27
+ format_dataframe,
28
+ fuzzy_match,
29
+ md_to_html,
30
+ test_id_to_name,
31
+ )
25
32
  from ..vm_models import TestContext, TestInput
26
33
  from .decorator import metric, tags, tasks
27
34
  from .test_providers import LocalTestProvider, TestProvider
@@ -75,10 +82,12 @@ def _pretty_list_tests(tests, truncate=True):
75
82
 
76
83
  table = [
77
84
  {
78
- "Test Type": __test_classes[test_id].test_type,
85
+ "ID": test_id,
79
86
  "Name": test_id_to_name(test_id),
87
+ "Test Type": __test_classes[test_id].test_type,
80
88
  "Description": _test_description(__test_classes[test_id], truncate),
81
- "ID": test_id,
89
+ "Required Inputs": __test_classes[test_id].required_inputs,
90
+ "Params": __test_classes[test_id].default_params or {},
82
91
  }
83
92
  for test_id in tests
84
93
  ]
@@ -339,7 +348,7 @@ def load_test(test_id: str, reload=False):
339
348
  return test
340
349
 
341
350
 
342
- def describe_test(test_id: str = None, raw: bool = False):
351
+ def describe_test(test_id: str = None, raw: bool = False, show: bool = True):
343
352
  """Get or show details about the test
344
353
 
345
354
  This function can be used to see test details including the test name, description,
@@ -365,20 +374,34 @@ def describe_test(test_id: str = None, raw: bool = False):
365
374
  if raw:
366
375
  return details
367
376
 
377
+ html = test_content_block_html.format(
378
+ test_id=test_id,
379
+ uuid=str(uuid4()),
380
+ title=f'{details["Name"]}',
381
+ description=md_to_html(details["Description"].strip()),
382
+ required_inputs=", ".join(details["Required Inputs"] or ["None"]),
383
+ params_table="\n".join(
384
+ [
385
+ f"<tr><td>{param}</td><td>{pformat(value, indent=4)}</td></tr>"
386
+ for param, value in details["Params"].items()
387
+ ]
388
+ ),
389
+ table_display="table" if details["Params"] else "none",
390
+ example_inputs=json.dumps(
391
+ {name: f"my_vm_{name}" for name in (details["Required Inputs"] or [])},
392
+ indent=4,
393
+ ),
394
+ example_params=json.dumps(details["Params"] or {}, indent=4, cls=NumpyEncoder),
395
+ instructions_display="block" if show else "none",
396
+ )
397
+
398
+ if not show:
399
+ return html
400
+
368
401
  display(
369
- HTML(
370
- test_content_block_html.format(
371
- title=f'{details["Name"]}',
372
- description=mistune.html(details["Description"].strip()),
373
- required_inputs=", ".join(details["Required Inputs"] or ["None"]),
374
- params_table="\n".join(
375
- [
376
- f"<tr><td>{param}</td><td>{pformat(value, indent=4)}</td></tr>"
377
- for param, value in details["Params"].items()
378
- ]
379
- ),
380
- table_display="table" if details["Params"] else "none",
381
- )
402
+ Accordion(
403
+ children=[HTML(html)],
404
+ titles=[f"Test Description: {details['Name']} ('{test_id}')"],
382
405
  )
383
406
  )
384
407
 
@@ -74,7 +74,7 @@ class ANOVAOneWayTable(Metric):
74
74
 
75
75
  # Select all numerical features if none are specified
76
76
  if features is None:
77
- features = self.inputs.dataset.get_numeric_features_columns()
77
+ features = self.inputs.dataset.feature_columns_numeric
78
78
 
79
79
  anova_results = self.anova_numerical_features(features, p_threshold)
80
80
 
@@ -72,7 +72,7 @@ class ChiSquaredFeaturesTable(Metric):
72
72
 
73
73
  # Ensure cat_features is provided
74
74
  if not cat_features:
75
- cat_features = self.inputs.dataset.get_categorical_features_columns()
75
+ cat_features = self.inputs.dataset.feature_columns_categorical
76
76
 
77
77
  df = self.inputs.dataset.df
78
78
 
@@ -116,10 +116,8 @@ class DescriptiveStatistics(Metric):
116
116
 
117
117
  def run(self):
118
118
  feature_columns = self.inputs.dataset.feature_columns
119
- numerical_feature_columns = self.inputs.dataset.get_numeric_features_columns()
120
- categorical_feature_columns = (
121
- self.inputs.dataset.get_categorical_features_columns()
122
- )
119
+ numerical_feature_columns = self.inputs.dataset.feature_columns_numeric
120
+ categorical_feature_columns = self.inputs.dataset.feature_columns_categorical
123
121
 
124
122
  df = self.inputs.dataset.df[feature_columns]
125
123
 
@@ -84,7 +84,7 @@ class Duplicates(ThresholdTest):
84
84
  if self.inputs.dataset.text_column:
85
85
  columns = self.inputs.dataset.text_column
86
86
  else:
87
- columns = self.inputs.dataset.get_features_columns()
87
+ columns = self.inputs.dataset.feature_columns
88
88
 
89
89
  df = self.inputs.dataset.df[columns]
90
90
  # Find duplicate rows
@@ -64,13 +64,13 @@ class IsolationForestOutliers(Metric):
64
64
 
65
65
  def run(self):
66
66
  if self.params["features_columns"] is None:
67
- features_list = self.inputs.dataset.get_features_columns()
67
+ features_list = self.inputs.dataset.feature_columns
68
68
  else:
69
69
  features_list = self.params["features_columns"]
70
70
 
71
71
  # Check if all elements from features_list are present in the feature columns
72
72
  all_present = all(
73
- elem in self.inputs.dataset.get_features_columns() for elem in features_list
73
+ elem in self.inputs.dataset.feature_columns for elem in features_list
74
74
  )
75
75
  if not all_present:
76
76
  raise ValueError(
@@ -115,7 +115,7 @@ class LaggedCorrelationHeatmap(Metric):
115
115
  else:
116
116
  target_col = self.inputs.dataset.target_column
117
117
 
118
- independent_vars = list(self.inputs.dataset.get_features_columns())
118
+ independent_vars = list(self.inputs.dataset.feature_columns)
119
119
  num_lags = self.params.get("num_lags", 10)
120
120
 
121
121
  if isinstance(target_col, list) and len(target_col) == 1:
@@ -57,7 +57,7 @@ class TargetRateBarPlots(Metric):
57
57
 
58
58
  # Use all categorical features if columns is not specified, else use selected columns
59
59
  if columns is None:
60
- features = self.inputs.dataset.get_categorical_features_columns()
60
+ features = self.inputs.dataset.feature_columns_categorical
61
61
  else:
62
62
  features = columns
63
63
 
@@ -0,0 +1,59 @@
1
+ # Copyright © 2023-2024 ValidMind Inc. All rights reserved.
2
+ # See the LICENSE file in the root of this repository for details.
3
+ # SPDX-License-Identifier: AGPL-3.0 AND ValidMind Commercial
4
+
5
+ """
6
+ Metrics functions for any Pandas-compatible datasets
7
+ """
8
+
9
+
10
+ import plotly.express as px
11
+ from langdetect import LangDetectException, detect
12
+
13
+ from validmind import tags, tasks
14
+
15
+
16
+ @tags("nlp", "text_data", "visualization")
17
+ @tasks("text_classification", "text_summarization")
18
+ def LanguageDetection(dataset):
19
+ """
20
+ Detects the language of each text entry in a dataset and visualizes the distribution of languages
21
+ as a histogram.
22
+
23
+ This method checks for a specified text column in the dataset's dataframe, uses a language detection
24
+ library to determine the language of each text entry, and returns a histogram plot of the language
25
+ distribution.
26
+
27
+ Args:
28
+ dataset (Dataset): A dataset object which must have a `df` attribute (a pandas DataFrame)
29
+ and a `text_column` attribute indicating the name of the column containing text. If the
30
+ `text_column` attribute is not set, a ValueError is raised.
31
+
32
+ Returns:
33
+ plotly.graph_objs._figure.Figure: A Plotly histogram plot showing the distribution of detected
34
+ languages across the dataset's text entries.
35
+
36
+ Raises:
37
+ ValueError: If the `text_column` is not specified in the dataset object.
38
+ """
39
+ # check text column
40
+ if not dataset.text_column:
41
+ raise ValueError("Please set text_column name in the Validmind Dataset object")
42
+
43
+ # Function to detect language
44
+ def detect_language(text):
45
+ try:
46
+ return detect(text)
47
+ except LangDetectException:
48
+ return "Unknown" # Return 'Unknown' if language detection fails
49
+
50
+ # Applying the language detection function to each text entry
51
+ languages = dataset.df[dataset.text_column].apply(detect_language)
52
+ fig = px.histogram(
53
+ languages,
54
+ x=languages,
55
+ title="Language Distribution",
56
+ labels={"x": "Language Codes"},
57
+ )
58
+
59
+ return fig
@@ -0,0 +1,48 @@
1
+ # Copyright © 2023-2024 ValidMind Inc. All rights reserved.
2
+ # See the LICENSE file in the root of this repository for details.
3
+ # SPDX-License-Identifier: AGPL-3.0 AND ValidMind Commercial
4
+
5
+
6
+ import pandas as pd
7
+ import plotly.express as px
8
+ from textblob import TextBlob
9
+
10
+ from validmind import tags, tasks
11
+
12
+
13
+ @tags("data_validation")
14
+ @tasks("nlp")
15
+ def PolarityAndSubjectivity(dataset):
16
+ """
17
+ Analyzes the polarity and subjectivity of text data within a dataset.
18
+
19
+ This method processes a dataset containing textual data to compute the polarity and
20
+ subjectivity scores using TextBlob, and returns a Plotly scatter plot visualizing
21
+ these scores.
22
+
23
+ Args:
24
+ dataset (Dataset): A dataset object which must have a `df` attribute (a pandas DataFrame)
25
+ and a `text_column` attribute indicating the name of the column containing text.
26
+
27
+ Returns:
28
+ plotly.graph_objs._figure.Figure: A Plotly scatter plot of polarity vs subjectivity.
29
+ """
30
+ # Function to calculate sentiment and subjectivity
31
+ def analyze_sentiment(text):
32
+ analysis = TextBlob(text)
33
+ return analysis.sentiment.polarity, analysis.sentiment.subjectivity
34
+
35
+ data = pd.DataFrame()
36
+ # Apply the function to each row
37
+ data[["polarity", "subjectivity"]] = dataset.df[dataset.text_column].apply(
38
+ lambda x: pd.Series(analyze_sentiment(x))
39
+ )
40
+
41
+ # Create a Plotly scatter plot
42
+ fig = px.scatter(
43
+ data, x="polarity", y="subjectivity", title="Polarity vs Subjectivity"
44
+ )
45
+ fig.update_traces(textposition="top center")
46
+ fig.update_layout(xaxis_title="Polarity", yaxis_title="Subjectivity")
47
+
48
+ return fig
@@ -72,25 +72,24 @@ class Punctuations(Metric):
72
72
  text_column = self.inputs.dataset.text_column
73
73
  corpus = create_corpus(self.inputs.dataset.df, text_column=text_column)
74
74
 
75
- dic = defaultdict(int)
76
75
  special = string.punctuation
76
+ dic = defaultdict(int, {key: 0 for key in special})
77
77
  for i in corpus:
78
78
  if i in special:
79
79
  dic[i] += 1
80
-
80
+ figures = []
81
+ # if dic:
81
82
  fig = plt.figure()
82
83
  x, y = zip(*dic.items())
83
84
  plt.bar(x, y, color="#17C37B")
84
-
85
+ figures.append(
86
+ Figure(
87
+ for_object=self,
88
+ key=self.key,
89
+ figure=fig,
90
+ )
91
+ )
85
92
  # Do this if you want to prevent the figure from being displayed
86
93
  plt.close("all")
87
94
 
88
- return self.cache_results(
89
- figures=[
90
- Figure(
91
- for_object=self,
92
- key=self.key,
93
- figure=fig,
94
- )
95
- ]
96
- )
95
+ return self.cache_results(figures=figures)
@@ -0,0 +1,57 @@
1
+ # Copyright © 2023-2024 ValidMind Inc. All rights reserved.
2
+ # See the LICENSE file in the root of this repository for details.
3
+ # SPDX-License-Identifier: AGPL-3.0 AND ValidMind Commercial
4
+
5
+
6
+ import matplotlib.pyplot as plt
7
+ import nltk
8
+ import seaborn as sns
9
+ from nltk.sentiment import SentimentIntensityAnalyzer
10
+
11
+ from validmind import tags, tasks
12
+
13
+
14
+ @tags("data_validation")
15
+ @tasks("nlp")
16
+ def Sentiment(dataset):
17
+ """
18
+ Analyzes the sentiment of text data within a dataset using the VADER sentiment analysis tool.
19
+
20
+ This method initializes the VADER SentimentIntensityAnalyzer and applies it to each text entry
21
+ in the specified column of the dataset's dataframe. It returns a KDE plot visualizing the distribution
22
+ of sentiment scores across the dataset.
23
+
24
+ Args:
25
+ dataset (Dataset): A dataset object which must have a `df` attribute (a pandas DataFrame)
26
+ and a `text_column` attribute indicating the name of the column containing text.
27
+
28
+ Returns:
29
+ matplotlib.figure.Figure: A KDE plot visualizing the distribution of sentiment scores.
30
+ """
31
+ nltk.download("vader_lexicon", quiet=True)
32
+ # Initialize VADER
33
+ sia = SentimentIntensityAnalyzer()
34
+
35
+ # Function to get VADER sentiment scores
36
+ def get_vader_sentiment(text):
37
+ sentiment_score = sia.polarity_scores(text)
38
+ return sentiment_score["compound"]
39
+
40
+ # Apply the function to each row
41
+ vader_sentiment = dataset.df[dataset.text_column].apply(get_vader_sentiment)
42
+
43
+ fig = plt.figure()
44
+ ax = sns.kdeplot(
45
+ x=vader_sentiment,
46
+ fill=True,
47
+ common_norm=False,
48
+ palette="crest",
49
+ alpha=0.5,
50
+ linewidth=0,
51
+ )
52
+ ax.set_title(f"Sentiment score of {dataset.text_column} ")
53
+ ax.set_xlabel("Sentiment score")
54
+
55
+ plt.close("all")
56
+
57
+ return fig
@@ -0,0 +1,45 @@
1
+ # Copyright © 2023-2024 ValidMind Inc. All rights reserved.
2
+ # See the LICENSE file in the root of this repository for details.
3
+ # SPDX-License-Identifier: AGPL-3.0 AND ValidMind Commercial
4
+
5
+ import evaluate
6
+ import matplotlib.pyplot as plt
7
+ import seaborn as sns
8
+
9
+ from validmind import tags, tasks
10
+
11
+
12
+ @tags("data_validation")
13
+ @tasks("nlp")
14
+ def Toxicity(dataset):
15
+ """
16
+ Analyzes the toxicity of text data within a dataset using a pre-trained toxicity model.
17
+
18
+ This method loads a toxicity evaluation model and applies it to each text entry
19
+ in the specified column of the dataset's dataframe. It returns a KDE plot visualizing the distribution
20
+ of toxicity scores across the dataset.
21
+
22
+ Args:
23
+ dataset (Dataset): A dataset object which must have a `df` attribute (a pandas DataFrame)
24
+ and a `text_column` attribute indicating the name of the column containing text.
25
+
26
+ Returns:
27
+ matplotlib.figure.Figure: A KDE plot visualizing the distribution of toxicity scores.
28
+ """
29
+ toxicity = evaluate.load("toxicity")
30
+ input_text = dataset.df[dataset.text_column]
31
+ toxicity_scores = toxicity.compute(predictions=list(input_text.values))["toxicity"]
32
+
33
+ fig = plt.figure()
34
+ ax = sns.kdeplot(
35
+ x=toxicity_scores,
36
+ fill=True,
37
+ common_norm=False,
38
+ palette="crest",
39
+ alpha=0.5,
40
+ linewidth=0,
41
+ )
42
+ ax.set_title(f"Toxicity score of {dataset.text_column} ")
43
+ ax.set_xlabel("Toxicity score")
44
+ plt.close("all")
45
+ return fig
@@ -15,6 +15,7 @@ import pandas as pd
15
15
 
16
16
  from validmind.errors import MissingRequiredTestInputError
17
17
  from validmind.logging import get_logger
18
+ from validmind.utils import get_description_metadata
18
19
  from validmind.vm_models import (
19
20
  Metric,
20
21
  MetricResult,
@@ -113,20 +114,24 @@ def _build_result(results, test_id, description, output_template, inputs): # no
113
114
  else:
114
115
  process_item(results)
115
116
 
117
+ result_summary = ResultSummary(results=tables)
118
+
116
119
  return MetricResultWrapper(
117
120
  result_id=test_id,
118
121
  metric=MetricResult(
119
122
  key=test_id,
120
123
  ref_id=ref_id,
121
124
  value="Empty",
122
- summary=ResultSummary(results=tables),
125
+ summary=result_summary,
123
126
  ),
124
127
  figures=figures,
125
128
  result_metadata=[
126
- {
127
- "content_id": f"metric_description:{test_id}",
128
- "text": description,
129
- }
129
+ get_description_metadata(
130
+ test_id=test_id,
131
+ default_description=description,
132
+ summary=result_summary.serialize(),
133
+ figures=figures,
134
+ )
130
135
  ],
131
136
  inputs=inputs,
132
137
  output_template=output_template,
@@ -153,7 +158,7 @@ def _get_run_method(func, inputs, params):
153
158
  test_id=self.test_id,
154
159
  description=inspect.getdoc(self),
155
160
  output_template=self.output_template,
156
- inputs=list(inputs.keys()),
161
+ inputs=self.get_accessed_inputs(),
157
162
  )
158
163
 
159
164
  return self.result
@@ -264,7 +269,7 @@ def metric(func_or_id):
264
269
  {
265
270
  "run": _get_run_method(func, inputs, params),
266
271
  "required_inputs": list(inputs.keys()),
267
- "default_parameters": params,
272
+ "default_params": {k: v["default"] for k, v in params.items()},
268
273
  "__doc__": description,
269
274
  "metadata": {
270
275
  "task_types": tasks,