Usage and Examples
This comprehensive guide demonstrates practical usage patterns and real-world examples of the AxisFuzzy analysis framework. Through hands-on examples and step-by-step tutorials, you’ll learn how to leverage the full power of fuzzy data analysis, from basic contract development to sophisticated model applications.
Each section builds upon previous concepts while providing standalone examples that you can adapt to your specific use cases. Whether you’re developing custom contracts, building reusable components, or creating complex analysis workflows, this guide provides the practical knowledge you need to succeed.
Contract Development Fundamentals
This section introduces the foundational concepts of contract-driven development within the AxisFuzzy analysis framework. You’ll learn how to leverage the contract system to build robust, type-safe analysis components that ensure data integrity throughout the analysis pipeline.
Learning Outcomes:
Understanding the Contract base architecture and validation mechanisms
Creating custom contracts for domain-specific data structures
Utilizing contract decorators for automatic type inference
Implementing contract inheritance and compatibility patterns
Applying built-in contracts for common analysis scenarios
Key Files: base.py, decorator.py, build_in.py
Reference Documentation: Contracts Deep Dive and Architecture
Note
Code examples in this section correspond to practical implementations
found in examples/analysis/ directory.
Understanding Contract Architecture
The Contract class serves as the fundamental building block for data validation
in the AxisFuzzy analysis system. Each contract encapsulates three core elements:
Identity: A unique name for registration and identification
Validation Logic: Runtime validation functions for data compliance
Inheritance Hierarchy: Parent-child relationships for polymorphic compatibility
from axisfuzzy.analysis.contracts import Contract
# Basic contract creation
def validate_positive_number(obj):
return isinstance(obj, (int, float)) and obj > 0
# Create a custom contract
ContractPositiveNumber = Contract(
name='PositiveNumber',
validator=validate_positive_number
)
# Validate data
result = ContractPositiveNumber.validate(5.0) # Returns True
invalid = ContractPositiveNumber.validate(-1) # Returns False
Contract Registry and Management
The contract system maintains a global registry that prevents naming conflicts and enables contract lookup by name:
# Contracts are automatically registered upon creation
print(Contract._registry.keys()) # Shows all registered contract names
# Retrieve contracts by name
retrieved_contract = Contract._registry['PositiveNumber']
# Contract names must be unique
try:
duplicate = Contract('PositiveNumber', lambda x: True)
except NameError as e:
print(f"Error: {e}") # Contract already registered
Custom Contract Development
Creating domain-specific contracts involves defining validation logic that captures your data requirements:
import pandas as pd
import numpy as np
from axisfuzzy.analysis.dataframe import FuzzyDataFrame
# Custom validator for decision matrices
def validate_decision_matrix(obj):
if not isinstance(obj, pd.DataFrame):
return False
# Must have numeric data only
return obj.select_dtypes(include=[np.number]).shape[1] == obj.shape[1]
# Create specialized contract
ContractDecisionMatrix = Contract(
name='DecisionMatrix',
validator=validate_decision_matrix
)
# Fuzzy-specific contract
def validate_fuzzy_weights(obj):
return (isinstance(obj, FuzzyDataFrame) and
obj.shape[1] == 1 and
obj.mtype is not None)
ContractFuzzyWeights = Contract(
name='FuzzyWeights',
validator=validate_fuzzy_weights
)
Contract Inheritance and Compatibility
Contracts support inheritance relationships that enable polymorphic data handling:
# Base contract for numeric vectors
ContractVector = Contract(
name='Vector',
validator=lambda obj: isinstance(obj, (list, np.ndarray, pd.Series))
)
# Specialized contract inheriting from base
ContractNormalizedVector = Contract(
name='NormalizedVector',
validator=lambda obj: (ContractVector.validate(obj) and
abs(np.sum(obj) - 1.0) < 1e-6),
parent=ContractVector
)
# Check compatibility
normalized_data = np.array([0.3, 0.4, 0.3])
is_compatible = ContractNormalizedVector.is_compatible_with(ContractVector)
print(f"Compatibility: {is_compatible}") # True
Contract Decorators for Type Inference
The @contract decorator automatically extracts contract information from
function type annotations:
from axisfuzzy.analysis.contracts import contract
from axisfuzzy.analysis.build_in import ContractCrispTable, ContractWeightVector, ContractScoreVector
import numpy as np
@contract
def calculate_weighted_scores(data: ContractCrispTable, weights: ContractWeightVector) -> ContractScoreVector:
"""Calculate weighted scores for decision alternatives."""
return np.dot(data.values, weights)
# The decorator attaches contract metadata
print(f"Input contracts: {calculate_weighted_scores._contract_inputs}")
print(f"Output contract: {calculate_weighted_scores._contract_outputs}")
Built-in Contract Patterns
AxisFuzzy provides a comprehensive set of built-in contracts for common analysis scenarios:
from axisfuzzy.analysis.build_in import (
ContractCrispTable, ContractFuzzyTable, ContractWeightVector,
ContractMatrix, ContractFuzzyNumber, ContractScoreVector
)
# Using built-in contracts for validation
crisp_data = pd.DataFrame([[1, 2, 3], [4, 5, 6]])
weights = np.array([0.3, 0.4, 0.3])
# Validate inputs before processing
if (ContractCrispTable.validate(crisp_data) and
ContractWeightVector.validate(weights)):
scores = np.dot(crisp_data.values, weights)
print(f"Calculated scores: {scores}")
Contract Composition and Advanced Patterns
Complex validation scenarios can be addressed through contract composition:
# Composite validation for multi-criteria data
def validate_mcda_dataset(obj):
return (ContractCrispTable.validate(obj) and
obj.shape[0] >= 2 and # At least 2 alternatives
obj.shape[1] >= 2 and # At least 2 criteria
not obj.isnull().any().any()) # No missing values
ContractMCDADataset = Contract(
name='MCDADataset',
validator=validate_mcda_dataset,
parent=ContractCrispTable
)
# Usage in analysis functions
@contract
def perform_mcda_analysis(dataset: ContractMCDADataset) -> 'ContractRankingResult':
"""Perform multi-criteria decision analysis."""
# Implementation details...
pass
Component Development Mastery
Note
This section covers component development patterns, including custom component creation, lifecycle management, and contract integration.
Learning Outcomes:
Master the AnalysisComponent architecture and design principles
Implement custom components with proper contract integration
Understand component lifecycle and configuration management
Apply best practices for reusable component development
Key Files:
component/base.py- Base component architecturecomponent/basic.py- Built-in utility components
Reference Documentation:
Components and Pipeline - Comprehensive component framework guide
Component Architecture Foundation
The AnalysisComponent serves as the foundational
base class for all analysis tools. This marker pattern promotes object-oriented design,
enabling better state management and configuration serialization.
from axisfuzzy.analysis.component.base import AnalysisComponent
from axisfuzzy.analysis.contracts import contract, Contract
class CustomProcessor(AnalysisComponent):
def __init__(self, threshold: float = 0.5):
self.threshold = threshold
def get_config(self) -> dict:
return {'threshold': self.threshold}
@contract
def run(self, data: 'ContractCrispTable') -> 'ContractCrispTable':
# Implementation logic here
return processed_data
The architecture enforces two essential methods: run() for execution logic and
get_config() for configuration serialization.
Built-in Component Implementation
The framework provides utility components for common operations. The
ToolNormalization demonstrates typical usage:
from axisfuzzy.analysis.component.basic import ToolNormalization
# Initialize with configuration
normalizer = ToolNormalization(method='min_max', axis=1)
# Execute with contract validation
normalized_data = normalizer.run(crisp_data)
# Access configuration for serialization
config = normalizer.get_config() # {'method': 'min_max', 'axis': 1}
Built-in components include ToolNormalization, ToolWeightNormalization, ToolStatistics, and ToolFuzzification.
Component Lifecycle Management
Components follow a structured lifecycle pattern supporting both immediate execution and pipeline integration:
# 1. Initialization Phase
component = ToolNormalization(method='z_score', axis=0)
# 2. Configuration Access
config = component.get_config()
# 3. Execution Phase
result = component.run(input_data)
# 4. Serialization Support
import json
serialized_config = json.dumps(config)
restored_component = ToolNormalization(**json.loads(serialized_config))
The get_config() method ensures components can be serialized and reconstructed,
enabling model persistence and pipeline reproducibility.
Contract Integration and Custom Development
Components leverage the contract system for type safety. The @contract decorator
automatically validates inputs and outputs:
from axisfuzzy.analysis.component.base import AnalysisComponent
from axisfuzzy.analysis.contracts import contract, Contract
import numpy as np
class OutlierDetector(AnalysisComponent):
def __init__(self, method: str = 'iqr', threshold: float = 1.5):
self.method = method
self.threshold = threshold
def get_config(self) -> dict:
return {'method': self.method, 'threshold': self.threshold}
@contract
def run(self, data: 'ContractCrispTable') -> 'ContractCrispTable':
"""Detect outliers using IQR method."""
if self.method == 'iqr':
Q1 = np.percentile(data, 25, axis=0)
Q3 = np.percentile(data, 75, axis=0)
IQR = Q3 - Q1
lower_bound = Q1 - self.threshold * IQR
upper_bound = Q3 + self.threshold * IQR
outlier_mask = (data < lower_bound) | (data > upper_bound)
# Process outliers as needed
return data
Best Practices Summary
Effective component development follows these principles:
Configuration Management: Implement
get_config()with JSON-serializable parametersContract Compliance: Use type annotations with contract decorators for validation
State Encapsulation: Store configuration in instance variables during initialization
Error Handling: Implement graceful error handling with informative messages
Documentation: Provide comprehensive docstrings following NumPy style conventions
Pipeline Core Architecture
Note
Learning Outcomes: Master DAG-based pipeline construction, data flow orchestration, and performance optimization for complex fuzzy analysis workflows.
Pipeline Design Philosophy
The FuzzyPipeline implements a Directed Acyclic Graph (DAG) execution engine that
separates workflow definition from execution. This architecture provides:
Declarative Construction
Pipelines use a fluent API describing what should happen, not how:
from axisfuzzy.analysis.pipeline import FuzzyPipeline
from axisfuzzy.analysis.contracts import Contract
pipeline = FuzzyPipeline(name="Analysis Workflow")
# Declare inputs with type contracts
raw_data = pipeline.input("raw_data", contract=Contract.get('ContractCrispTable'))
weights = pipeline.input("weights", contract=Contract.get('ContractWeightVector'))
# Define processing steps
normalized = pipeline.add(normalizer.run, data=raw_data)
scored = pipeline.add(scorer.run, data=normalized, weights=weights)
Lazy Evaluation Benefits
Optimization: Engine analyzes entire graph before execution
Validation: Type contracts checked before computation begins
Debugging: Complete workflow can be inspected and visualized
Pipeline Construction Patterns
Linear Processing
from axisfuzzy.analysis.component.basic import ToolNormalization, ToolSimpleAggregation
pipeline = FuzzyPipeline(name="Linear Processing")
data = pipeline.input("data", contract=Contract.get('ContractCrispTable'))
normalizer = ToolNormalization(method='min_max')
aggregator = ToolSimpleAggregation(operation='mean')
normalized = pipeline.add(normalizer.run, data=data)
result = pipeline.add(aggregator.run, data=normalized)
Multi-Input Convergence
pipeline = FuzzyPipeline(name="Multi-Input Analysis")
criteria_data = pipeline.input("criteria", contract=Contract.get('ContractCrispTable'))
expert_weights = pipeline.input("weights", contract=Contract.get('ContractWeightVector'))
normalized_criteria = pipeline.add(normalizer.run, data=criteria_data)
weighted_analysis = pipeline.add(
weighted_scorer.run,
data=normalized_criteria,
weights=expert_weights
)
Parallel Processing
raw_data = pipeline.input("data", contract=Contract.get('ContractCrispTable'))
# Multiple parallel branches
statistical_summary = pipeline.add(statistics.run, data=raw_data)
fuzzy_analysis = pipeline.add(fuzzifier.run, data=raw_data)
correlation_matrix = pipeline.add(correlator.run, data=raw_data)
Data Flow Management
StepOutput Objects
Pipeline steps return StepOutput objects as symbolic references:
# StepOutput represents a "promise" of future data
normalized_data = pipeline.add(normalizer.run, data=input_data)
final_result = pipeline.add(analyzer.run, data=normalized_data)
Contract-Based Validation
from axisfuzzy.analysis.contracts import contract
from axisfuzzy.analysis.build_in import ContractCrispTable, ContractScoreVector
class TypeSafeComponent(AnalysisComponent):
@contract
def run(self, data: ContractCrispTable) -> ContractScoreVector:
return self.process(data) # Automatic validation
Execution State Management
# Step-by-step execution control
initial_state = pipeline.start_execution(input_data)
while not initial_state.is_complete():
initial_state = initial_state.run_next()
print(f"Completed: {initial_state.latest_step_id}")
Performance Optimization
Execution Order Optimization
The engine automatically determines optimal execution order using topological sorting:
execution_order = pipeline.get_execution_order()
print(f"Optimized order: {[step.display_name for step in execution_order]}")
Memory-Efficient Execution
# Iterative execution for large datasets
for step_info in pipeline.step_by_step(input_data):
print(f"Step: {step_info.step_name} - {step_info.execution_time} ms")
Pipeline Visualization
# Debug and optimize with visualization
pipeline.visualize(
output_path="pipeline_graph.png",
show_contracts=True,
highlight_critical_path=True
)
Advanced Patterns and Best Practices
Nested Pipeline Composition
from axisfuzzy.analysis.component.basic import ToolNormalization
# Hierarchical pipeline composition
preprocessing_pipeline = FuzzyPipeline(name="Preprocessing")
raw_input = preprocessing_pipeline.input("raw_data", contract=Contract.get('ContractCrispTable'))
cleaner = ToolNormalization(method='min_max')
cleaned_data = preprocessing_pipeline.add(cleaner.run, data=raw_input)
main_pipeline = FuzzyPipeline(name="Main Analysis")
main_input = main_pipeline.input("main_data", contract=Contract.get('ContractCrispTable'))
preprocessed = main_pipeline.add(preprocessing_pipeline, raw_data=main_input)
Error Handling
from axisfuzzy.analysis.component.base import AnalysisComponent
from axisfuzzy.analysis.contracts import contract, Contract
class RobustComponent(AnalysisComponent):
@contract
def run(self, data: 'ContractCrispTable') -> 'ContractCrispTable':
try:
return self.process_data(data)
except Exception as e:
return self.fallback_processing(data)
Best Practices
Single Responsibility: Each step has one clear purpose
Type Safety: Use contract annotations for validation
Immutability: Return new objects instead of modifying inputs
Error Handling: Implement graceful degradation patterns
Documentation: Use descriptive names for steps and components
Model API Applications
The Model API provides a PyTorch-inspired interface for building sophisticated fuzzy analysis workflows. Models serve as high-level blueprints that automatically generate optimized pipeline execution graphs, focusing on what your analysis should accomplish rather than how it should be executed.
Understanding Model Architecture
The Model Abstraction Layer
Models automatically register analysis components and handle dependency tracking:
from axisfuzzy.analysis.app.model import Model
from axisfuzzy.analysis.component.basic import (
ToolNormalization, ToolFuzzification, ToolSimpleAggregation
)
class BasicAnalysisModel(Model):
def __init__(self, fuzzifier):
super().__init__()
self.normalizer = ToolNormalization(method='min_max', axis=0)
self.fuzzifier = ToolFuzzification(fuzzifier=fuzzifier)
self.aggregator = ToolSimpleAggregation(operation='mean', axis=1)
def get_config(self) -> dict:
return {'fuzzifier': self.fuzzifier.fuzzifier}
def forward(self, data):
normalized_data = self.normalizer(data)
fuzzy_data = self.fuzzifier(normalized_data)
return self.aggregator(fuzzy_data)
Forward Method Design Patterns
Linear Processing Workflows
Sequential data transformation through analysis components:
class LinearAnalysisModel(Model):
def forward(self, input_data):
x = self.step1(input_data)
x = self.step2(x)
return self.step3(x)
Branching and Parallel Processing
Parallel data processing paths that converge at aggregation points:
class BranchingAnalysisModel(Model):
def __init__(self):
super().__init__()
self.data_normalizer = ToolNormalization(method='min_max')
self.weight_normalizer = ToolNormalization(method='sum_to_one')
self.aggregator = ToolWeightedAggregation(operation='topsis')
def forward(self, data, weights):
# Process data and weight branches separately
processed_data = self.data_normalizer(data)
processed_weights = self.weight_normalizer(weights)
# Combine branches
return self.aggregator(processed_data, processed_weights)
Conditional Processing Logic
Adaptive processing based on input characteristics:
class AdaptiveAnalysisModel(Model):
def forward(self, data):
normalized = self.normalizer(data)
# Choose processing path based on data size
if data.shape[0] < 100:
return self.light_processor(normalized)
else:
return self.heavy_processor(normalized)
Model Composition Strategies
Hierarchical Model Architecture
Complex workflows decomposed into specialized model layers:
class PreprocessingModel(Model):
def forward(self, raw_data):
cleaned = self.cleaner(raw_data)
return self.normalizer(cleaned)
class MainAnalysisModel(Model):
def __init__(self, preprocessing_model):
super().__init__()
self.preprocessor = preprocessing_model
self.fuzzifier = ToolFuzzification(fuzzifier=my_fuzzifier)
self.analyzer = ToolComplexAggregation(operation='electre')
def forward(self, raw_data):
preprocessed = self.preprocessor(raw_data)
fuzzy_data = self.fuzzifier(preprocessed)
return self.analyzer(fuzzy_data)
Model Ensemble Patterns
Combining multiple models for robust analysis results:
class EnsembleAnalysisModel(Model):
def forward(self, data, weights=None):
result_a = self.model_a(data)
result_b = self.model_b(data, weights)
return self.ensemble_aggregator([result_a, result_b])
Execution and Optimization
Automatic Pipeline Generation
Models automatically generate optimized execution pipelines:
# Model execution builds and optimizes pipeline automatically
model = MainAnalysisModel(PreprocessingModel())
result = model(input_data)
# Access generated pipeline for inspection
pipeline = model.pipeline
print(f"Pipeline steps: {len(pipeline.components)}")
Performance Optimization
Built-in optimization strategies for large datasets:
class OptimizedAnalysisModel(Model):
def forward(self, large_dataset):
# Automatic batching for memory efficiency
batched_results = self.batch_processor(large_dataset)
# Parallel aggregation for speed
return self.parallel_aggregator(batched_results)
Model Serialization
Models support serialization for deployment:
# Save and reconstruct model configuration
model_config = model.get_config()
new_model = MainAnalysisModel.from_config(model_config)
Data Structure Integration
FuzzyDataFrame serves as the cornerstone data structure for fuzzy analysis workflows, providing seamless integration between pandas-style data manipulation and AxisFuzzy’s analysis framework.
FuzzyDataFrame in Analysis Workflows
From Pandas to Fuzzy Analysis
Convert existing pandas DataFrames using the .fuzzy accessor:
import pandas as pd
from axisfuzzy.fuzzifier import Fuzzifier
# Start with traditional pandas DataFrame
crisp_data = pd.DataFrame({
'performance': [0.85, 0.72, 0.91, 0.68],
'reliability': [0.78, 0.89, 0.82, 0.75]
})
# Configure fuzzification strategy
fuzzifier = Fuzzifier(mf='gaussmf', mtype='qrofn', pi=0.2)
# Convert to FuzzyDataFrame using accessor
fuzzy_data = crisp_data.fuzzy.to_fuzz_dataframe(fuzzifier=fuzzifier)
Direct FuzzyDataFrame Construction
Construct FuzzyDataFrame directly from Fuzzarray objects:
from axisfuzzy.core import Fuzzarray
from axisfuzzy.analysis.dataframe import FuzzyDataFrame
# Create Fuzzarray columns with specific fuzzy numbers
performance_array = Fuzzarray([
(0.85, 0.10), (0.72, 0.20), (0.91, 0.05), (0.68, 0.25)
], mtype='qrofn')
# Construct FuzzyDataFrame
fuzzy_df = FuzzyDataFrame({
'performance': performance_array
}, index=['Project_A', 'Project_B', 'Project_C', 'Project_D'])
Contract Integration Patterns
FuzzyDataFrame as Contract Types
FuzzyDataFrame integrates seamlessly with AxisFuzzy’s contract system:
from axisfuzzy.analysis.build_in import ContractFuzzyTable
# FuzzyDataFrame automatically satisfies fuzzy table contracts
def process_fuzzy_data(data: ContractFuzzyTable) -> ContractFuzzyTable:
aggregator = ToolSimpleAggregation(operation='mean', axis=1)
return aggregator.run(data)
result = process_fuzzy_data(fuzzy_data)
Custom Contract Validation
Create specialized contracts for domain-specific requirements:
from axisfuzzy.analysis.contracts import Contract
class ContractProjectEvaluation(Contract):
def validate(self, data) -> bool:
if not isinstance(data, FuzzyDataFrame):
return False
required_columns = {'performance', 'reliability'}
return required_columns.issubset(set(data.columns))
Component Integration Strategies
FuzzyDataFrame-Aware Components
Design components that leverage FuzzyDataFrame’s structure:
from axisfuzzy.analysis.component import AnalysisComponent
class FuzzyDataFrameProcessor(AnalysisComponent):
def __init__(self, weight_column: str = None):
super().__init__()
self.weight_column = weight_column
@contract(input_data=ContractFuzzyTable, output=ContractFuzzyTable)
def run(self, input_data: FuzzyDataFrame) -> FuzzyDataFrame:
# Leverage FuzzyDataFrame's column structure
if self.weight_column and self.weight_column in input_data.columns:
weights = input_data[self.weight_column]
# Process weighted operations
return self.process_weighted(input_data, weights)
return input_data
Pipeline Integration Patterns
FuzzyDataFrame flows naturally through analysis pipelines:
from axisfuzzy.analysis.pipeline import FuzzyPipeline
# Create pipeline that processes FuzzyDataFrame
pipeline = FuzzyPipeline("fuzzy_dataframe_analysis")
input_data = pipeline.input("fuzzy_data", contract=ContractFuzzyTable)
# Components work with FuzzyDataFrame structure
normalized = pipeline.add(
ToolNormalization(method='min_max', axis=0).run,
data=input_data
)
result = pipeline.run(fuzzy_data=fuzzy_data)
Performance Optimization Techniques
Memory-Efficient Operations
FuzzyDataFrame leverages Fuzzarray’s backend for optimized memory usage:
def efficient_fuzzy_processing(fuzzy_df: FuzzyDataFrame) -> FuzzyDataFrame:
# Column-wise operations are optimized
processed_columns = {}
for column_name in fuzzy_df.columns:
column_data = fuzzy_df[column_name] # Returns Fuzzarray
# Fuzzarray operations are vectorized and memory-efficient
processed_columns[column_name] = column_data
return FuzzyDataFrame(processed_columns, index=fuzzy_df.index)
Batch Processing Strategies
Handle large datasets efficiently:
def process_large_fuzzy_dataset(large_fuzzy_df: FuzzyDataFrame,
chunk_size: int = 1000) -> FuzzyDataFrame:
results = []
total_rows = len(large_fuzzy_df)
for start_idx in range(0, total_rows, chunk_size):
end_idx = min(start_idx + chunk_size, total_rows)
chunk = large_fuzzy_df.iloc[start_idx:end_idx]
processed_chunk = efficient_fuzzy_processing(chunk)
results.append(processed_chunk)
return combine_fuzzy_dataframes(results)
Advanced Integration Patterns
Model-FuzzyDataFrame Integration
Combine FuzzyDataFrame with the Model API:
from axisfuzzy.analysis.app.model import Model
class FuzzyDataFrameAnalysisModel(Model):
def __init__(self):
super().__init__()
self.processor = FuzzyDataFrameProcessor(weight_column='importance')
self.aggregator = ToolSimpleAggregation(operation='weighted_mean')
def forward(self, fuzzy_data: ContractFuzzyTable):
processed = self.processor(fuzzy_data)
return self.aggregator(processed)
Interoperability with External Systems
FuzzyDataFrame maintains compatibility with pandas ecosystem:
def export_fuzzy_results(fuzzy_df: FuzzyDataFrame) -> pd.DataFrame:
# Extract membership degrees for traditional analysis
membership_data = {}
for column in fuzzy_df.columns:
membership_data[f"{column}_membership"] = [
fn.membership for fn in fuzzy_df[column]
]
return pd.DataFrame(membership_data, index=fuzzy_df.index)
Complete Model Implementation Example
This section demonstrates a comprehensive Model implementation that integrates multiple analysis components into a cohesive workflow. The example showcases advanced Model patterns including multi-input processing, component composition, and structured output generation.
Multi-Component Analysis Model
The following example implements a complete fuzzy data analysis model that processes crisp data through normalization and aggregation stages:
import pandas as pd
import numpy as np
from axisfuzzy.analysis.app.model import Model
from axisfuzzy.analysis.component.basic import (
ToolNormalization, ToolSimpleAggregation
)
from axisfuzzy.analysis.build_in import ContractCrispTable
class ComprehensiveAnalysisModel(Model):
"""
A multi-stage analysis model demonstrating advanced Model patterns.
This model processes crisp data through normalization and aggregation
stages, demonstrating proper Model usage patterns.
"""
def __init__(self, norm_method: str = 'min_max'):
super().__init__()
# Initialize analysis components
self.data_normalizer = ToolNormalization(method=norm_method, axis=0)
self.aggregator = ToolSimpleAggregation(operation='mean', axis=1)
def get_config(self) -> dict:
"""Return model configuration for reproducibility."""
return {
'normalization_method': self.data_normalizer.method,
'aggregation_operation': self.aggregator.operation
}
def forward(self, data: ContractCrispTable):
"""
Define the analysis workflow through component composition.
The forward method demonstrates Model's declarative approach to
workflow definition, where component calls are automatically
translated into pipeline operations.
IMPORTANT: In forward(), all variables are symbolic placeholders
(StepOutput objects). You cannot access their properties like .columns
or perform direct data operations. The actual computation happens
when model.run() is called.
"""
# Primary data processing branch - these are symbolic operations
normalized_data = self.data_normalizer(data)
aggregated_result = self.aggregator(normalized_data)
# Return the final symbolic result
return aggregated_result
Model Usage and Execution
The following demonstrates complete model instantiation, building, and execution:
# Prepare sample data
sample_data = pd.DataFrame({
'Criterion_A': [0.8, 0.6, 0.9, 0.7, 0.5],
'Criterion_B': [0.7, 0.8, 0.6, 0.9, 0.8],
'Criterion_C': [0.9, 0.7, 0.8, 0.6, 0.7]
})
# Initialize and build model
model = ComprehensiveAnalysisModel(norm_method='z_score')
model.build() # Automatic pipeline construction
# Method 1: Execute using pandas fuzzy accessor (recommended)
results = sample_data.fuzzy.run(model, return_intermediate=True)
final_result = results[0] # Final aggregated scores
intermediate_steps = results[1] # Dictionary of intermediate results
# Method 2: Direct model execution
direct_result = model.run(sample_data)
# Display results
print(f"Final aggregated scores: {final_result}")
print(f"Number of intermediate steps: {len(intermediate_steps)}")
print(f"Direct execution result: {direct_result}")
# Access model configuration
config = model.get_config()
print(f"Model configuration: {config}")
This example demonstrates Model’s proper usage patterns:
Symbolic Computation: The forward() method defines computation graph structure
Execution Separation: Actual data processing occurs during run() calls
Multiple Execution Methods: Support for both accessor and direct execution
Configuration Management: Serializable model configuration for reproducibility