import numpy as np

def is_numeric_columns(col):
    """判断列是否为数值类型"""
    for s in col:
        try:
            float(s)
        except ValueError:
            return False
    return True

def select_best_normalizer(x):
    """选择最佳归一化方法"""
    n = len(x)
    
    # 计算各种归一化方法的评分
    score_l1 = 0.0
    score_l2 = 0.0
    score_max = 0.0
    score_robust = 0.0
    score_power = 0.0
    score_log = 0.0
    score_sqrt = 0.0
    
    # 计算基本统计量
    mean = np.mean(x)
    variance = np.var(x)
    std_dev = np.sqrt(variance)
    max_val = max(x)
    min_val = min(x)
    range_val = max_val - min_val
    q1 = np.percentile(x, 25)
    q3 = np.percentile(x, 75)
    iqr = q3 - q1
    
    # 计算L1评分 - 基于数据的分布特性，而不是仅仅稀疏性
    if range_val > 0:
        # 对于非稀疏数据，基于数据的均匀性评分
        # 计算数据的变异系数
        cv = std_dev / mean if mean > 0 else 0
        # 变异系数适中时L1评分较高
        score_l1 = np.exp(-0.5 * ((cv - 1.0) ** 2))
    else:
        score_l1 = 0.0
    
    # 计算L2评分 - 基于数据的分布均匀性
    if std_dev > 0:
        # 标准差适中时得分最高
        # 调整参数，使标准差在0.5-2之间时得分较高
        score_l2 = np.exp(-0.5 * ((np.log(std_dev) - 0) ** 2))
    else:
        score_l2 = 0.0
    
    # 计算Max评分 - 基于数据的范围
    if range_val > 0:
        # 对于不同范围的数据，都有合理的评分
        # 调整参数，使范围在1-1000之间时都能得到合理的评分
        score_max = 1.0 / (1.0 + np.exp(-0.01 * (np.log10(range_val + 1) - 1)))
    else:
        score_max = 0.0
    
    # 计算Robust评分 - 基于数据的异常值情况
    if iqr > 0 and range_val > 0:
        # IQR与范围的比例越大，说明异常值越多，越适合Robust归一化
        outlier_ratio = iqr / range_val
        score_robust = outlier_ratio
    else:
        score_robust = 0.0
    
    # 计算幂次归一化评分 - 基于数据的偏度
    if std_dev > 0:
        skewness = np.abs(np.mean(((x - mean) / std_dev) ** 3))
        # 偏度越大，越适合使用幂次归一化
        score_power = min(skewness / 2, 1.0)  # 偏度为2时得分约为1.0
    else:
        score_power = 0.0
    
    # 计算对数归一化评分 - 基于数据的取值范围和偏度
    if all(v > 0 for v in x):  # 对数归一化要求所有值为正
        # 数据范围较大且偏度较大时适合对数归一化
        if max_val > 1:
            log_range = np.log10(max_val) - np.log10(min_val)
            # 计算数据的偏度
            if std_dev > 0:
                skewness = np.mean(((x - mean) / std_dev) ** 3)
                # 正偏度较大时更适合对数归一化
                if skewness > 0:
                    score_log = min((log_range / 3 + skewness / 3), 1.0)
                else:
                    score_log = min(log_range / 5, 1.0)
            else:
                score_log = min(log_range / 5, 1.0)
        else:
            score_log = 0.0
    else:
        score_log = 0.0
    
    # 计算平方根归一化评分 - 基于数据的取值范围和分布
    if all(v >= 0 for v in x):  # 平方根归一化要求所有值非负
        # 数据为非负数且有一定范围时适合平方根归一化
        if max_val > 0:
            # 计算数据的偏度
            if std_dev > 0:
                skewness = np.mean(((x - mean) / std_dev) ** 3)
                # 正偏度适中时更适合平方根归一化
                if skewness > 0 and skewness < 2:
                    score_sqrt = min((np.sqrt(range_val) / 10 + skewness / 2), 1.0)
                else:
                    score_sqrt = min(np.sqrt(range_val) / 15, 1.0)
            else:
                score_sqrt = min(np.sqrt(range_val) / 15, 1.0)
        else:
            score_sqrt = 0.0
    else:
        score_sqrt = 0.0
    
    # 为不同类型的列添加特定的偏好
    # 检测列的类型（基于值的范围和分布）
    is_id_column = max_val > 100 and min_val == 1 and np.allclose(np.diff(sorted(x)), 1)  # 连续ID
    is_age_column = min_val >= 0 and max_val <= 120 and range_val > 5  # 年龄列
    is_score_column = min_val >= 0 and max_val <= 10 and range_val < 5  # 分数列（如GPA）
    
    # 根据列类型调整评分
    if is_id_column:
        # ID列通常不需要归一化，但如果必须选择，推荐Max或L2
        score_max *= 1.5
        score_l2 *= 1.2
    elif is_age_column:
        # 年龄列适合L2或Max归一化
        score_l2 *= 1.3
        score_max *= 1.2
    elif is_score_column:
        # 分数列适合L2或Robust归一化
        score_l2 *= 1.3
        score_robust *= 1.2
    
    # 最后进行比较，返回评分最高的那个归一化方法
    scores = [score_l1, score_l2, score_max, score_robust, score_power, score_log, score_sqrt]
    best_index = np.argmax(scores)
    
    # 返回对应的归一化方法
    normalizer_methods = ['L1 Normalization', 'L2 Normalization', 'Max Normalization', 'Robust Normalization', 'Power Normalization', 'Log Normalization', 'Square Root Normalization']
    return normalizer_methods[best_index]

def get_best_normalizer(col):
    """获取最佳归一化方法"""
    data = str_to_double(col)
    return select_best_normalizer(data)

def str_to_double(col):
    """将字符串列转换为double数组"""
    return [float(s) for s in col]
