import sys
import os
import numpy as np
import pandas as pd
import random
import itertools
from scipy.optimize import curve_fit
from sklearn.metrics import r2_score

# 添加项目根目录到Python路径
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', '..')))

from myffe.tools.Loggerv1_1 import log_class
from myffe.tools.color_printer import ColorPrinter
from myffe.tools.evaluation_decorator import with_evaluation
from myffe.tools.data_inspector import inspect_data
from myffe.tools.param_utils import convert_to_list

# 尝试导入可选依赖
try:
    from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor
    from sklearn.preprocessing import LabelEncoder
    from sklearn.decomposition import PCA, KernelPCA
    from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
    sklearn_available = True
except ImportError:
    sklearn_available = False

@log_class(type='use')
class RelativePreprocessing:
    def __init__(self, shortcut_relative=None):
        self.shortcut_relative = shortcut_relative

    @with_evaluation
    def __call__(self, data, clean_type=None, data_label=None):
        self.data_label = data_label
        self.clean_type = clean_type
        
        # 分离标签列和特征列
        label_data = None
        feature_data = data.copy()
        if data_label and data_label in feature_data.columns:
            label_data = feature_data.pop(data_label)
            ColorPrinter.print_info(f'已分离标签列: {data_label}')
        
        self.data = feature_data
        ColorPrinter.print_progress('开始相关性分析和特征工程')
        
        # 使用 pandas 处理数据
        ColorPrinter.print_info('使用 pandas 处理')
        processed_data = self._process_with_pandas(feature_data)
        
        # 只返回特征列，不包含标签列
        return processed_data
    
    def _process_with_pandas(self, data):
        """使用pandas处理数据"""
        if self.clean_type == 'advance':
            data = self.relative_advance_switch(data)
        else:
            data = self.relative_normal_switch(data)
        return data

    def linear_plus(self, data, cols, threshold=0.75):
        if len(cols) < 2:
            ColorPrinter.print_error('列数必须大于2')
            return data
        if not isinstance(threshold, (int, float)):
            ColorPrinter.print_error('阈值必须是浮点数或整数')
            return data

        feature_cols = [col for col in cols if col != self.data_label]
        if len(feature_cols) < 2:
            ColorPrinter.print_error("需要至少2个特征列进行线性组合")
            return data

        # 检查并处理NaN值
        if data[feature_cols].isnull().any().any():
            ColorPrinter.print_warning("警告: 线性组合处理前检测到NaN值，将自动填充")
            for col in feature_cols:
                if data[col].isnull().any():
                    data[col] = data[col].fillna(data[col].mean())
                    ColorPrinter.print_progress(f"  已填充列 {col} 的NaN值")

        # 计算相关系数矩阵
        data_values = data[feature_cols].values
        
        # 使用纯Python实现
        ColorPrinter.print_info("使用纯Python实现计算相关系数矩阵")
        # 计算相关系数矩阵
        cm = np.corrcoef(data_values, rowvar=False)
        # 找出相关系数大于阈值的特征对
        max_cols = []
        n_features = cm.shape[0]
        for i in range(n_features):
            for j in range(i + 1, n_features):
                if abs(cm[i, j]) > threshold:
                    max_cols.append((i, j))
        
        for max_ in max_cols:
            drop_relative = random.choices(max_, k=1)
            col_name = feature_cols[drop_relative[0]]
            data.drop(col_name, axis=1, inplace=True)
        return data

    def feature_plus(self, data, cols, threshold=0.75, relation_func='func1'):
        """
        非线性特征构建
        
        通过函数拟合发现列之间的函数关系，并添加新的特征列
        支持的函数关系：
        - 二次函数：a*x^2 + b*x + c
        - 三次函数：a*x^3 + b*x^2 + c*x + d
        - 指数函数：a*exp(b*x) + c
        - 对数函数：a*log(x) + b
        - 平方根函数：a*sqrt(x) + b
        
        Args:
            data: 输入数据
            cols: 要分析的列名列表
            threshold: R²阈值，大于此值才添加新特征
            relation_func: 函数类型，可选值：'func1'(二次)、'func2'(三次)、'func3'(指数)、'func4'(对数)、'func5'(平方根)
            
        Returns:
            处理后的数据
        """
        
        
        if len(cols) < 2:
            ColorPrinter.print_error('列数必须大于2')
            return data
        if not isinstance(threshold, (int, float)):
            ColorPrinter.print_error('阈值必须是浮点数或整数')
            return data

        # 排除标签列并过滤出存在的列
        feature_cols = [col for col in cols if col != self.data_label and col in data.columns]
        if len(feature_cols) < 2:
            ColorPrinter.print_error("需要至少2个特征列进行特征构建")
            return data

        # 只处理数值列
        numeric_cols = [col for col in feature_cols if data[col].dtype in ['int64', 'float64']]
        if len(numeric_cols) < 2:
            ColorPrinter.print_error("需要至少2个数值列进行特征构建")
            return data

        # 检查并处理NaN值
        if data[numeric_cols].isnull().any().any():
            ColorPrinter.print_warning("警告: 特征构建处理前检测到NaN值，将自动填充")
            for col in numeric_cols:
                if data[col].isnull().any():
                    data[col] = data[col].fillna(data[col].mean())
                    ColorPrinter.print_progress(f"  已填充列 {col} 的NaN值")

        # 定义函数关系
        def func1(x, a, b, c):
            """二次函数：a*x^2 + b*x + c"""
            return a * x ** 2 + b * x + c

        def func2(x, a, b, c, d):
            """三次函数：a*x^3 + b*x^2 + c*x + d"""
            return a * x ** 3 + b * x ** 2 + c * x + d

        def func3(x, a, b, c):
            """指数函数：a*exp(b*x) + c"""
            return a * np.exp(b * x) + c
        
        def func4(x, a, b):
            """对数函数：a*log(x) + b"""
            return a * np.log(x + 1e-8) + b
        
        def func5(x, a, b):
            """平方根函数：a*sqrt(x) + b"""
            return a * np.sqrt(x + 1e-8) + b

        # 获取所有两列组合
        combinations_list = list(itertools.combinations(numeric_cols, 2))
        new_features = []

        for col1, col2 in combinations_list:
            try:
                x = data[col1].values
                y = data[col2].values
                
                # 根据选择的函数类型进行拟合
                if relation_func == 'func1':
                    # 二次函数拟合
                    try:
                        popt, _ = curve_fit(func1, x, y, maxfev=5000)
                        a, b, c = popt
                        y_fit = func1(x, a, b, c)
                        r2 = r2_score(y, y_fit)
                        
                        if r2 > threshold:
                            data[f'{col1}_square'] = x ** 2
                            new_features.append(f'{col1}_square')
                        else:
                            ColorPrinter.print_info(f'{col1}和{col2}之间没有显著的二次函数关系 (R²={r2:.3f})')
                    except Exception as fit_error:
                        ColorPrinter.print_error(f'{col1}和{col2}的二次函数拟合失败: {fit_error}')
                
                elif relation_func == 'func2':
                    # 三次函数拟合
                    try:
                        popt, _ = curve_fit(func2, x, y, maxfev=5000)
                        a, b, c, d = popt
                        y_fit = func2(x, a, b, c, d)
                        r2 = r2_score(y, y_fit)
                        
                        if r2 > threshold:
                            data[f'{col1}_cube'] = x ** 3
                            data[f'{col2}_cube'] = y ** 3
                            data[f'{col2}_square'] = x ** 2
                            new_features.extend([f'{col1}_cube', f'{col2}_cube', f'{col2}_square'])
                        else:
                            ColorPrinter.print_info(f'{col1}和{col2}之间没有显著的三次函数关系 (R²={r2:.3f})')
                    except Exception as fit_error:
                        ColorPrinter.print_error(f'{col1}和{col2}的三次函数拟合失败: {fit_error}')
                
                elif relation_func == 'func3':
                    # 指数函数拟合
                    try:
                        # 对数据进行归一化，防止数值溢出
                        x_norm = (x - np.min(x)) / (np.max(x) - np.min(x) + 1e-8)
                        y_norm = (y - np.min(y)) / (np.max(y) - np.min(y) + 1e-8)
                        
                        popt, _ = curve_fit(func3, x_norm, y_norm, maxfev=5000, 
                                           p0=[1.0, 0.1, 0.0], bounds=([-np.inf, -10, -np.inf], [np.inf, 10, np.inf]))
                        a, b, c = popt
                        y_fit = func3(x_norm, a, b, c)
                        r2 = r2_score(y_norm, y_fit)
                        
                        if r2 > threshold:
                            data[f'{col1}_exp'] = np.exp(b * x_norm)
                            data.drop(columns=[col1], inplace=True)
                            new_features.append(f'{col1}_exp')
                        else:
                            ColorPrinter.print_info(f'{col1}和{col2}之间没有显著的指数函数关系 (R²={r2:.3f})')
                    except Exception as fit_error:
                        ColorPrinter.print_error(f'{col1}和{col2}的指数函数拟合失败: {fit_error}')
                
                elif relation_func == 'func4':
                    # 对数函数拟合
                    try:
                        # 确保数据为正值
                        x_pos = np.maximum(x, 1e-8)
                        popt, _ = curve_fit(func4, x_pos, y, maxfev=5000)
                        a, b = popt
                        y_fit = func4(x_pos, a, b)
                        r2 = r2_score(y, y_fit)
                        
                        if r2 > threshold:
                            data[f'{col1}_log'] = np.log(x_pos)
                            new_features.append(f'{col1}_log')
                        else:
                            ColorPrinter.print_info(f'{col1}和{col2}之间没有显著的对数函数关系 (R²={r2:.3f})')
                    except Exception as fit_error:
                        ColorPrinter.print_error(f'{col1}和{col2}的对数函数拟合失败: {fit_error}')
                
                elif relation_func == 'func5':
                    # 平方根函数拟合
                    try:
                        # 确保数据为非负值
                        x_non_neg = np.maximum(x, 0)
                        popt, _ = curve_fit(func5, x_non_neg, y, maxfev=5000)
                        a, b = popt
                        y_fit = func5(x_non_neg, a, b)
                        r2 = r2_score(y, y_fit)
                        
                        if r2 > threshold:
                            data[f'{col1}_sqrt'] = np.sqrt(x_non_neg)
                            new_features.append(f'{col1}_sqrt')
                        else:
                            ColorPrinter.print_info(f'{col1}和{col2}之间没有显著的平方根函数关系 (R²={r2:.3f})')
                    except Exception as fit_error:
                        ColorPrinter.print_error(f'{col1}和{col2}的平方根函数拟合失败: {fit_error}')

            except Exception as e:
                ColorPrinter.print_error(f'特征构建失败: {col1}, {col2}: {e}')

        ColorPrinter.print_success(f'已构建 {len(new_features)} 个新特征')
        return data

    def feature_importance(self, data, cols, n_features=10):
        """
        特征重要性评估和特征选择
        
        使用随机森林评估特征重要性，并选择最重要的特征
        
        Args:
            data: 输入数据
            cols: 要分析的列名列表
            n_features: 要选择的特征数量
            
        Returns:
            处理后的数据
        """
        if not sklearn_available:
            ColorPrinter.print_error('scikit-learn 未安装，无法使用特征重要性评估')
            return data
        
        # 排除标签列
        feature_cols = [col for col in cols if col != self.data_label]
        if len(feature_cols) <= n_features:
            ColorPrinter.print_info(f"特征数量 ({len(feature_cols)}) 小于或等于要选择的特征数量 ({n_features})，跳过特征选择")
            return data

        # 只处理数值列
        numeric_cols = [col for col in feature_cols if data[col].dtype in ['int64', 'float64']]
        if len(numeric_cols) <= n_features:
            ColorPrinter.print_info(f"数值特征数量 ({len(numeric_cols)}) 小于或等于要选择的特征数量 ({n_features})，跳过特征选择")
            return data

        # 检查并处理NaN值
        if data[numeric_cols].isnull().any().any():
            ColorPrinter.print_warning("警告: 特征重要性评估前检测到NaN值，将自动填充")
            for col in numeric_cols:
                if data[col].isnull().any():
                    data[col] = data[col].fillna(data[col].mean())
                    ColorPrinter.print_progress(f"  已填充列 {col} 的NaN值")

        # 准备特征和标签数据
        X = data[numeric_cols].values
        y = data[self.data_label].values
        
        # 确保标签是数值类型
        if y.dtype == 'object':
            le = LabelEncoder()
            y = le.fit_transform(y)
            ColorPrinter.print_info(f"标签列已转换为数值类型: {le.classes_} -> {le.transform(le.classes_)}")
        
        # 确定任务类型（分类或回归）
        if len(np.unique(y)) <= 10:  # 假设类别数小于等于10为分类任务
            model = RandomForestClassifier(n_estimators=100, random_state=42)
        else:
            model = RandomForestRegressor(n_estimators=100, random_state=42)
        
        # 训练模型并获取特征重要性
        model.fit(X, y)
        importances = model.feature_importances_
        
        # 按重要性排序并选择前n_features个特征
        indices = np.argsort(importances)[::-1]
        selected_indices = indices[:n_features]
        selected_cols = [numeric_cols[i] for i in selected_indices]
        
        # 打印特征重要性
        ColorPrinter.print_info("特征重要性排序:")
        for i, idx in enumerate(indices[:10]):  # 只打印前10个
            ColorPrinter.print_info(f"{i+1}. {numeric_cols[idx]}: {importances[idx]:.4f}")
        
        # 保留选定的特征和标签列
        keep_cols = selected_cols + [self.data_label]
        data = data[keep_cols]
        
        ColorPrinter.print_success(f"特征选择完成，保留了 {len(selected_cols)} 个重要特征")
        ColorPrinter.print_info(f"保留的特征: {selected_cols}")
        
        return data
    
    def pca_lda_kernel(self, data, cols, n_components=10):
        if not sklearn_available:
            ColorPrinter.print_error('scikit-learn 未安装，无法使用降维处理')
            return data

        feature_cols = [col for col in cols if col != self.data_label]
        if len(feature_cols) < 2:
            ColorPrinter.print_error("需要至少2个特征列进行降维")
            return data

        numeric_cols = [col for col in feature_cols if data[col].dtype in ['int64', 'float64']]
        if len(numeric_cols) < 2:
            ColorPrinter.print_error("需要至少2个数值列进行降维")
            return data

        # 检查并处理NaN值
        if data[numeric_cols].isnull().any().any():
            ColorPrinter.print_warning("警告: 降维处理前检测到NaN值，将自动填充")
            for col in numeric_cols:
                if data[col].isnull().any():
                    data[col] = data[col].fillna(data[col].mean())
                    ColorPrinter.print_progress(f"  已填充列 {col} 的NaN值")

        kernel_selection = self.shortcut_relative.get('kernel_selection', 'pca')

        feature_data = data[numeric_cols]

        if kernel_selection == 'pca':
            pca = PCA(n_components=n_components)
            pca_data = pca.fit_transform(feature_data)
            for i in range(n_components):
                data[f'pca_component_{i}'] = pca_data[:, i]
            ColorPrinter.print_success(f'PCA降维完成，保留 {n_components} 个主成分')

        elif kernel_selection == 'lda':
            if self.data_label not in data.columns:
                ColorPrinter.print_error('LDA需要标签列')
                return data
            lda = LDA(n_components=n_components)
            lda_data = lda.fit_transform(feature_data, data[self.data_label])
            for i in range(min(n_components, lda_data.shape[1])):
                data[f'lda_component_{i}'] = lda_data[:, i]
            ColorPrinter.print_success(f'LDA降维完成，保留 {n_components} 个判别分量')

        elif kernel_selection == 'kernel':
            kernel = KernelPCA(n_components=n_components, kernel='rbf')
            kernel_data = kernel.fit_transform(feature_data)
            for i in range(n_components):
                data[f'kernel_component_{i}'] = kernel_data[:, i]
            ColorPrinter.print_success(f'KernelPCA降维完成，保留 {n_components} 个核分量')

        return data

    def relative_normal_switch(self, data):
        choice3_normal = self.shortcut_relative['choice3_normal']

        for choice in choice3_normal:
            try:
                if choice == 'linear_plus':
                    cols = self.shortcut_relative.get('linear_cols')
                    threshold = self.shortcut_relative.get('linear_threshold', 0.75)
                    if cols is None:
                        ColorPrinter.print_warning('linear_cols参数未指定，跳过线性特征组合')
                        continue
                    data = self.linear_plus(data, cols, threshold)

                elif choice == 'feature_plus':
                    cols = self.shortcut_relative.get('feature_cols')
                    threshold = self.shortcut_relative.get('feature_threshold', 0.75)
                    relation_func = self.shortcut_relative.get('relation_func', 'func1')
                    if cols is None:
                        ColorPrinter.print_warning('feature_cols参数未指定，跳过非线性特征构建')
                        continue
                    data = self.feature_plus(data, cols, threshold, relation_func)

                elif choice == 'feature_importance':
                    cols = self.shortcut_relative.get('feature_cols')
                    n_features = self.shortcut_relative.get('n_features', 10)
                    if cols is None:
                        ColorPrinter.print_warning('feature_cols参数未指定，跳过特征重要性评估')
                        continue
                    data = self.feature_importance(data, cols, n_features)

                elif choice == 'skip':
                    ColorPrinter.print_info('跳过特征工程（普通模式）')
            except Exception as e:
                ColorPrinter.print_error(f'特征工程处理出错: {choice}, {e}')

        return data

    def relative_advance_switch(self, data):
        choice3_advance = self.shortcut_relative['choice3_advance']

        for choice in choice3_advance:
            try:
                if choice == 'linear_plus':
                    cols = self.shortcut_relative.get('linear_cols')
                    threshold = self.shortcut_relative.get('linear_threshold', 0.75)
                    if cols is None:
                        ColorPrinter.print_warning('linear_cols参数未指定，跳过线性特征组合')
                        continue
                    data = self.linear_plus(data, cols, threshold)

                elif choice == 'feature_plus':
                    cols = self.shortcut_relative.get('feature_cols')
                    threshold = self.shortcut_relative.get('feature_threshold', 0.75)
                    relation_func = self.shortcut_relative.get('relation_func', 'func1')
                    if cols is None:
                        ColorPrinter.print_warning('feature_cols参数未指定，跳过非线性特征构建')
                        continue
                    data = self.feature_plus(data, cols, threshold, relation_func)

                elif choice == 'pca_lda_kernel':
                    cols = self.shortcut_relative.get('pca_cols')
                    n_components = self.shortcut_relative.get('n_components', 10)
                    if cols is None:
                        ColorPrinter.print_warning('pca_cols参数未指定，跳过降维处理')
                        continue
                    data = self.pca_lda_kernel(data, cols, n_components)

                elif choice == 'feature_importance':
                    cols = self.shortcut_relative.get('feature_cols')
                    n_features = self.shortcut_relative.get('n_features', 10)
                    if cols is None:
                        ColorPrinter.print_warning('feature_cols参数未指定，跳过特征重要性评估')
                        continue
                    data = self.feature_importance(data, cols, n_features)

                elif choice == 'skip':
                    ColorPrinter.print_info('跳过特征工程（高级模式）')
            except Exception as e:
                ColorPrinter.print_error(f'特征工程处理出错: {choice}, {e}')

        return data


