import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LassoCV
from scipy.stats import mannwhitneyu
from imblearn.over_sampling import SMOTENC
from collections import defaultdict
from joblib import Parallel, delayed
import warnings
warnings.filterwarnings('ignore')


np.random.seed(42)
# ======================== 数据加载与划分 ========================
def load_and_split_data():
    rad_features = pd.read_csv('D:/taskPONV/stable/rad_features2009320_96.csv')
    labels = pd.read_csv('D:/taskPONV/stable/label320_96.csv')
    data = pd.merge(rad_features, labels, on='ID', how='inner')

    categorical_features = ['gender', 'hypertension', 'diabetes', 'coronaryheartdisease',
                           'PONVhistory', 'smoke', 'antiemetic', 'dezosine', 'ASA',
                           'volatileanesthetic', 'LBP', 'postopioiduse']
    

    mask = data['ID'].str.match(r'sub\d{3}\.nii\.gz')
    data_a = data[mask].reset_index(drop=True)
    data_b = data[~mask].reset_index(drop=True)
    

    X_train, X_test, y_train, y_test = train_test_split(
        data_a.drop(['ID', 'label'], axis=1),
        data_a['label'],
        test_size=0.3,
        stratify=data_a['label'],
        random_state=42
    )
    
    return X_train, X_test, y_train, y_test, data_b, categorical_features
# 
# ======================== 预处理管道 ========================
class PreprocessingPipeline:
    def __init__(self, categorical_features):
        self.categorical_features = categorical_features
        self.scaler = None
        self.smote = None
    
    def fit_resample(self, X, y):


        cat_indices = [X.columns.get_loc(c) for c in self.categorical_features]
        

        self.smote = SMOTENC(categorical_features=cat_indices, random_state=42)
        X_res, y_res = self.smote.fit_resample(X, y)
        

        continuous_features = [c for c in X.columns if c not in self.categorical_features]
        self.scaler = StandardScaler().fit(X_res[continuous_features])
        

        X_res_cont = self.scaler.transform(X_res[continuous_features])
        return pd.DataFrame(
            np.hstack([X_res[self.categorical_features].values, X_res_cont]),
            columns=self.categorical_features + continuous_features
        ), y_res
    
    def transform(self, X):

        continuous_features = [c for c in X.columns if c not in self.categorical_features]
        X_cont = self.scaler.transform(X[continuous_features])
        return pd.DataFrame(
            np.hstack([X[self.categorical_features].values, X_cont]),
            columns=self.categorical_features + continuous_features
        )

# ======================== 特征筛选流程 ========================
def bootstrap_feature_selection(X_train, y_train, preprocessor, n_iter=1000):

    feature_counts = defaultdict(int)

    results = Parallel(n_jobs=-1)(
        delayed(single_bootstrap_iteration)(X_train, y_train, preprocessor)
        for _ in range(n_iter)
    )
    for features in results:
        for feat in features:
            feature_counts[feat] += 1

    stability_df = pd.DataFrame.from_dict(feature_counts, orient='index', columns=['count'])
    stability_df['frequency'] = stability_df['count'] / n_iter
    return stability_df.sort_values('frequency', ascending=False)

def single_bootstrap_iteration(X_train, y_train, preprocessor):
    # 1. Bootstrap采样
    n_samples = len(X_train)
    bootstrap_indices = np.random.choice(n_samples, size=n_samples, replace=True)
    X_bs = X_train.iloc[bootstrap_indices]
    y_bs = y_train.iloc[bootstrap_indices]
    
    # 2. 预处理
    X_processed, y_resampled = preprocessor.fit_resample(X_bs, y_bs)
    
    # 3. 单变量筛选
    selected = univariate_selection(X_processed, y_resampled)
    
    # 4. 高相关过滤
    selected = filter_high_correlation(X_processed[selected])
    
    # 5. Lasso筛选
    final_features = lasso_selection(X_processed[selected], y_resampled)
    
    return final_features

def univariate_selection(X, y, alpha=0.05):
    """Mann-Whitney U检验筛选"""
    p_values = []
    for col in X.columns:
        _, p = mannwhitneyu(X[col][y == 0], X[col][y == 1])
        p_values.append(p)
    return X.columns[np.array(p_values) < alpha].tolist()

def filter_high_correlation(X, threshold=0.9):
    """高相关特征过滤"""
    corr_matrix = X.corr().abs()
    upper = corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k=1).astype(bool))
    to_drop = [col for col in upper.columns if any(upper[col] > threshold)]
    return [col for col in X.columns if col not in to_drop]

def lasso_selection(X, y):
    """Lasso特征筛选"""
    lasso = LassoCV(alphas=np.logspace(-3, 1, 50), cv=10, max_iter=5000)
    lasso.fit(X, y)
    return X.columns[np.abs(lasso.coef_) > 1e-6].tolist()  # 使用lambda.min对应的系数
# ======================== 新增代码：特征数据提取 ========================
def export_top_features():
    # 1. 读取特征稳定性结果
    stability_df = pd.read_csv('D:/taskPONV/stable/feature_stability.csv', index_col=0)
    
    # 2. 获取前30个特征并加入gender
    top_features = stability_df.head(30).index.tolist()
    required_features = list(set(top_features + ['gender','PONVhistory']))  # 自动去重
    
    # 3. 重新加载原始数据（确保获取所有样本）
    rad_features = pd.read_csv('D:/taskPONV/stable/rad_features2009320_96.csv')
    labels = pd.read_csv('D:/taskPONV/stable/label320_96.csv')
    full_data = pd.merge(rad_features, labels, on='ID', how='inner')  # 合并全部数据
    
    # 4. 验证特征存在性
    valid_features = [f for f in required_features if f in full_data.columns]
    
    # 5. 创建包含样本名的新表格
    result_df = full_data[['ID'] + valid_features]
    
    # 6. 保存结果
    result_df.to_csv('D:/taskPONV/stable/stable_features_data.csv', index=False)
    print(f"生成表格包含 {len(valid_features)} 个特征，样本数：{len(result_df)}")
# ======================== 主执行流程 ========================
if __name__ == "__main__":
    # 1. 数据加载与划分
    X_train, X_test, y_train, y_test, data_b, categorical_features = load_and_split_data()
    
    # 2. 初始化预处理管道
    preprocessor = PreprocessingPipeline(categorical_features)
    
    # 3. Bootstrap特征筛选
    stability_df = bootstrap_feature_selection(X_train, y_train, preprocessor, n_iter=5000)
    
    # 4. 筛选稳定特征
    stable_features = stability_df[stability_df['frequency'] > 0.5].index.tolist()
    print(f"最终稳定特征数: {len(stable_features)}")
    print("Top特征:", stable_features)
    # 5. 保存结果
    stability_df.to_csv('D:/taskPONV/stable/feature_stability.csv')
            # 新增数据导出
    export_top_features()
stability_df = pd.read_csv('D:/taskPONV/stable/feature_stability.csv', index_col=0)
    
# 2. 获取前20个特征并加入gender
top_features = stability_df.head(30).index.tolist()
print("top_features:",top_features)