使用python将Excel表格中的数据进行标准化
·
设计原因:作者使用传感器(多个传感器)采集到数据以后,想要通过这些数据进行回归模型预测,但是采集到的原始数据的单位与量级存在显著差异,会导致模型预测偏差过大的问题出现,故需要进行标准化,以此提高收敛速度,让模型更加准确。主要使用python进行标准化。
标准化之前的数据如下图所示:

标准化后结果如下如所示:

下面简单介绍一下常用的标准化方法,如下图所示:

因为所采集到的数据,并不符合高斯分布,并且想要保留原始的边界,故使用的为Min-Max缩放进行标准化。
python实现如下:
import os
import pandas as pd
import numpy as np
from openpyxl import load_workbook
from openpyxl.utils import get_column_letter
from openpyxl.styles import Font
from openpyxl.styles import numbers
def z_score_normalization(column):
"""Z-score标准化:将数据转换为均值为0,标准差为1的分布"""
mean = np.mean(column)
std = np.std(column)
if std == 0:
return column - mean
return (column - mean) / std
def min_max_normalization(column):
"""Min-Max标准化:将数据缩放到[0,1]区间"""
min_val = np.min(column)
max_val = np.max(column)
if max_val - min_val == 0:
return column - min_val
return (column - min_val) / (max_val - min_val)
def generate_target_column(df, method='linear', feature_weights=None, noise_level=0.1, scale_factor=1000):
"""
基于现有列生成目标列
参数:
df: 输入DataFrame
method: 生成方法,'linear'(线性组合)或'polynomial'(多项式组合)
feature_weights: 特征权重字典,例如 {'col1': 2.0, 'col2': 1.5}
noise_level: 添加的随机噪声强度
scale_factor: 缩放因子,用于缩小目标列
"""
# 选择前10个数值列作为特征
numeric_cols = df.select_dtypes(include=[np.number]).columns.tolist()
feature_cols = numeric_cols[:10] # 取前10列
if not feature_cols:
raise ValueError("数据中没有数值列可供生成目标列")
# 如果未指定权重,随机生成0-2之间的权重
if feature_weights is None:
np.random.seed(42) # 设置随机种子,确保结果可重现
weights = np.random.uniform(0, 2, len(feature_cols))
feature_weights = {col: weight for col, weight in zip(feature_cols, weights)}
print("\n随机生成的权重分配:")
for col, weight in feature_weights.items():
print(f" {col}: {weight:.4f}")
# 确保所有指定的列都存在
for col in feature_weights.keys():
if col not in df.columns:
raise ValueError(f"列 '{col}' 不存在于数据中")
# 生成目标列
if method == 'linear':
# 线性组合: y = w1*x1 + w2*x2 + ... + noise
target = np.zeros(len(df))
for col, weight in feature_weights.items():
target += df[col] * weight
# 添加随机噪声
noise = np.random.normal(0, noise_level * np.std(target), len(target))
target += noise
# 缩小目标列并保留两位小数
target = (target / scale_factor).round(2)
return pd.Series(target, name='generated_target')
elif method == 'polynomial':
# 多项式组合: y = w1*x1 + w2*x2^2 + w3*x1*x3 + noise
target = np.zeros(len(df))
# 线性项
for col, weight in feature_weights.items():
target += df[col] * weight
# 添加平方项(使用第一个特征的平方)
first_col = list(feature_weights.keys())[0]
target += 0.5 * (df[first_col] ** 2)
# 添加交叉项(如果有至少两列)
if len(feature_weights) >= 2:
col1, col2 = list(feature_weights.keys())[:2]
target += 0.3 * df[col1] * df[col2]
# 添加随机噪声
noise = np.random.normal(0, noise_level * np.std(target), len(target))
target += noise
# 缩小目标列并保留两位小数
target = (target / scale_factor).round(2)
return pd.Series(target, name='generated_target')
else:
raise ValueError(f"不支持的生成方法: {method}")
def normalize_excel(input_file, output_file, normalization_method='z_score', target_column=None,
generate_target=False, target_gen_method='linear', feature_weights=None, scale_factor=1000):
"""
对Excel文件中的数值列进行标准化处理,保留原始表头
参数:
input_file: 输入Excel文件路径
output_file: 输出Excel文件路径
normalization_method: 标准化方法,可选'z_score'、'min_max'或'regression'
target_column: 目标变量列名(如'y'),若指定则不对该列标准化
generate_target: 是否基于现有列生成目标列
target_gen_method: 目标列生成方法,'linear'或'polynomial'
feature_weights: 特征权重字典,用于生成目标列
scale_factor: 缩放因子,用于缩小目标列
"""
# 读取Excel文件
try:
df = pd.read_excel(input_file)
print(f"成功读取文件: {input_file}")
except Exception as e:
print(f"错误: 读取文件 {input_file} 时出错 - {str(e)}")
return
# 生成目标列(如果需要)
if generate_target:
print(f"正在基于现有列生成目标列(将缩小{scale_factor}倍并保留两位小数)...")
generated_target = generate_target_column(
df,
method=target_gen_method,
feature_weights=feature_weights,
scale_factor=scale_factor
)
df['generated_target'] = generated_target
target_column = 'generated_target' # 更新目标列名
print(f"已生成目标列 '{target_column}' 并置于最后一列")
# 创建新的工作簿
wb = load_workbook(input_file)
# 创建一个新的工作表来保存标准化结果
sheet_title = f"标准化结果({normalization_method})"
ws = wb.create_sheet(title=sheet_title[:31]) # 工作表名称不能超过31个字符
# 设置表头样式
header_font = Font(bold=True)
# 写入原始表头
for col_idx, header in enumerate(df.columns, start=1):
ws.cell(row=1, column=col_idx).value = header
ws.cell(row=1, column=col_idx).font = header_font
# 根据不同的标准化方法处理数据
if normalization_method == 'z_score':
norm_function = z_score_normalization
method_suffix = '(Z-score)'
elif normalization_method == 'min_max':
norm_function = min_max_normalization
method_suffix = '(Min-Max)'
elif normalization_method == 'regression':
norm_function = z_score_normalization
method_suffix = '(Regression)'
else:
print(f"错误: 不支持的标准化方法 - {normalization_method}")
return
# 对每列数据进行标准化处理
for col_idx in range(len(df.columns)):
column_name = df.columns[col_idx]
column = df.iloc[:, col_idx]
# 检查是否为数值列
if pd.api.types.is_numeric_dtype(column):
# 在线性回归模式下,如果是目标变量则跳过标准化
if normalization_method == 'regression' and column_name == target_column:
# 直接复制目标变量数据,并确保保留两位小数
for row_idx, value in enumerate(column, start=2):
cell = ws.cell(row=row_idx, column=col_idx + 1)
cell.value = value
cell.number_format = '0.00' # 设置Excel单元格格式为两位小数
continue
# 应用标准化
normalized_column = norm_function(column)
# 写入标准化后的数据(从第2行开始,保留表头)
for row_idx, value in enumerate(normalized_column, start=2):
ws.cell(row=row_idx, column=col_idx + 1).value = value
else:
# 非数值列直接复制原始数据
for row_idx, value in enumerate(column, start=2):
ws.cell(row=row_idx, column=col_idx + 1).value = value
# 调整列宽以适应内容
for col_idx in range(1, len(df.columns) + 1):
column_letter = get_column_letter(col_idx)
max_length = max(len(str(cell.value)) for cell in ws[column_letter])
ws.column_dimensions[column_letter].width = max(max_length + 2, 15)
# 保存工作簿
try:
wb.save(output_file)
print(f"\n标准化完成!结果已保存至: {output_file}")
except Exception as e:
print(f"错误: 保存文件时出错 - {str(e)}")
if __name__ == "__main__":
# 配置输入和输出文件路径
input_excel_file = "./处理后的数据/合并结果.xlsx" # 请修改为实际输入文件路径
output_excel_file = "./标准化的数据/normalized_data2.xlsx" # 请修改为实际输出文件路径
# 选择标准化方法:'z_score'、'min_max' 或 'regression'
# 'regression' 方法专为线性回归优化,使用Z-score并可排除目标变量
normalization_method = 'regression'
# 是否基于现有列生成目标列
generate_target = True
# 目标列生成方法:'linear'(线性组合)或'polynomial'(多项式组合)
target_gen_method = 'linear'
# 保持feature_weights为None,将自动从前10列随机分配0-2的权重
feature_weights = None
# 缩放因子,用于缩小目标列
scale_factor = 1000
# 如果不生成目标列,可手动指定现有目标列名
target_column = 'generated_target' if generate_target else None
# 确保输入文件存在
if not os.path.exists(input_excel_file):
print(f"错误: 指定的输入文件不存在 - {input_excel_file}")
else:
normalize_excel(
input_excel_file,
output_excel_file,
normalization_method,
target_column,
generate_target,
target_gen_method,
feature_weights,
scale_factor
)
该代码中提供了两中标准化方法,可按需进行选择。代码中已经使用AI进行详细注释,欢迎讨论交流!!!
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)