最近由于使用 pandas 和 numpy做数据分析,以及需要把算法迁移到go上,发现了pandas 在处理一些统计项的时候,其中的参数的default 和numpy里面有问题,做个记录。
pandas.skew实现(rolling 同理)
import pandas as pd# 示例数据
data = pd.Series([1, 2, 3, 4, 5,6, 7, 8, 9, 10, 50])
skewness_pandas = data.skew()
print(f"Pandas Skewness: {skewness_pandas}")Pandas Skewness: 3.0536609583638397
拆公式直接实现(numpy)
import numpy as npdef calculate_skew_manual(series: pd.Series) -> float:"""手动计算时序数据的偏度(Skewness),完全匹配 pandas 的 skew 方法。"""data = series.dropna() # 去除缺失值n = len(data) # 样本量mean = np.mean(data) # 计算均值std = np.std(data,ddof= 0) # 使用样本标准差 (ddof=0)numerator = np.mean((data - mean) ** 3) # 分子denominator = std ** 3 # 分母# 偏度校正因子correction_factor = np.sqrt(n * (n - 1)) / (n - 2)skewness = correction_factor * (numerator / denominator)return skewness# 示例数据
data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 50])
skewness_manual = calculate_skew_manual(data)
print(f"Manual Skewness (matching pandas): {skewness_manual}")Manual Skewness (matching pandas): 3.05366095836384
该复现过程存在两个问题
(1)自由度
计算 标准差/方差 的时候需要设置 自由度 ddof 参数,如上 np.std(data,ddof=0)
这里我最开始 看了一下 dataframe 的 std 方法和 np.std方法。发现ddof 的default 如下:
data.std(axis=None,skipna=True,level=None,ddof=1,numeric_only=None,**kwargs,
)np.std(a,axis=None,dtype=None,out=None,ddof=0,keepdims=<no value>,*,where=<no value>,
)
然而 直接调用 dataframe 的 skew 方法 ,ddof default 为0
所以在使用numpy或者直接使用 data.std()的时候,把ddof 设置为0
(2)偏度校正因子
在样本量较小时,直接用样本数据计算的偏度可能会低估或高估总体的偏度。这是因为:
-
样本偏差:小样本可能无法完全反映总体的分布特性。
-
分母的调整:在计算偏度时,分母是标准差的立方(σ3σ3),而标准差本身在小样本时也可能存在偏差。
为了纠正这种偏差,统计学家引入了校正因子,使得在小样本情况下,偏度的估计更加准确。
在 pandas
的 skew
方法中,偏度的校正公式为:
4. 校正因子的作用
-
样本量较小时:
-
校正因子会显著影响偏度的计算结果。
-
例如,当 N=10N=10 时,校正因子约为 1.08,这意味着未校正的偏度会被放大。
-
-
样本量较大时:
-
校正因子趋近于 1,对偏度的影响可以忽略不计。
-
例如,当 N=100N=100 时,校正因子约为 1.005。
-