📜  Python| Box-Cox 变换

📅  最后修改于: 2022-05-13 01:54:56.022000             🧑  作者: Mango

Python| Box-Cox 变换

想象一下,您正在观看一场赛马,并且像任何其他比赛一样,有快跑者和慢跑者。所以,从逻辑上讲,先来的马和随之而来的快马的完成时间差异相同,而最慢的马完成时间差异更大。

我们可以将其与统计学中一个非常著名的术语联系起来,称为方差,它指的是数据相对于均值的变化程度。在我们的示例中,快马和慢马之间存在不一致的方差(异方差),因为较短的完成时间会有小的变化,反之亦然。

因此,我们的数据分布不会是钟形曲线或正态分布,因为右侧会有更长的尾巴。这些类型的分布遵循幂律80-20 规则,其中一个量的相对变化随另一个量的幂而变化。


幂律

在上图中,我们可以看到幂律分布在较短的运行时间内达到峰值,因为运行时间较长,方差较小,尾部较重。这些幂律分布存在于物理学、生物学、经济学等领域。

所以,想一想,如果这些分布存在于这么多领域,如果我们可以将其转换为像正态分布这样更舒适的分布呢?那会让我们的生活轻松很多。幸运的是,我们有一种方法可以使用Box-Cox 变换将幂律或任何非线性分布转换为正态分布

让我们直观地思考一下,如果我们自己进行这种转变,我们将如何进行?

从上图可以清楚地看出,如果我们能以某种方式夸大非正态分布左侧(即峰值)的变异性,并减少尾部的变异性。简而言之,尝试将峰值移向中心,然后我们可以获得接近钟形曲线的曲线。

形式上,Box cox 变换被定义为一种将数据中的非正态因变量转换为正常形状的方法,通过这种方法我们可以运行比我们所能拥有的更多的测试。

Box-Cox 变换背后的数学:

我们如何才能将我们的直觉思维转化为数学变换函数?对数变换就是我们所需要的。当对数变换应用于非正态分布时,它会尝试扩大较小值之间的差异,因为对数函数的斜率对于较小的值更陡峭,而较大值之间的差异可以减小,因为对于较大的值,对数分布具有中等斜率。这就是我们想要做的,对吧?

Box-cox 变换只关心计算\lambda 从 - 5 到 5 不等。 \lambda 如果能够将非正态曲线近似为正态曲线,则称其为最佳。变换方程如下:

y(\lambda)=\left\{\begin{array}{l} \left(y^{\lambda}-1\right) / \lambda \text { if } \lambda \neq 0 \\ \log y \quad \text { if } \lambda=0 \end{array}\right.

此函数要求输入为正。手动使用这个公式是一项非常费力的任务,因此许多流行的库都提供了这个函数。

执行:

SciPy 的 stats 包提供了一个名为boxcox的函数,用于执行 box-cox 幂变换,该函数将原始非正态数据作为输入并返回拟合数据以及用于将非正态分布拟合到正态分布的 lambda 值。

以下是相同的代码。

例子:

# Python3 code to show Box-cox Transformation 
# of non-normal data
  
# import modules
import numpy as np
from scipy import stats
  
# plotting modules
import seaborn as sns
import matplotlib.pyplot as plt
  
# generate non-normal data (exponential)
original_data = np.random.exponential(size = 1000)
  
# transform training data & save lambda value
fitted_data, fitted_lambda = stats.boxcox(original_data)
  
# creating axes to draw plots
fig, ax = plt.subplots(1, 2)
  
# plotting the original data(non-normal) and 
# fitted data (normal)
sns.distplot(original_data, hist = False, kde = True,
            kde_kws = {'shade': True, 'linewidth': 2}, 
            label = "Non-Normal", color ="green", ax = ax[0])
  
sns.distplot(fitted_data, hist = False, kde = True,
            kde_kws = {'shade': True, 'linewidth': 2}, 
            label = "Normal", color ="green", ax = ax[1])
  
# adding legends to the subplots
plt.legend(loc = "upper right")
  
# rescaling the subplots
fig.set_figheight(5)
fig.set_figwidth(10)
  
print(f"Lambda value used for Transformation: {fitted_lambda}")

输出:


输出

我们可以看到,使用SciPy.stats.boxcox()将非正态分布转换为正态分布或更接近正态分布。

Box-cox 总是有效吗?

答案是否定的。 Box-cox 不保证正态性,因为它从不检查正态性,这是万无一失的,它是否正确地转换了非正态分布。它只检查最小的标准偏差。

因此,绝对有必要始终使用概率图检查转换数据的正态性。