stats.zscore
来自scipy
stats.zscore
(在Manuel的回答中提到)适用于DataFrame / 2D数组,因此不需要通过apply()
调用它(因为apply
是Python for循环的语法糖,如果有很多列,它会明显变慢1)。从语法上说,只需要对DataFrame调用zscore
即可。
from scipy import stats
df = pd.DataFrame([[0,1,2],[3,3,5],[5,6,100]]).add_prefix('col')
zscore_df = stats.zscore(df)
![result](https://istack.dev59.com/GjNpx.webp)
如果需要对某些列进行标准化,只需选择这些列并计算Z分数。
stats.zscore(df[['col0', 'col2']])
您可以验证这确实返回与对每列应用zscore以及手动计算((df - df.mean())/df.std(ddof=0))相同的DataFrame。
x = stats.zscore(df)
y = df.apply(stats.zscore)
z = (df - df.mean()) / df.std(ddof=0)
np.allclose(x, y) and np.allclose(x, z)
scikit-learn
中的 StandardScaler
另一种方法是从 scikit-learn 中调用 StandardScaler()
。只需实例化 StandardScaler
,然后使用相关列作为输入调用 fit_transform
。结果是一个 numpy 数组,您可以将其赋值回数据框作为新列(或对数组本身进行操作等)。
from sklearn.preprocessing import StandardScaler
cols = ['col1', 'col2']
new_cols = [f"{c}_zscore" for c in cols]
sc = StandardScaler()
df[new_cols] = sc.fit_transform(df[cols])
1 一项 timeit 测试显示,对于一个包含100列的 DataFrame,直接在列上调用 zscore
比使用 apply()
在每列上调用它要快大约30倍。此外,正如 Joe Bathelt 的答案中提到的,直接计算实际上是最好的。
import pandas as pd
import numpy as np
from scipy import stats
from sklearn.preprocessing import StandardScaler
df = pd.DataFrame(np.random.default_rng(0).choice(100, size=(1000, 100))).add_prefix('col')
%timeit df.apply(stats.zscore)
%timeit stats.zscore(df)
%timeit df.sub(df.mean()).div(df.std(ddof=0))
%timeit StandardScaler().fit_transform(df)