基于残差的标准差优化数据

这段代码的目的是分析和优化Excel文件中的两列数据,以提高这两列数据之间的R²值(决定系数),这是一个衡量回归模型拟合优度的统计指标。具体来说,代码执行以下步骤:

  1. 读取数据:从指定的Excel文件路径读取数据,并提取出指定的两列(x_coly_col)。

  2. 计算初始R²值:使用calculate_r2函数计算这两列数据的初始R²值,并打印出来。

  3. 迭代优化:如果初始R²值没有达到目标值(target_r2),则开始迭代过程。在每次迭代中:

    • 使用线性回归模型(LinearRegression)来拟合数据。
    • 计算残差(实际值与预测值之间的差异)。
    • 根据残差的标准差和设定的阈值(threshold)来识别异常值。
    • 删除异常值,并重新计算R²值。
    • 重复上述步骤,直到R²值达到目标值或数据点数量不足以进行进一步的迭代。
  4. 绘制对比图:使用plot_comparison函数绘制优化前后的数据对比图,以直观展示优化效果。

  5. 保存结果:将优化后的数据保存到一个新的Excel文件中,并打印出优化后的数据点数量和最终的R²值。

  6. 异常处理:如果在迭代过程中未能达到目标R²值,代码会给出警告,并提供一些建议,如减小阈值、检查数据中的系统性误差或降低目标R²值。

异常值的识别是通过计算残差(即实际值与预测值之间的差异)并使用标准差来实现的。具体步骤如下:

  1. 线性回归拟合:首先,使用线性回归模型对数据进行拟合,得到预测值。

  2. 计算残差:残差是实际值与预测值之间的差异,计算公式为:

    残差=y−预测值残差

    其中 y是实际值。

  3. 计算残差的标准差:使用NumPy的np.std()函数计算残差的标准差,这个标准差用于衡量残差的分散程度。

  4. 识别异常值:根据设定的阈值(threshold),标识残差绝对值超过该阈值倍数的点为异常值。具体判断条件为:

    ∣残差∣>threshold×残差的标准差

    这意味着,如果某个数据点的残差超过了标准差的threshold倍数,则该点被视为异常值。

通过这种方法,代码能够动态识别并删除那些对模型拟合造成干扰的异常值,从而提高R²值,优化数据集的线性关系。

import pandas as pd
import numpy as np
from sklearn.metrics import r2_score
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt


def analyze_and_optimize_r2(file_path, x_col, y_col, threshold=2, target_r2=0.995):
    """
    分析两列数据的R²值,并通过删除异常值来优化R²

    参数:
    file_path: Excel文件路径
    x_col: x轴列名
    y_col: y轴列名(参考真值)
    threshold: 残差阈值(标准差的倍数)
    target_r2: 目标R²值,达到此值后停止迭代

    返回:
    优化后的数据框和最终的R²值
    """
    # 读取数据
    df = pd.read_excel(file_path)
    print(f"原始数据点数量: {len(df)}")

    # 提取需要的列
    data = df[[x_col, y_col]].copy()
    data = data.dropna()  # 删除空值

    # 计算初始R²
    initial_r2 = calculate_r2(data[x_col], data[y_col])
    print(f"初始R²值: {initial_r2:.6f}")

    if initial_r2 >= target_r2:
        print(f"R²值已经达到目标值 {target_r2},无需优化")
        return data, initial_r2

    # 开始迭代优化
    iteration = 1
    current_data = data.copy()
    current_r2 = initial_r2

    while current_r2 < target_r2 and len(current_data) > 2:
        # 计算残差
        model = LinearRegression()
        X = current_data[x_col].values.reshape(-1, 1)
        y = current_data[y_col].values
        model.fit(X, y)

        predictions = model.predict(X)
        residuals = y - predictions

        # 计算残差的标准差
        residual_std = np.std(residuals)

        # 标识异常值
        outlier_mask = abs(residuals) > threshold * residual_std

        if not any(outlier_mask):
            print(f"没有发现新的异常值,迭代停止")
            break

        # 移除异常值
        current_data = current_data[~outlier_mask]

        # 重新计算R²
        current_r2 = calculate_r2(current_data[x_col], current_data[y_col])

        print(f"迭代 {iteration}: 删除了 {sum(outlier_mask)} 个点, 新的R²值: {current_r2:.6f}")
        iteration += 1

    # 绘制优化前后的对比图
    plot_comparison(data, current_data, x_col, y_col)

    # 保存结果
    output_path = file_path.replace('.xlsx', '_optimized.xlsx')
    current_data.to_excel(output_path, index=False)
    print(f"\n优化后的数据已保存至: {output_path}")
    print(f"优化后的数据点数量: {len(current_data)}")
    print(f"最终R²值: {current_r2:.6f}")

    # 如果未达到目标R²值,给出提示
    if current_r2 < target_r2:
        print(f"\n警告:未能达到目标R²值 {target_r2}。")
        print("建议:")
        print("1. 尝试减小threshold值")
        print("2. 检查数据中是否存在系统性误差")
        print("3. 考虑降低目标R²值")

    return current_data, current_r2


def calculate_r2(x, y):
    """计算R²值"""
    return r2_score(y, x)


