sensor-modeling 0.2.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 (114) hide show
  1. sensor_modeling/__init__.py +45 -0
  2. sensor_modeling/alerts/__init__.py +26 -0
  3. sensor_modeling/alerts/alert.py +532 -0
  4. sensor_modeling/analysis/__init__.py +43 -0
  5. sensor_modeling/analysis/_frame.py +19 -0
  6. sensor_modeling/analysis/behavioral_analysis.py +57 -0
  7. sensor_modeling/analysis/behavioral_metrics.py +66 -0
  8. sensor_modeling/analysis/comparison.py +164 -0
  9. sensor_modeling/analysis/dependency_network.py +408 -0
  10. sensor_modeling/analysis/granger_causality.py +314 -0
  11. sensor_modeling/analysis/pipeline.py +168 -0
  12. sensor_modeling/analysis/reporting.py +109 -0
  13. sensor_modeling/baseline/__init__.py +30 -0
  14. sensor_modeling/baseline/adaptive.py +520 -0
  15. sensor_modeling/baseline/features.py +224 -0
  16. sensor_modeling/change_point/__init__.py +13 -0
  17. sensor_modeling/change_point/_validation.py +31 -0
  18. sensor_modeling/change_point/adaptive_normalization.py +55 -0
  19. sensor_modeling/change_point/embedding_cpd.py +60 -0
  20. sensor_modeling/change_point/energy_efficient.py +57 -0
  21. sensor_modeling/change_point/genetic_optimization.py +65 -0
  22. sensor_modeling/cli.py +416 -0
  23. sensor_modeling/context/__init__.py +33 -0
  24. sensor_modeling/context/occupancy.py +529 -0
  25. sensor_modeling/data/__init__.py +5 -0
  26. sensor_modeling/data/loaders.py +146 -0
  27. sensor_modeling/data/preprocessing.py +83 -0
  28. sensor_modeling/data/synthetic.py +121 -0
  29. sensor_modeling/data/validation.py +81 -0
  30. sensor_modeling/evaluation/__init__.py +92 -0
  31. sensor_modeling/evaluation/ablation.py +303 -0
  32. sensor_modeling/evaluation/attribution.py +474 -0
  33. sensor_modeling/evaluation/detection.py +297 -0
  34. sensor_modeling/evaluation/metrics.py +541 -0
  35. sensor_modeling/evaluation/provenance.py +309 -0
  36. sensor_modeling/examples/__init__.py +1 -0
  37. sensor_modeling/examples/demos/__init__.py +1 -0
  38. sensor_modeling/examples/demos/ambient_pipeline_demo.py +418 -0
  39. sensor_modeling/examples/demos/bernoulli_ar_demo.py +356 -0
  40. sensor_modeling/examples/demos/cpd_ar_demo.py +25 -0
  41. sensor_modeling/examples/demos/cpd_benchmark.py +42 -0
  42. sensor_modeling/examples/demos/hmm_granger_demo.py +30 -0
  43. sensor_modeling/examples/demos/nhpp_pelt_demo.py +80 -0
  44. sensor_modeling/examples/tutorials/__init__.py +1 -0
  45. sensor_modeling/fusion/__init__.py +46 -0
  46. sensor_modeling/fusion/defaults.py +296 -0
  47. sensor_modeling/fusion/emissions.py +339 -0
  48. sensor_modeling/fusion/estimate.py +375 -0
  49. sensor_modeling/fusion/filter.py +323 -0
  50. sensor_modeling/health/__init__.py +31 -0
  51. sensor_modeling/health/monitor.py +590 -0
  52. sensor_modeling/health/status.py +74 -0
  53. sensor_modeling/hmm/__init__.py +15 -0
  54. sensor_modeling/hmm/adaptive_hmm.py +22 -0
  55. sensor_modeling/hmm/base.py +134 -0
  56. sensor_modeling/hmm/circadian_hmm.py +22 -0
  57. sensor_modeling/hmm/heterogeneous_hmm.py +22 -0
  58. sensor_modeling/hmm/hierarchical_hmm.py +35 -0
  59. sensor_modeling/hmm/scaled_dirichlet_hmm.py +23 -0
  60. sensor_modeling/interop/__init__.py +57 -0
  61. sensor_modeling/interop/fhir.py +418 -0
  62. sensor_modeling/interop/privacy.py +308 -0
  63. sensor_modeling/models/__init__.py +12 -0
  64. sensor_modeling/models/bernoulli_ar/__init__.py +6 -0
  65. sensor_modeling/models/bernoulli_ar/base_model.py +569 -0
  66. sensor_modeling/models/bernoulli_ar/multivariate_model.py +411 -0
  67. sensor_modeling/models/change_point_detection/__init__.py +10 -0
  68. sensor_modeling/models/change_point_detection/deep.py +65 -0
  69. sensor_modeling/models/change_point_detection/pelt.py +159 -0
  70. sensor_modeling/models/nhpp_pelt/__init__.py +5 -0
  71. sensor_modeling/models/nhpp_pelt/bspline.py +96 -0
  72. sensor_modeling/models/nhpp_pelt/cli.py +243 -0
  73. sensor_modeling/models/nhpp_pelt/diagnostics.py +234 -0
  74. sensor_modeling/models/nhpp_pelt/io.py +58 -0
  75. sensor_modeling/models/nhpp_pelt/model.py +408 -0
  76. sensor_modeling/models/nhpp_pelt/optimizer.py +142 -0
  77. sensor_modeling/models/nhpp_pelt/plotting.py +218 -0
  78. sensor_modeling/models/nhpp_pelt/quad.py +72 -0
  79. sensor_modeling/models/nhpp_pelt/regularization.py +121 -0
  80. sensor_modeling/models/nhpp_pelt/utils.py +174 -0
  81. sensor_modeling/observations/__init__.py +59 -0
  82. sensor_modeling/observations/adapters.py +195 -0
  83. sensor_modeling/observations/ingest.py +269 -0
  84. sensor_modeling/observations/observation.py +270 -0
  85. sensor_modeling/observations/registry.py +262 -0
  86. sensor_modeling/observations/stream.py +342 -0
  87. sensor_modeling/observations/types.py +107 -0
  88. sensor_modeling/observations/units.py +117 -0
  89. sensor_modeling/online/__init__.py +36 -0
  90. sensor_modeling/online/benchmarks.py +242 -0
  91. sensor_modeling/online/pipeline.py +485 -0
  92. sensor_modeling/simulation/__init__.py +54 -0
  93. sensor_modeling/simulation/faults.py +191 -0
  94. sensor_modeling/simulation/household.py +862 -0
  95. sensor_modeling/states/__init__.py +23 -0
  96. sensor_modeling/states/markov.py +105 -0
  97. sensor_modeling/states/ontology.py +238 -0
  98. sensor_modeling/utils/__init__.py +41 -0
  99. sensor_modeling/utils/data_io.py +199 -0
  100. sensor_modeling/utils/logging_config.py +10 -0
  101. sensor_modeling/utils/missing.py +188 -0
  102. sensor_modeling/utils/plotting.py +98 -0
  103. sensor_modeling/utils/validation.py +117 -0
  104. sensor_modeling/visualization/__init__.py +3 -0
  105. sensor_modeling/visualization/clinical.py +67 -0
  106. sensor_modeling/visualization/interactive.py +208 -0
  107. sensor_modeling/visualization/research.py +60 -0
  108. sensor_modeling/visualization/web_app.py +137 -0
  109. sensor_modeling-0.2.0.dist-info/METADATA +683 -0
  110. sensor_modeling-0.2.0.dist-info/RECORD +114 -0
  111. sensor_modeling-0.2.0.dist-info/WHEEL +5 -0
  112. sensor_modeling-0.2.0.dist-info/entry_points.txt +18 -0
  113. sensor_modeling-0.2.0.dist-info/licenses/LICENSE +21 -0
  114. sensor_modeling-0.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,356 @@
