如何对含有NaN的Pandas列进行Z-score归一化?

27 投票
4 回答
38253 浏览
提问于 2025-04-18 05:16

我有一个 pandas 数据框,其中有一列真实值,我想对这列数据进行 z-score 标准化:

>> a
array([    nan,  0.0767,  0.4383,  0.7866,  0.8091,  0.1954,  0.6307,
        0.6599,  0.1065,  0.0508])
>> df = pandas.DataFrame({"a": a})

问题是,如果这一列中有一个 nan 值,整个数组都会变成 nan

>> from scipy.stats import zscore
>> zscore(df["a"])
array([ nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan])

那么,怎样才能正确地对 pandas 数据框中的一列应用 zscore(或者其他不来自 scipy 的等效函数),并且让它忽略 nan 值呢?我希望处理后的结果和原来的列一样大,对于无法标准化的值用 np.nan 表示。

补充说明:也许最好的解决方案是使用 scipy.stats.nanmeanscipy.stats.nanstd?我不明白为什么在这个情况下需要改变 std 的自由度:

zscore = lambda x: (x - scipy.stats.nanmean(x)) / scipy.stats.nanstd(x)

4 个回答

0

解决这个问题的另一种方法是,在计算z-score时,用每列的平均值来填补DataFrame中的NaN值。这样一来,NaN值就会被计算成z-score为0,然后可以通过在原始数据框上使用notna来屏蔽掉这些值。

你可以用一行代码创建一个和原始数据框大小一样的新数据框,这个新数据框里包含了原始数据框中数值的z-score,同时NaN值也会在相同的位置出现:

zscore_df = pd.DataFrame(scipy.stats.zscore(df.fillna(df.mean())), index=df.index, columns=df.columns).where(df.notna())
6

你可以使用 isnan 来忽略那些“不是数字”(nan)的值。

z = a                    # initialise array for zscores
z[~np.isnan(a)] = zscore(a[~np.isnan(a)])
pandas.DataFrame({'a':a,'Zscore':z})

     Zscore       a
0       NaN     NaN
1 -1.148329  0.0767
2  0.071478  0.4383
3  1.246419  0.7866
4  1.322320  0.8091
5 -0.747912  0.1954
6  0.720512  0.6307
7  0.819014  0.6599
8 -1.047803  0.1065
9 -1.235699  0.0508
7

我不太确定这个参数是什么时候出现的,因为我学Python的时间不长。不过你可以简单地使用这个参数 nan_policy = 'omit',这样在计算的时候就会忽略掉那些“nan”(也就是缺失值)了。

a = np.array([np.nan,  0.0767,  0.4383,  0.7866,  0.8091,  0.1954,  0.6307, 0.6599, 0.1065,  0.0508])
ZScore_a = stats.zscore(a,nan_policy='omit')

print(ZScore_a)
[nan -1.14832945  0.07147776  1.24641928  1.3223199  -0.74791154
0.72051236  0.81901449 -1.0478033  -1.23569949]
28

好吧,pandas'里的meanstd函数会自动处理Nan值,所以你可以这样计算(要想得到和scipy的zscore一样的结果,我觉得在std里需要用到ddof=0):

df['zscore'] = (df.a - df.a.mean())/df.a.std(ddof=0)
print df

        a    zscore
0     NaN       NaN
1  0.0767 -1.148329
2  0.4383  0.071478
3  0.7866  1.246419
4  0.8091  1.322320
5  0.1954 -0.747912
6  0.6307  0.720512
7  0.6599  0.819014
8  0.1065 -1.047803
9  0.0508 -1.235699

撰写回答