def plot_comparison(original_data, optimized_data, x_col, y_col):
    """绘制优化前后的对比散点图"""
    plt.figure(figsize=(12, 5))

    # 绘制优化前的数据
    plt.subplot(121)
    plt.scatter(original_data[x_col], original_data[y_col], alpha=0.5)
    plt.plot([original_data[y_col].min(), original_data[y_col].max()],
             [original_data[y_col].min(), original_data[y_col].max()],
             'r--')
    plt.title('优化前')
    plt.xlabel(x_col)
    plt.ylabel(y_col)

    # 绘制优化后的数据
    plt.subplot(122)
    plt.scatter(optimized_data[x_col], optimized_data[y_col], alpha=0.5)
    plt.plot([optimized_data[y_col].min(), optimized_data[y_col].max()],
             [optimized_data[y_col].min(), optimized_data[y_col].max()],
             'r--')
    plt.title('优化后')
    plt.xlabel(x_col)
    plt.ylabel(y_col)

    plt.tight_layout()
    plt.show()


# 运行代码
if __name__ == "__main__":
    file_path = r"你的数据路径(Excel表)"
    x_col = "Height" #预测数据
    y_col = "样地一_"  #实测数据

    try:
        optimized_data, final_r2 = analyze_and_optimize_r2(
            file_path,
            x_col,
            y_col,
            threshold=2,  # 可以调整此值来控制异常值判定的严格程度
            target_r2=0.995  # 设置目标R²值为0.995
        )
    except Exception as e:
        print(f"错误: {str(e)}")

数据优化前后散点图对比

-------------------------------------------------------2024年12月27日更-------------------------------------------------

使用Z得分的方法区清洗数据

Z分数(Z-score),也称为标准分数(standard score),是一个表示元素值与平均值之间差异的度量,通常以标准差为单位。它描述了一个数据点与平均值的距离,用标准差的倍数来表示。Z分数的计算公式如下:

其中:

  • XX 是数据点的值。
  • μμ 是数据集的平均值(mean)。
  • σσ 是数据集的标准差(standard deviation)。

Z分数的主要作用包括:

  1. 标准化数据:将数据转换为一个通用的尺度,使得不同数据集或不同量表的数据可以进行比较。

  2. 识别异常值:在统计学中,Z分数可以用来识别异常值。通常,如果一个数据点的Z分数大于+3或小于-3(这个阈值可以根据具体应用调整),则可能被认为是异常值。

  3. 理解数据分布:Z分数可以帮助我们理解数据的分布情况,比如数据点是集中在平均值附近,还是分散在平均值周围。

  4. 进行统计测试:在进行某些统计测试时,Z分数是一个重要的计算步骤,比如Z检验。

import pandas as pd
import numpy as np
from sklearn.metrics import r2_score
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt
from scipy import stats


def analyze_and_optimize_r2(file_path, x_col, y_col, threshold=3, target_r2=0.995):
    """
    使用改进的异常值检测方法分析数据的R²值

    参数:
    file_path: Excel文件路径
    x_col: x轴列名
    y_col: y轴列名(参考真值)
    threshold: z分数阈值
    target_r2: 目标R²值
    """
    df = pd.read_excel(file_path)
    print(f"原始数据点数量: {len(df)}")

    data = df[[x_col, y_col]].copy()
    data = data.dropna()

    initial_r2 = calculate_r2(data[x_col], data[y_col])
    print(f"初始R²值: {initial_r2:.6f}")

    # 计算相对误差
    relative_error = abs(data[x_col] - data[y_col]) / data[y_col] * 100

    # 使用Z分数检测异常值
    z_scores = np.abs(stats.zscore(relative_error))
    outlier_mask = z_scores < threshold

    # 移除异常值
    cleaned_data = data[outlier_mask].copy()

    # 计算最终R²值
    final_r2 = calculate_r2(cleaned_data[x_col], cleaned_data[y_col])

    # 输出结果
    print(f"移除的数据点数量: {len(data) - len(cleaned_data)}")
    print(f"保留的数据点数量: {len(cleaned_data)}")
    print(f"最终R²值: {final_r2:.6f}")

    # 保存结果
    output_path = file_path.replace('.xlsx', '_cleaned.xlsx')
    cleaned_data.to_excel(output_path, index=False)
    print(f"\n清理后的数据已保存至: {output_path}")

    # 绘图
    plot_comparison(data, cleaned_data, x_col, y_col)

    return cleaned_data, final_r2


def calculate_r2(x, y):
    """计算R²值"""
    return r2_score(y, x)


def plot_comparison(original_data, cleaned_data, x_col, y_col):
    """绘制清理前后的对比散点图"""
    plt.figure(figsize=(12, 5))

    plt.subplot(121)
    plt.scatter(original_data[x_col], original_data[y_col], alpha=0.5)
    plt.plot([original_data[y_col].min(), original_data[y_col].max()],
             [original_data[y_col].min(), original_data[y_col].max()],
             'r--')
    plt.title('清理前')
    plt.xlabel(x_col)
    plt.ylabel(y_col)

    plt.subplot(122)
    plt.scatter(cleaned_data[x_col], cleaned_data[y_col], alpha=0.5)
    plt.plot([cleaned_data[y_col].min(), cleaned_data[y_col].max()],
             [cleaned_data[y_col].min(), cleaned_data[y_col].max()],
             'r--')
    plt.title('清理后')
    plt.xlabel(x_col)
    plt.ylabel(y_col)

    plt.tight_layout()
    plt.show()


if __name__ == "__main__":
    file_path = r"文件路径"
    x_col = "Height"
    y_col = "ALS"

    try:
        cleaned_data, final_r2 = analyze_and_optimize_r2(
            file_path,
            x_col,
            y_col,
            threshold=3,
            target_r2=0.995
        )
    except Exception as e:
        print(f"错误: {str(e)}")

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值