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.
- sensor_modeling/__init__.py +45 -0
- sensor_modeling/alerts/__init__.py +26 -0
- sensor_modeling/alerts/alert.py +532 -0
- sensor_modeling/analysis/__init__.py +43 -0
- sensor_modeling/analysis/_frame.py +19 -0
- sensor_modeling/analysis/behavioral_analysis.py +57 -0
- sensor_modeling/analysis/behavioral_metrics.py +66 -0
- sensor_modeling/analysis/comparison.py +164 -0
- sensor_modeling/analysis/dependency_network.py +408 -0
- sensor_modeling/analysis/granger_causality.py +314 -0
- sensor_modeling/analysis/pipeline.py +168 -0
- sensor_modeling/analysis/reporting.py +109 -0
- sensor_modeling/baseline/__init__.py +30 -0
- sensor_modeling/baseline/adaptive.py +520 -0
- sensor_modeling/baseline/features.py +224 -0
- sensor_modeling/change_point/__init__.py +13 -0
- sensor_modeling/change_point/_validation.py +31 -0
- sensor_modeling/change_point/adaptive_normalization.py +55 -0
- sensor_modeling/change_point/embedding_cpd.py +60 -0
- sensor_modeling/change_point/energy_efficient.py +57 -0
- sensor_modeling/change_point/genetic_optimization.py +65 -0
- sensor_modeling/cli.py +416 -0
- sensor_modeling/context/__init__.py +33 -0
- sensor_modeling/context/occupancy.py +529 -0
- sensor_modeling/data/__init__.py +5 -0
- sensor_modeling/data/loaders.py +146 -0
- sensor_modeling/data/preprocessing.py +83 -0
- sensor_modeling/data/synthetic.py +121 -0
- sensor_modeling/data/validation.py +81 -0
- sensor_modeling/evaluation/__init__.py +92 -0
- sensor_modeling/evaluation/ablation.py +303 -0
- sensor_modeling/evaluation/attribution.py +474 -0
- sensor_modeling/evaluation/detection.py +297 -0
- sensor_modeling/evaluation/metrics.py +541 -0
- sensor_modeling/evaluation/provenance.py +309 -0
- sensor_modeling/examples/__init__.py +1 -0
- sensor_modeling/examples/demos/__init__.py +1 -0
- sensor_modeling/examples/demos/ambient_pipeline_demo.py +418 -0
- sensor_modeling/examples/demos/bernoulli_ar_demo.py +356 -0
- sensor_modeling/examples/demos/cpd_ar_demo.py +25 -0
- sensor_modeling/examples/demos/cpd_benchmark.py +42 -0
- sensor_modeling/examples/demos/hmm_granger_demo.py +30 -0
- sensor_modeling/examples/demos/nhpp_pelt_demo.py +80 -0
- sensor_modeling/examples/tutorials/__init__.py +1 -0
- sensor_modeling/fusion/__init__.py +46 -0
- sensor_modeling/fusion/defaults.py +296 -0
- sensor_modeling/fusion/emissions.py +339 -0
- sensor_modeling/fusion/estimate.py +375 -0
- sensor_modeling/fusion/filter.py +323 -0
- sensor_modeling/health/__init__.py +31 -0
- sensor_modeling/health/monitor.py +590 -0
- sensor_modeling/health/status.py +74 -0
- sensor_modeling/hmm/__init__.py +15 -0
- sensor_modeling/hmm/adaptive_hmm.py +22 -0
- sensor_modeling/hmm/base.py +134 -0
- sensor_modeling/hmm/circadian_hmm.py +22 -0
- sensor_modeling/hmm/heterogeneous_hmm.py +22 -0
- sensor_modeling/hmm/hierarchical_hmm.py +35 -0
- sensor_modeling/hmm/scaled_dirichlet_hmm.py +23 -0
- sensor_modeling/interop/__init__.py +57 -0
- sensor_modeling/interop/fhir.py +418 -0
- sensor_modeling/interop/privacy.py +308 -0
- sensor_modeling/models/__init__.py +12 -0
- sensor_modeling/models/bernoulli_ar/__init__.py +6 -0
- sensor_modeling/models/bernoulli_ar/base_model.py +569 -0
- sensor_modeling/models/bernoulli_ar/multivariate_model.py +411 -0
- sensor_modeling/models/change_point_detection/__init__.py +10 -0
- sensor_modeling/models/change_point_detection/deep.py +65 -0
- sensor_modeling/models/change_point_detection/pelt.py +159 -0
- sensor_modeling/models/nhpp_pelt/__init__.py +5 -0
- sensor_modeling/models/nhpp_pelt/bspline.py +96 -0
- sensor_modeling/models/nhpp_pelt/cli.py +243 -0
- sensor_modeling/models/nhpp_pelt/diagnostics.py +234 -0
- sensor_modeling/models/nhpp_pelt/io.py +58 -0
- sensor_modeling/models/nhpp_pelt/model.py +408 -0
- sensor_modeling/models/nhpp_pelt/optimizer.py +142 -0
- sensor_modeling/models/nhpp_pelt/plotting.py +218 -0
- sensor_modeling/models/nhpp_pelt/quad.py +72 -0
- sensor_modeling/models/nhpp_pelt/regularization.py +121 -0
- sensor_modeling/models/nhpp_pelt/utils.py +174 -0
- sensor_modeling/observations/__init__.py +59 -0
- sensor_modeling/observations/adapters.py +195 -0
- sensor_modeling/observations/ingest.py +269 -0
- sensor_modeling/observations/observation.py +270 -0
- sensor_modeling/observations/registry.py +262 -0
- sensor_modeling/observations/stream.py +342 -0
- sensor_modeling/observations/types.py +107 -0
- sensor_modeling/observations/units.py +117 -0
- sensor_modeling/online/__init__.py +36 -0
- sensor_modeling/online/benchmarks.py +242 -0
- sensor_modeling/online/pipeline.py +485 -0
- sensor_modeling/simulation/__init__.py +54 -0
- sensor_modeling/simulation/faults.py +191 -0
- sensor_modeling/simulation/household.py +862 -0
- sensor_modeling/states/__init__.py +23 -0
- sensor_modeling/states/markov.py +105 -0
- sensor_modeling/states/ontology.py +238 -0
- sensor_modeling/utils/__init__.py +41 -0
- sensor_modeling/utils/data_io.py +199 -0
- sensor_modeling/utils/logging_config.py +10 -0
- sensor_modeling/utils/missing.py +188 -0
- sensor_modeling/utils/plotting.py +98 -0
- sensor_modeling/utils/validation.py +117 -0
- sensor_modeling/visualization/__init__.py +3 -0
- sensor_modeling/visualization/clinical.py +67 -0
- sensor_modeling/visualization/interactive.py +208 -0
- sensor_modeling/visualization/research.py +60 -0
- sensor_modeling/visualization/web_app.py +137 -0
- sensor_modeling-0.2.0.dist-info/METADATA +683 -0
- sensor_modeling-0.2.0.dist-info/RECORD +114 -0
- sensor_modeling-0.2.0.dist-info/WHEEL +5 -0
- sensor_modeling-0.2.0.dist-info/entry_points.txt +18 -0
- sensor_modeling-0.2.0.dist-info/licenses/LICENSE +21 -0
- 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
|
+
]
|