"""
Parameter documentation:

shortcut_relative parameter dictionary:
    - choice3_normal: Normal mode feature engineering method selection
      Type: string or list of strings
      Optional values: 'linear_plus', 'feature_plus', 'feature_importance', 'skip'
      Default: None (must be specified)
      Description: Multiple selection supported, can choose the following methods:
        - 'linear_plus': Linear feature combination, remove highly correlated features
        - 'feature_plus': Non-linear feature construction, discover functional relationships between columns through function fitting
        - 'feature_importance': Feature importance evaluation and feature selection
        - 'skip': Skip feature engineering
    
    - choice3_advance: Advanced mode feature engineering method selection
      Type: string or list of strings
      Optional values: 'linear_plus', 'feature_plus', 'pca_lda_kernel', 'feature_importance', 'skip'
      Default: None (must be specified)
      Description: Multiple selection supported, can choose the following methods:
        - 'linear_plus': Linear feature combination
        - 'feature_plus': Non-linear feature construction
        - 'pca_lda_kernel': Dimensionality reduction (PCA/LDA/KernelPCA)
        - 'feature_importance': Feature importance evaluation and feature selection
        - 'skip': Skip feature engineering
    
    - linear_cols: Columns for linear combination
      Type: list of column names
      Default: None (must be specified in linear_plus mode)
      Description: Select columns from numeric columns for linear combination
    
    - linear_threshold: Correlation coefficient threshold for linear combination
      Type: float
      Optional values: 0.0 - 1.0
      Default: None (must be specified in linear_plus mode)
      Description: Columns with correlation coefficient greater than this value will be linearly combined
    
    - feature_cols: Columns for feature construction
      Type: list of column names
      Default: None (must be specified in feature_plus mode)
      Description: Select columns from numeric columns for feature construction
    
    - feature_threshold: R² threshold for feature construction
      Type: float
      Optional values: 0.0 - 1.0
      Default: None (must be specified in feature_plus mode)
      Description: New features will only be added if the fitted R² value is greater than this threshold
    
    - relation_func: Function type for feature construction
      Type: string
      Optional values: 'func1', 'func2', 'func3', 'func4', 'func5'
      Default: 'func1'
      Description: Select function type for fitting:
        - 'func1': Quadratic function a*x^2 + b*x + c
        - 'func2': Cubic function a*x^3 + b*x^2 + c*x + d
        - 'func3': Exponential function a*exp(b*x) + c
        - 'func4': Logarithmic function a*log(x) + b
        - 'func5': Square root function a*sqrt(x) + b
      Note: This parameter must be specified in feature_plus mode
    
    - pca_cols: Columns for dimensionality reduction
      Type: list of column names
      Default: None (must be specified in pca_lda_kernel mode)
      Description: Select columns from numeric columns for dimensionality reduction
    
    - n_components: Number of dimensions after dimensionality reduction
      Type: integer
      Optional values: >= 1
      Default: None (must be specified in pca_lda_kernel mode)
      Description: Number of features after dimensionality reduction
    
    - kernel_selection: Dimensionality reduction method selection
      Type: string
      Optional values: 'pca', 'lda', 'kernel'
      Default: None (must be specified in pca_lda_kernel mode)
      Description: 
        - 'pca': Principal Component Analysis
        - 'lda': Linear Discriminant Analysis (requires label column)
        - 'kernel': Kernel Principal Component Analysis
    
    - n_features: Number of features for importance evaluation
      Type: integer
      Optional values: >= 1
      Default: 10
      Description: Number of features to retain after feature importance evaluation (only used in feature_importance mode)

Usage example:
    # Example 1: Using quadratic function for feature construction
    relative_params = {
        'choice3_normal': ['feature_plus'],
        'feature_cols': ['col1', 'col2', 'col3'],
        'feature_threshold': 0.75,
        'relation_func': 'func1'
    }
    relative_processor = RelativePreprocessing(shortcut_relative=relative_params)
    processed_data = relative_processor(data, 'normal', 'label')
    
    # Example 2: Using cubic function for feature construction
    relative_params = {
        'choice3_advance': ['feature_plus'],
        'feature_cols': ['col1', 'col2', 'col3'],
        'feature_threshold': 0.8,
        'relation_func': 'func2'
    }
    
    # Example 3: Using exponential function for feature construction
    relative_params = {
        'choice3_advance': ['feature_plus'],
        'feature_cols': ['col1', 'col2'],
        'feature_threshold': 0.7,
        'relation_func': 'func3'
    }
    
    # Example 4: Using logarithmic function for feature construction
    relative_params = {
        'choice3_advance': ['feature_plus'],
        'feature_cols': ['col1', 'col2'],
        'feature_threshold': 0.7,
        'relation_func': 'func4'
    }
    
    # Example 5: Using square root function for feature construction
    relative_params = {
        'choice3_advance': ['feature_plus'],
        'feature_cols': ['col1', 'col2'],
        'feature_threshold': 0.7,
        'relation_func': 'func5'
    }
    
    # Example 6: Using feature importance evaluation
    relative_params = {
        'choice3_advance': ['feature_importance'],
        'feature_cols': ['col1', 'col2', 'col3', 'col4', 'col5'],
        'n_features': 3
    }
    relative_processor = RelativePreprocessing(shortcut_relative=relative_params)
    processed_data = relative_processor(data, 'advance', 'label')
"""