1
+ """
2
+ Main Example and Testing Module
3
+
4
+ This module demonstrates how to use all the sensor modeling components
5
+ together and provides comprehensive testing examples.
6
+ """
7
+
8
+ import logging
9
+
10
+ from sensor_modeling.analysis import (
11
+ GrangerCausalityTest,
12
+ SensorDependencyNetwork,
13
+ calculate_behavioral_metrics,
14
+ )
15
+
16
+ # Import our modules
17
+ from sensor_modeling.models.bernoulli_ar import (
18
+ BernoulliAutoregressiveModel,
19
+ MultivariateAutoregressiveModel,
20
+ )
21
+ from sensor_modeling.utils import (
22
+ create_model_comparison_report,
23
+ export_analysis_results,
24
+ plot_quantile_intervals,
25
+ plot_sensor_activity_patterns,
26
+ simulate_sensor_data,
27
+ validate_model_predictions,
28
+ )
29
+
30
+ # Set up logging
31
+ logging.basicConfig(level=logging.INFO, format="%(levelname)s - %(message)s")
32
+ logger = logging.getLogger(__name__)
33
+
34
+
35
+ def run_single_sensor_example():
36
+ """Run example with single sensor modeling (original functionality)."""
37
+ print("\n" + "=" * 60)
38
+ print("SINGLE SENSOR MODEL EXAMPLE")
39
+ print("=" * 60)
40
+
41
+ # Simulate data
42
+ print("Simulating sensor data...")
43
+ data = simulate_sensor_data(n_days=30, n_sensors=4)
44
+
45
+ # Split into training and testing
46
+ split_idx = len(data) // 2
47
+ train_data = data.iloc[:split_idx]
48
+ test_data = data.iloc[split_idx:]
49
+
50
+ print(f"Training data: {len(train_data)} intervals")
51
+ print(f"Testing data: {len(test_data)} intervals")
52
+
53
+ # Initialize and fit model
54
+ target_sensor = "sensor_0"
55
+ model = BernoulliAutoregressiveModel(data.columns.tolist(), target_sensor)
56
+
57
+ print(f"\nFitting model for {target_sensor}...")
58
+ result = model.fit(train_data)
59
+
60
+ if result["convergence"]:
61
+ print("\nModel Parameters:")
62
+ for param, value in result["parameters"].items():
63
+ print(f" {param}: {value:.4f}")
64
+
65
+ print(f"\nSelected sensors: {result['selected_sensors']}")
66
+ print(f"Include seasonal: {result['include_seasonal']}")
67
+ print(f"BIC: {result['bic']:.2f}")
68
+
69
+ # Validate model
70
+ validation = validate_model_predictions(model, test_data, target_sensor)
71
+
72
+ if validation["validation_successful"]:
73
+ print("\nValidation Results:")
74
+ print(
75
+ f"Points outside 95% interval: {validation['outside_interval_count']}/96"
76
+ )
77
+ print(
78
+ f"Outside percentage: {validation['outside_interval_percentage']:.1f}%"
79
+ )
80
+ print("Expected: ~5.0%")
81
+ print(f"Well calibrated: {validation['is_well_calibrated']}")
82
+
83
+ # Plot results
84
+ try:
85
+ plot_quantile_intervals(
86
+ validation["actual_counts"],
87
+ validation["quantile_info"],
88
+ "Single Sensor Model Validation",
89
+ target_sensor,
90
+ )
91
+ except Exception as e:
92
+ print(f"Plotting skipped: {e}")
93
+
94
+ return {
95
+ "model": model,
96
+ "result": result,
97
+ "validation": validation if "validation" in locals() else None,
98
+ }
99
+
100
+
101
+ def run_granger_causality_example():
102
+ """Run example with Granger causality testing."""
103
+ print("\n" + "=" * 60)
104
+ print("GRANGER CAUSALITY ANALYSIS EXAMPLE")
105
+ print("=" * 60)
106
+
107
+ # Simulate data with stronger interactions
108
+ data = simulate_sensor_data(n_days=45, n_sensors=5, interaction_strength=0.5)
109
+
110
+ # Initialize Granger test
111
+ granger_test = GrangerCausalityTest(max_lags=3)
112
+
113
+ # Test all sensor pairs
114
+ print("Testing causality for all sensor pairs...")
115
+ causality_results = granger_test.test_all_pairs(data)
116
+
117
+ # Show significant relationships
118
+ significant = causality_results[causality_results["causality_detected"]]
119
+
120
+ print(f"\nFound {len(significant)} significant causal relationships:")
121
+ for _, row in significant.iterrows():
122
+ print(
123
+ f" {row['cause']} → {row['effect']} "
124
+ + f"(test stat: {row['test_statistic']:.3f}, p-value: {row['p_value']:.4f})"
125
+ )
126
+
127
+ # Create summary
128
+ summary = granger_test.create_causality_summary(causality_results)
129
+
130
+ print("\nCausality Summary:")
131
+ print(f" Total pairs tested: {summary['total_pairs_tested']}")
132
+ print(f" Significant relationships: {summary['significant_relationships']}")
133
+ print(f" Causality rate: {summary['causality_rate']:.3f}")
134
+
135
+ if summary["top_causes"]:
136
+ print(f" Top causal sensors: {list(summary['top_causes'].keys())[:3]}")
137
+
138
+ if summary["bidirectional_relationships"]:
139
+ print(
140
+ f" Bidirectional relationships: {summary['bidirectional_relationships']}"
141
+ )
142
+
143
+ return {"causality_results": causality_results, "summary": summary}
144
+
145
+
146
+ def run_dependency_network_example():
147
+ """Run example with dependency network analysis."""
148
+ print("\n" + "=" * 60)
149
+ print("SENSOR DEPENDENCY NETWORK EXAMPLE")
150
+ print("=" * 60)
151
+
152
+ # Use data with interactions
153
+ data = simulate_sensor_data(n_days=40, n_sensors=6, interaction_strength=0.4)
154
+
155
+ # Build network
156
+ network_builder = SensorDependencyNetwork(
157
+ significance_level=0.1
158
+ ) # Lenient for demo
159
+ network = network_builder.build_network(data)
160
+
161
+ # Get network statistics
162
+ net_stats = network_builder.get_network_statistics()
163
+ print("\nNetwork Statistics:")
164
+ print(f" Nodes: {net_stats['num_nodes']}")
165
+ print(f" Edges: {net_stats['num_edges']}")
166
+ print(f" Density: {net_stats['density']:.4f}")
167
+ print(f" Connected: {net_stats['is_connected']}")
168
+ print(f" Components: {net_stats['num_components']}")
169
+
170
+ # Identify sensor roles
171
+ roles = network_builder.identify_sensor_roles()
172
+ print("\nSensor Roles:")
173
+ for role, sensors in roles.items():
174
+ if sensors:
175
+ print(f" {role.capitalize()}: {sensors}")
176
+
177
+ # Find communities
178
+ communities = network_builder.detect_communities()
179
+ if communities:
180
+ print("\nCommunities detected:")
181
+ for i, community in enumerate(communities, 1):
182
+ print(f" Community {i}: {community}")
183
+
184
+ # Critical sensor analysis
185
+ critical_analysis = network_builder.find_critical_sensors()
186
+ if critical_analysis["most_critical"]:
187
+ print(f"\nMost critical sensor: {critical_analysis['most_critical']}")
188
+
189
+ # Visualization (skip if running headless)
190
+ try:
191
+ print("\nGenerating network visualizations...")
192
+ network_builder.plot_network()
193
+ network_builder.plot_causality_matrix()
194
+ except Exception as e:
195
+ print(f"Network visualization skipped: {e}")
196
+
197
+ return {"network": network, "network_builder": network_builder}
198
+
199
+
200
+ def run_multivariate_model_example():
201
+ """Run example with multivariate modeling."""
202
+ print("\n" + "=" * 60)
203
+ print("MULTIVARIATE MODEL EXAMPLE")
204
+ print("=" * 60)
205
+
206
+ # Generate data with clear interaction patterns
207
+ data = simulate_sensor_data(n_days=50, n_sensors=4, interaction_strength=0.6)
208
+
209
+ # Split data
210
+ split_idx = int(len(data) * 0.7)
211
+ train_data = data.iloc[:split_idx]
212
+ test_data = data.iloc[split_idx:]
213
+
214
+ print(f"Training: {len(train_data)} intervals")
215
+ print(f"Testing: {len(test_data)} intervals")
216
+
217
+ # Initialize multivariate model
218
+ multivariate_model = MultivariateAutoregressiveModel(data.columns.tolist())
219
+
220
+ # Fit with network-informed structure
221
+ print("\nFitting multivariate model with network structure...")
222
+ results = multivariate_model.fit_joint_model(train_data, use_network_structure=True)
223
+
224
+ # Show results for each sensor
225
+ print("\nMultivariate Model Results:")
226
+ converged_models = 0
227
+ for sensor, result in results.items():
228
+ if result["convergence"]:
229
+ converged_models += 1
230
+ print(f"\n{sensor}:")
231
+ print(f" Selected sensors: {result['selected_sensors']}")
232
+ print(f" Include seasonal: {result['include_seasonal']}")
233
+ print(f" BIC: {result['bic']:.2f}")
234
+
235
+ print(f"\nSuccessfully fitted {converged_models}/{len(results)} sensor models")
236
+
237
+ # Generate joint predictions
238
+ print("\nGenerating joint predictions...")
239
+ joint_predictions = multivariate_model.predict_joint_probabilities(test_data)
240
+ print(f"Joint predictions shape: {joint_predictions.shape}")
241
+
242
+ # Comprehensive interaction analysis
243
+ print("\nPerforming comprehensive interaction analysis...")
244
+ interaction_analysis = multivariate_model.analyze_sensor_interactions(train_data)
245
+
246
+ # Generate interaction report
247
+ report = multivariate_model.generate_interaction_report(train_data)
248
+ print(f"\n{report}")
249
+
250
+ # Model comparison
251
+ print("\nComparing different modeling approaches...")
252
+ model_comparison = multivariate_model.compare_model_approaches(train_data)
253
+ comparison_report = create_model_comparison_report(model_comparison)
254
+ print(f"\n{comparison_report}")
255
+
256
+ # Comprehensive visualization
257
+ try:
258
+ print("\nGenerating comprehensive interaction visualization...")
259
+ multivariate_model.plot_interaction_summary(train_data)
260
+ except Exception as e:
261
+ print(f"Comprehensive visualization skipped: {e}")
262
+
263
+ return {
264
+ "multivariate_model": multivariate_model,
265
+ "results": results,
266
+ "joint_predictions": joint_predictions,
267
+ "interaction_analysis": interaction_analysis,
268
+ "model_comparison": model_comparison,
269
+ }
270
+
271
+
272
+ def run_behavioral_analysis_example():
273
+ """Run example with behavioral pattern analysis."""
274
+ print("\n" + "=" * 60)
275
+ print("BEHAVIORAL PATTERN ANALYSIS EXAMPLE")
276
+ print("=" * 60)
277
+
278
+ # Generate data
279
+ data = simulate_sensor_data(n_days=30, n_sensors=5)
280
+
281
+ # Calculate behavioral metrics
282
+ print("Calculating behavioral metrics...")
283
+ behavioral_metrics = calculate_behavioral_metrics(data)
284
+
285
+ print("\nOverall Behavioral Patterns:")
286
+ print(f" Activity rate: {behavioral_metrics['overall_activity_rate']:.3f}")
287
+ print(f" Total activations: {behavioral_metrics['total_activations']}")
288
+ print(f" Peak activity hour: {behavioral_metrics['peak_activity_hour']}:00")
289
+ print(f" Quietest hour: {behavioral_metrics['quietest_hour']}:00")
290
+ print(f" Most active day: {behavioral_metrics['most_active_day']}")
291
+ print(f" Least active day: {behavioral_metrics['least_active_day']}")
292
+
293
+ print("\nSensor-Specific Patterns:")
294
+ for sensor, metrics in behavioral_metrics["sensor_metrics"].items():
295
+ print(f" {sensor}:")
296
+ print(f" Activation rate: {metrics['activation_rate']:.3f}")
297
+ print(
298
+ f" Longest inactive period: {metrics['longest_inactive_period']} intervals"
299
+ )
300
+ print(f" Daily variance: {metrics['daily_variance']:.2f}")
301
+
302
+ # Plot activity patterns
303
+ try:
304
+ print("\nGenerating activity pattern plots...")
305
+ plot_sensor_activity_patterns(data)
306
+ except Exception as e:
307
+ print(f"Activity pattern plotting skipped: {e}")
308
+
309
+ return {"behavioral_metrics": behavioral_metrics}
310
+
311
+
312
+ def run_comprehensive_demo():
313
+ """Run all examples in sequence for comprehensive demonstration."""
314
+ print("COMPREHENSIVE SENSOR MODELING DEMONSTRATION")
315
+ print("=" * 80)
316
+
317
+ all_results = {}
318
+
319
+ try:
320
+ # Run all examples
321
+ all_results["single_sensor"] = run_single_sensor_example()
322
+ all_results["granger_causality"] = run_granger_causality_example()
323
+ all_results["dependency_network"] = run_dependency_network_example()
324
+ all_results["multivariate_model"] = run_multivariate_model_example()
325
+ all_results["behavioral_analysis"] = run_behavioral_analysis_example()
326
+
327
+ print("\n" + "=" * 80)
328
+ print("DEMONSTRATION COMPLETE")
329
+ print("=" * 80)
330
+
331
+ print("\nSUMMARY:")
332
+ print("- Single sensor modeling: Baseline approach from Gillam et al. (2022)")
333
+ print("- Granger causality: Statistical testing for sensor interactions")
334
+ print("- Dependency networks: Graph-based analysis of sensor relationships")
335
+ print("- Multivariate modeling: Joint prediction of multiple sensors")
336
+ print("- Behavioral analysis: Pattern extraction and characterization")
337
+
338
+ print("\nAll components successfully demonstrated!")
339
+
340
+ except Exception as e:
341
+ logger.error(f"Demonstration failed: {e}")
342
+ print(f"Error during demonstration: {e}")
343
+
344
+ return all_results
345
+
346
+
347
+ if __name__ == "__main__":
348
+ # Run comprehensive demonstration
349
+ results = run_comprehensive_demo()
350
+
351
+ # Optional: Export results
352
+ try:
353
+ export_analysis_results(results, "comprehensive_demo_results")
354
+ print("\nResults exported to files.")
355
+ except Exception as e:
356
+ print(f"Export failed: {e}")
@@ -0,0 +1,25 @@
1
+ """Demo: combine Bernoulli AR model with change point detection."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from sensor_modeling.change_point import EmbeddingCPD
6
+ from sensor_modeling.models.bernoulli_ar import BernoulliAutoregressiveModel
7
+ from sensor_modeling.utils import SensorDataset, simulate_sensor_data
8
+
9
+
10
+ def main() -> None:
11
+ data = simulate_sensor_data(num_sensors=1, length=200)
12
+ sensor_name = data.columns[0]
13
+ dataset = SensorDataset(data)
14
+
15
+ model = BernoulliAutoregressiveModel([sensor_name], sensor_name)
16
+ model.fit(dataset)
17
+ probs = model.predict_probabilities(dataset)
18
+
19
+ cpd = EmbeddingCPD().fit(probs)
20
+ cps = cpd.predict(plot=True)
21
+ print("Detected change points:", cps)
22
+
23
+
24
+ if __name__ == "__main__":
25
+ main()
@@ -0,0 +1,42 @@
1
+ """Benchmark different change point detection approaches."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import time
6
+
7
+ import numpy as np
8
+
9
+ from sensor_modeling.change_point import (
10
+ AdaptiveNormalizer,
11
+ EmbeddingCPD,
12
+ EnergyEfficientCPD,
13
+ GeneticOptimizationCPD,
14
+ )
15
+ from sensor_modeling.utils import plot_benchmark_results
16
+
17
+
18
+ def _generate_data() -> np.ndarray:
19
+ rng = np.random.default_rng(0)
20
+ return np.concatenate([np.zeros(50), np.ones(50)]) + rng.normal(0, 0.1, 100)
21
+
22
+
23
+ def main() -> None:
24
+ series = _generate_data()
25
+ algorithms = {
26
+ "embedding": EmbeddingCPD(),
27
+ "energy": EnergyEfficientCPD(),
28
+ "adaptive": AdaptiveNormalizer(),
29
+ "genetic": GeneticOptimizationCPD(),
30
+ }
31
+ results = {}
32
+ for name, alg in algorithms.items():
33
+ start = time.perf_counter()
34
+ alg.fit(series)
35
+ cps = alg.predict()
36
+ results[name] = time.perf_counter() - start
37
+ print(f"{name}: {len(cps)} change points")
38
+ plot_benchmark_results(results)
39
+
40
+
41
+ if __name__ == "__main__":
42
+ main()
@@ -0,0 +1,30 @@
1
+ """Example combining HMM state sequences with Granger causality analysis."""
2
+
3
+ import pandas as pd
4
+
5
+ from sensor_modeling.analysis import GrangerCausalityTest
6
+ from sensor_modeling.hmm import HierarchicalHMM
7
+ from sensor_modeling.utils import SensorDataset, simulate_sensor_data
8
+
9
+
10
+ def main():
11
+ # Simulate binary sensor data for two sensors
12
+ data = simulate_sensor_data(n_sensors=2, n_timesteps=200)
13
+ dataset = SensorDataset(data)
14
+ df = dataset.to_dataframe()
15
+
16
+ # Fit an HMM to each sensor independently
17
+ state_df = pd.DataFrame()
18
+ for sensor in df.columns:
19
+ model = HierarchicalHMM(n_states=3, random_state=0)
20
+ model.fit(df[[sensor]].values)
21
+ state_df[sensor] = model.predict(df[[sensor]].values)
22
+
23
+ # Apply Granger causality test on the inferred state sequences
24
+ gtest = GrangerCausalityTest(max_lags=3)
25
+ results = gtest.test_all_pairs(state_df)
26
+ print(results)
27
+
28
+
29
+ if __name__ == "__main__":
30
+ main()
@@ -0,0 +1,80 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Callable, List
4
+
5
+ import matplotlib.pyplot as plt
6
+ import numpy as np
7
+
8
+ from sensor_modeling.models.nhpp_pelt import NHPPPELT, NHPPConfig
9
+ from sensor_modeling.models.nhpp_pelt.plotting import (
10
+ HistConfig,
11
+ PlotConfig,
12
+ plot_segments_and_intensities_with_histograms,
13
+ )
14
+
15
+ Array1D = np.ndarray
16
+
17
+
18
+ def simulate_ihpp(
19
+ rng: np.random.Generator,
20
+ lam: Callable[[Array1D], Array1D],
21
+ delta: float,
22
+ lam_max: float,
23
+ ) -> Array1D:
24
+ """Ogata thinning with a supplied upper bound lam_max >= sup_t λ(t)."""
25
+ t = 0.0
26
+ events: List[float] = []
27
+ while True:
28
+ t += rng.exponential(1.0 / lam_max)
29
+ if t > delta:
30
+ break
31
+ if rng.uniform() < float(lam(np.array([t])) / lam_max):
32
+ events.append(t)
33
+ return np.array(events, dtype=float)
34
+
35
+
36
+ def main() -> None:
37
+ rng = np.random.default_rng(7)
38
+ delta = 24.0
39
+
40
+ def shape_peak(mu_hour: float):
41
+ def lam(tt: Array1D) -> Array1D:
42
+ g1 = np.exp(-0.5 * ((tt - mu_hour) / 2.0) ** 2) / (2.0 * np.sqrt(2 * np.pi))
43
+ g2 = np.exp(-0.5 * ((tt - (mu_hour + 8.0)) / np.sqrt(8.0)) ** 2) / (
44
+ np.sqrt(8.0) * np.sqrt(2 * np.pi)
45
+ )
46
+ return 20.0 * (g1 + g2)
47
+
48
+ return lam
49
+
50
+ lam1 = shape_peak(6.0)
51
+ lam2 = shape_peak(9.0)
52
+
53
+ n1, n2 = 20, 20
54
+ lam_max = 5.0
55
+ days: List[Array1D] = [simulate_ihpp(rng, lam1, delta, lam_max) for _ in range(n1)]
56
+ days += [simulate_ihpp(rng, lam2, delta, lam_max) for _ in range(n2)]
57
+
58
+ cfg = NHPPConfig(
59
+ delta=delta,
60
+ degree=3,
61
+ n_basis=5,
62
+ knot_strategy="quantile",
63
+ min_seg_len=2, # avoid 1-day blips
64
+ )
65
+ model = NHPPPELT(cfg).fit(days)
66
+ print("Changepoints:", model.changepoints_)
67
+ print("Segments:", model.segments_)
68
+
69
+ plot_segments_and_intensities_with_histograms(
70
+ days,
71
+ model,
72
+ config=PlotConfig(grid_points=500),
73
+ hist=HistConfig(bins="fd", density=True, alpha=0.4),
74
+ save_path=None,
75
+ )
76
+ plt.show()
77
+
78
+
79
+ if __name__ == "__main__":
80
+ main()
@@ -0,0 +1 @@
1
+ """Tutorial notebooks and guides."""
@@ -0,0 +1,46 @@
1
+ """Multimodal sensor fusion into a probabilistic behavioural state.
2
+
3
+ The fusion layer answers ``P(Z_t | O_1:t)`` for asynchronous, heterogeneous,
4
+ partially missing observations, and reports the answer together with the
5
+ evidence that produced it.
6
+ """
7
+
8
+ from .defaults import EmissionDefaults, default_emission_for, default_emissions
9
+ from .emissions import (
10
+ BernoulliEmission,
11
+ BetaEmission,
12
+ EmissionModel,
13
+ GaussianEmission,
14
+ PoissonEventEmission,
15
+ )
16
+ from .estimate import (
17
+ EvidenceContribution,
18
+ Explanation,
19
+ StateEstimate,
20
+ belief_from_mapping,
21
+ belief_matrix,
22
+ )
23
+ from .filter import (
24
+ FusionConfig,
25
+ MultimodalBayesFilter,
26
+ NonMonotonicUpdateError,
27
+ )
28
+
29
+ __all__ = [
30
+ "BernoulliEmission",
31
+ "BetaEmission",
32
+ "EmissionDefaults",
33
+ "EmissionModel",
34
+ "EvidenceContribution",
35
+ "Explanation",
36
+ "FusionConfig",
37
+ "GaussianEmission",
38
+ "MultimodalBayesFilter",
39
+ "NonMonotonicUpdateError",
40
+ "PoissonEventEmission",
41
+ "StateEstimate",
42
+ "belief_from_mapping",
43
+ "default_emission_for",
44
+ "default_emissions",
45
+ "belief_matrix",
46
+ ]