为何用Z-score标准化Pandas DataFrame会生成NaN列?
解决Z-score标准化后部分列变为NaN的问题
嘿,我来帮你分析下为啥mta_tax和trip_type列在标准化后变成了NaN——核心原因其实很直白:这些列的标准差为0。
Z-score的计算公式是(x - 均值)/标准差,如果某列所有数值完全一致(比如mta_tax可能是固定金额的税费,所有行都是同一个数;trip_type可能只有单一类别选项),那它的标准差就是0,分母为0自然会得到NaN结果。
接下来给你几个可行的解决方案:
1. 先识别并处理标准差为0的列
首先你可以先确认哪些列存在这个问题:
# 计算每列的标准差 column_std = df.std() # 筛选出标准差为0的列 zero_std_columns = column_std[column_std == 0].index.tolist() print("标准差为0的列:", zero_std_columns)
方案A:删除无区分度的列
如果这些列的所有值都相同,它们对后续分析(比如建模)没有任何贡献,直接删除就好:
# 保留标准差不为0的列 df_filtered = df.drop(columns=zero_std_columns) # 对筛选后的列做Z-score标准化 df_normalized = df_filtered.apply(zscore) print(df_normalized.describe())
方案B:保留列但跳过标准化
如果你需要保留这些列,可以只对有波动的列做标准化,再把原列合并回去:
# 拆分标准差为0和不为0的列 non_zero_std_cols = column_std[column_std != 0].index.tolist() zero_std_cols = column_std[column_std == 0].index.tolist() # 对非零标准差列做标准化 df_normalized = df[non_zero_std_cols].apply(zscore) # 合并原零标准差列 df_normalized[zero_std_cols] = df[zero_std_cols] print(df_normalized.describe())
2. 优化异常值处理步骤
另外,你之前的异常值去除代码df = df[(np.abs(stats.zscore(df)) < 3).all(axis=1)],如果某列标准差为0,stats.zscore(df)会为该列生成全NaN的结果,这会导致all(axis=1)返回False,进而误删所有行?不过看你说的是标准化后列变NaN,这个步骤可能没触发大问题,但最好提前处理零标准差列,避免后续意外。
给你一个完整的修改后代码示例:
import numpy as np import pandas as pd from scipy import stats from scipy.stats import zscore # 读取数据并处理缺失值 df = pd.read_csv('dataset.csv', sep=',') df = df.dropna(how='any') # 识别标准差为0的列 column_std = df.std() zero_std_cols = column_std[column_std == 0].index.tolist() non_zero_std_cols = column_std[column_std != 0].index.tolist() # 仅对非零标准差列做异常值去除 if non_zero_std_cols: df = df[(np.abs(stats.zscore(df[non_zero_std_cols])) < 3).all(axis=1)] # 标准化非零标准差列,合并零标准差列 df_normalized = df[non_zero_std_cols].apply(zscore) df_normalized[zero_std_cols] = df[zero_std_cols] print("处理后的数据描述:") print(df_normalized.describe())
这样就能彻底避免NaN的问题了,核心就是避开那些没有数值波动的列做Z-score计算。
内容的提问来源于stack exchange,提问作者steve
相关产品推荐
相关产品推荐