if __name__ == "__main__":
    import pandas as pd
    import numpy as np
    
    print("=" * 60)
    print("相关性分析和特征工程测试程序")
    print("=" * 60)
    
    # 创建测试数据
    np.random.seed(42)
    test_data = pd.DataFrame({
        'feature1': np.random.normal(50, 10, 50),
        'feature2': np.random.normal(100, 20, 50),
        'feature3': np.random.normal(200, 30, 50),
        'feature4': np.random.normal(300, 40, 50),
        'label': ['A'] * 25 + ['B'] * 25
    })
    
    # 添加一些相关性
    test_data['feature5'] = test_data['feature1'] * 2 + np.random.normal(0, 5, 50)
    test_data['feature6'] = test_data['feature2'] * 1.5 + np.random.normal(0, 5, 50)
    
    print("\n原始数据:")
    print(test_data.head(10))
    print(f"\n数据形状: {test_data.shape}")
    
    # 测试不同的特征工程方式
    test_cases = [
        {
            'clean_type': 'normal',
            'params': {
                'choice3_normal': ['linear_plus'],
                'linear_cols': ['feature1', 'feature2', 'feature3', 'feature4', 'feature5', 'feature6'],
                'linear_threshold': 0.8
            },
            'description': '线性特征组合（普通模式）'
        },
        {
            'clean_type': 'normal',
            'params': {
                'choice3_normal': ['feature_plus'],
                'feature_cols': ['feature1', 'feature2', 'feature3'],
                'feature_threshold': 0.8,
                'relation_func': 'func1'
            },
            'description': '非线性特征构建-二次函数（普通模式）'
        },
        {
            'clean_type': 'advance',
            'params': {
                'choice3_advance': ['feature_plus'],
                'feature_cols': ['feature1', 'feature2', 'feature3'],
                'feature_threshold': 0.8,
                'relation_func': 'func2'
            },
            'description': '非线性特征构建-三次函数（高级模式）'
        },
        {
            'clean_type': 'advance',
            'params': {
                'choice3_advance': ['feature_plus'],
                'feature_cols': ['feature1', 'feature2'],
                'feature_threshold': 0.7,
                'relation_func': 'func3'
            },
            'description': '非线性特征构建-指数函数（高级模式）'
        },
        {
            'clean_type': 'advance',
            'params': {
                'choice3_advance': ['pca_lda_kernel'],
                'pca_cols': ['feature1', 'feature2', 'feature3', 'feature4', 'feature5', 'feature6'],
                'n_components': 3,
                'kernel_selection': 'pca'
            },
            'description': 'PCA降维（高级模式）'
        },
        {
            'clean_type': 'normal',
            'params': {
                'choice3_normal': ['skip']
            },
            'description': '跳过特征工程'
        }
    ]
    
    for i, test_case in enumerate(test_cases, 1):
        print(f"\n{'=' * 60}")
        print(f"测试 {i}: {test_case['description']}")
        print('=' * 60)
        
        relative_processor = RelativePreprocessing(shortcut_relative=test_case['params'])
        try:
            processed_data = relative_processor(test_data.copy(), test_case['clean_type'], 'label')
            
            print("\n处理后的数据形状:")
            print(f"原始数据: {test_data.shape}")
            print(f"处理后数据: {processed_data.shape}")
            
            if processed_data.shape[1] != test_data.shape[1]:
                print("\n新增/删除的列:")
                original_cols = set(test_data.columns)
                processed_cols = set(processed_data.columns)
                added_cols = processed_cols - original_cols
                removed_cols = original_cols - processed_cols
                if added_cols:
                    print(f"新增列: {added_cols}")
                if removed_cols:
                    print(f"删除列: {removed_cols}")
        except Exception as e:
            print(f"\n处理出错: {e}")
    
    print("\n" + "=" * 60)
    print("测试完成！")
    print("=" * 60)
    
    # 深度渗透测试套件
    print(f"\n{'=' * 80}")
    print("深度渗透测试套件")
    print('=' * 80)
    
    # 创建更大的测试数据
    np.random.seed(42)
    large_test_data = pd.DataFrame({
        'feature1': np.random.normal(50, 10, 1000),
        'feature2': np.random.normal(100, 20, 1000),
        'feature3': np.random.normal(200, 30, 1000),
        'feature4': np.random.normal(300, 40, 1000),
        'feature5': np.random.normal(400, 50, 1000),
        'feature6': np.random.normal(500, 60, 1000),
        'feature7': np.random.normal(600, 70, 1000),
        'feature8': np.random.normal(700, 80, 1000),
        'feature9': np.random.normal(800, 90, 1000),
        'feature10': np.random.normal(900, 100, 1000),
        'label': np.random.choice(['A', 'B', 'C'], 1000)
    })
    
    # 添加一些强相关性
    large_test_data['feature11'] = large_test_data['feature1'] * 2 + np.random.normal(0, 2, 1000)
    large_test_data['feature12'] = large_test_data['feature2'] * 3 + np.random.normal(0, 3, 1000)
    large_test_data['feature13'] = large_test_data['feature3'] * 1.5 + np.random.normal(0, 1.5, 1000)
    
    # 测试1: 边界条件测试 - 空参数
    print(f"\n{'-' * 60}")
    print("测试1: 边界条件测试 - 空参数")
    print('-' * 60)
    
    relative_processor_1 = RelativePreprocessing(shortcut_relative={})
    result_1 = relative_processor_1(large_test_data.copy(), 'normal', 'label')
    
    print(f"\n数据形状变化: {large_test_data.shape} -> {result_1.shape}")
    print("期望：数据保持不变")
    
    # 测试2: 边界条件测试 - 不存在的列
    print(f"\n{'-' * 60}")
    print("测试2: 边界条件测试 - 不存在的列")
    print('-' * 60)
    
    params_nonexistent = {
        'choice3_normal': ['linear_plus'],
        'linear_cols': ['nonexistent_col', 'feature1', 'feature2'],
        'linear_threshold': 0.8
    }
    relative_processor_2 = RelativePreprocessing(shortcut_relative=params_nonexistent)
    result_2 = relative_processor_2(large_test_data.copy(), 'normal', 'label')
    
    print(f"\n数据形状变化: {large_test_data.shape} -> {result_2.shape}")
    print("期望：只处理存在的列")
    
    # 测试3: 边界条件测试 - 列数不足
    print(f"\n{'-' * 60}")
    print("测试3: 边界条件测试 - 列数不足")
    print('-' * 60)
    
    params_few_cols = {
        'choice3_normal': ['linear_plus'],
        'linear_cols': ['feature1'],
        'linear_threshold': 0.8
    }
    relative_processor_3 = RelativePreprocessing(shortcut_relative=params_few_cols)
    result_3 = relative_processor_3(large_test_data.copy(), 'normal', 'label')
    
    print(f"\n数据形状变化: {large_test_data.shape} -> {result_3.shape}")
    print("期望：数据保持不变，至少需要2列")
    
    # 测试4: 边界条件测试 - 阈值边界值
    print(f"\n{'-' * 60}")
    print("测试4: 边界条件测试 - 阈值边界值")
    print('-' * 60)
    
    test_cases_threshold = [
        {'threshold': 0.0, 'desc': '阈值为0'},
        {'threshold': 1.0, 'desc': '阈值为1'},
    ]
    
    for tc in test_cases_threshold:
        params_threshold = {
            'choice3_normal': ['linear_plus'],
            'linear_cols': ['feature1', 'feature2', 'feature3', 'feature11', 'feature12'],
            'linear_threshold': tc['threshold']
        }
        relative_processor = RelativePreprocessing(shortcut_relative=params_threshold)
        result = relative_processor(large_test_data.copy(), 'normal', 'label')
        print(f"\n{tc['desc']}:")
        print(f"  数据形状变化: {large_test_data.shape} -> {result.shape}")
    
    # 测试5: 边界条件测试 - 只有一个数值列
    print(f"\n{'-' * 60}")
    print("测试5: 边界条件测试 - 只有一个数值列")
    print('-' * 60)
    
    data_single_numeric = pd.DataFrame({
        'numeric_col': np.random.normal(50, 10, 100),
        'str_col': ['a'] * 100,
        'label': ['A'] * 50 + ['B'] * 50
    })
    
    params_single_numeric = {
        'choice3_normal': ['linear_plus'],
        'linear_cols': ['numeric_col', 'str_col'],
        'linear_threshold': 0.8
    }
    relative_processor_5 = RelativePreprocessing(shortcut_relative=params_single_numeric)
    result_5 = relative_processor_5(data_single_numeric.copy(), 'normal', 'label')
    
    print(f"\n数据形状变化: {data_single_numeric.shape} -> {result_5.shape}")
    print("期望：数据保持不变，需要至少2个数值列")
    
    # 测试6: 边界条件测试 - 没有数值列
    print(f"\n{'-' * 60}")
    print("测试6: 边界条件测试 - 没有数值列")
    print('-' * 60)
    
    data_no_numeric = pd.DataFrame({
        'str_col1': ['a', 'b', 'c', 'd', 'e'] * 20,
        'str_col2': ['x', 'y', 'z', 'w', 'v'] * 20,
        'label': ['A'] * 50 + ['B'] * 50
    })
    
    params_no_numeric = {
        'choice3_normal': ['linear_plus'],
        'linear_cols': ['str_col1', 'str_col2'],
        'linear_threshold': 0.8
    }
    relative_processor_6 = RelativePreprocessing(shortcut_relative=params_no_numeric)
    result_6 = relative_processor_6(data_no_numeric.copy(), 'normal', 'label')
    
    print(f"\n数据形状变化: {data_no_numeric.shape} -> {result_6.shape}")
    print("期望：数据保持不变")
    
    # 测试7: 边界条件测试 - 空数据
    print(f"\n{'-' * 60}")
    print("测试7: 边界条件测试 - 空数据")
    print('-' * 60)
    
    empty_data = pd.DataFrame({
        'feature1': [],
        'feature2': [],
        'label': []
    })
    
    params_empty = {
        'choice3_normal': ['linear_plus'],
        'linear_cols': ['feature1', 'feature2'],
        'linear_threshold': 0.8
    }
    relative_processor_7 = RelativePreprocessing(shortcut_relative=params_empty)
    result_7 = relative_processor_7(empty_data.copy(), 'normal', 'label')
    
    print(f"\n数据形状变化: {empty_data.shape} -> {result_7.shape}")
    print("期望：空数据保持不变")
    
    # 测试8: 组合测试 - 所有函数类型测试
    print(f"\n{'-' * 60}")
    print("测试8: 组合测试 - 所有函数类型测试")
    print('-' * 60)
    
    funcs = ['func1', 'func2', 'func3', 'func4', 'func5']
    
    for func in funcs:
        params_func = {
            'choice3_advance': ['feature_plus'],
            'feature_cols': ['feature1', 'feature2', 'feature3'],
            'feature_threshold': 0.7,
            'relation_func': func
        }
        relative_processor = RelativePreprocessing(shortcut_relative=params_func)
        result = relative_processor(large_test_data.copy(), 'advance', 'label')
        print(f"\n函数类型 {func}:")
        print(f"  数据形状变化: {large_test_data.shape} -> {result.shape}")
    
    # 测试9: 组合测试 - 降维参数边界值
    print(f"\n{'-' * 60}")
    print("测试9: 组合测试 - 降维参数边界值")
    print('-' * 60)
    
    test_cases_pca = [
        {'n_components': 1, 'desc': '降维到1维'},
        {'n_components': 5, 'desc': '降维到5维'},
        {'n_components': 10, 'desc': '降维到10维'},
    ]
    
    for tc in test_cases_pca:
        params_pca = {
            'choice3_advance': ['pca_lda_kernel'],
            'pca_cols': ['feature1', 'feature2', 'feature3', 'feature4', 'feature5', 
                        'feature6', 'feature7', 'feature8', 'feature9', 'feature10'],
            'n_components': tc['n_components'],
            'kernel_selection': 'pca'
        }
        relative_processor = RelativePreprocessing(shortcut_relative=params_pca)
        result = relative_processor(large_test_data.copy(), 'advance', 'label')
        print(f"\n{tc['desc']}:")
        print(f"  数据形状变化: {large_test_data.shape} -> {result.shape}")
    
    # 测试10: 验证结果
    print(f"\n{'-' * 60}")
    print("测试10: 验证结果")
    print('-' * 60)
    
    test_data_verify = pd.DataFrame({
        'x': np.array(range(100)),
        'y': np.array([2 * i + np.random.normal(0, 0.1) for i in range(100)]),
        'label': ['A'] * 50 + ['B'] * 50
    })
    
    params_verify = {
        'choice3_normal': ['linear_plus'],
        'linear_cols': ['x', 'y'],
        'linear_threshold': 0.9
    }
    
    relative_processor_10 = RelativePreprocessing(shortcut_relative=params_verify)
    result_10 = relative_processor_10(test_data_verify.copy(), 'normal', 'label')
    
    print(f"\n原始列: {list(test_data_verify.columns)}")
    print(f"处理后列: {list(result_10.columns)}")
    print("期望：由于x和y高度相关，应该删除其中一列")
    
    print(f"\n{'=' * 80}")
    print("深度渗透测试完成！")
    print('=' * 80)
