百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

用 BOX-COX 变换进行数据正态性处理

toyiye 2024-06-21 12:36 10 浏览 0 评论

之前写了题为《用Python讲解偏度和峰度》的文章,在那篇文章里,笔者介绍了偏度、峰度以及如何基于二者进行数据正态性的判断,而今天笔者将介绍一下如何将数据进行正态性转换。

在我们进行数据分析时,遇到的数据往往不是呈正态分布的,而如果数据不是正态性的,那么在部分情况下会带来一些问题。比如某些模型的前提就是要求数据具有正态性(KNN、贝叶斯等),此外数据具有正态性可以在一定程度上提高机器学习的训练效果。

那么将非正态分布的数据转为正态分布有哪些方法呢?笔者在这里简单介绍几种常见的方法。第一种是对数据取平方根,这种方法常用于泊松分布数据,第二种是取对数,在对数正态分布数据中常用,这两种方法都要求数据非负,当然可以给这些数据都加一个常数使其为正值。还有一种方法是对数据取到数,常用于有极值的情况。但笔者今天介绍的方法和上面三种都不同,这种方法名为BOX-COX变换法。之所以介绍这种方法,是因为很多读者对这种方法不是太熟悉,想让大家更好地了解一下,同时这种方法在金融领域应用较多,笔者之前做过一些金融方面的数据分析,所以把这种方法拿出来重点介绍一下。

下面首先还是对BOX-COX变换做一个简单的介绍。

图1. BOX-COX变换的公式

BOX-COX变换是由博克斯(Box)与考克斯(Cox)在1964年提出的一种非常广泛的变换方法,它是对因变量y作如图1中式(1)的变换,式中λ是待定参数。此变换要求y的各分量都大于0,否则就要用另一种方式作BOX-COX变换,如图1中式(2)所示。这种方法先对y做平移,使y+a的各个分量都大于0,然后再做BOX-COX变换。对于不同的λ,所作的变换也不同,所以这是一个变换族,它包含一些常用操作,如对数变换(λ=0),平方根变换(λ=0.5),以及倒数变换(λ=-1)。

图2. BOX-COX变换的部分推导公式

通过此变换,我们寻找合适的λ,使得变换后图2中式(3)符合线性回归模型的各项假设:误差各分量等方差、不相关等。事实上,BOX-COX变换不仅可以处理异方差问题,还能处理自相关、误差非正态、回归函数非线性等情况。

图3. BOX-COX变换的部分推导公式

经过计算可得λ的最大似然估计为图2中式(4),而式(5)和(6)也都与(4)相关联。而通过图3中式(7)的变换,我们可以得到式(8)。为找出λ,使得Lmax(λ)最大,只需使SSE最小即可,它的解析解比较难找,通常是给出一系列λ的值,计算相应的SSE,取最小SSE所对应的λ即可。

在了解了BOX-COX变换基本原理之后我们就直接用python代码来说明一下其具体应用。在scipy的stats模块当中直接集成了BOX-COX方法,所以我们就利用该方法。

首先还是导入各种库。

import numpy as np
import pandas as pd
import seaborn as sns
from scipy import stats
import matplotlib.pyplot as plt

笔者在这里将用两个例子来说明BOX-COX变换的应用。首先我们来看一个比较特殊的例子。这个例子来自帕累托分布,帕累托分布原理如图4所示,其在实际生活中非常常见,比如石油的储量、社会财富的分布、人类居住区的大小等都是近似帕累托分布。我们首先生成服从帕累托分布的数据,然后再作出分布直方图。这里stats.lomax(c=14).rvs(size=500)这行代码中,lomax方法就是scipy中生成帕累托数据的方法,c=14是生成某个状态(或者说是形状)的数据,这个值可以随意设置。rvs是生成数据的方法,这里生成500个数值。

图4. 帕累托分布介绍

fig, ax = plt.subplots(figsize=[12,8])
data1 = stats.lomax(c=14).rvs(size=500) #生成帕累托分布数据,数据每次生成时可能不同
sns.distplot(data1)
plt.show()

结果如图5所示。从图中我们可以明显看出,该数据的分布不服从正态分布,而是一个右偏分布,数据比较集中于0到2之间。接下来我们对其进行BOX-COX变换,代码如下。这里stats.boxcox就是对原数据进行转换,会返回两个值,第一个值就是转换后的数据,所以我们取第一个值。

图5. 帕累托数据直方图

fig, ax = plt.subplots(figsize=[12,8])
converted_data1 = stats.boxcox(data1)[0] #对数据进行BOX-COX变换
sns.distplot(converted_data1)
plt.show()

结果如图6所示。从图中可以看出,该分布已经有了很明显的正态分布的特征,接下来我们再进一步验证一下。

图6. 转换后的帕累托数据直方图

fig, ax = plt.subplots(figsize=[12,8])
prob = stats.probplot(converted_data1, dist=stats.norm, plot=ax) #生成Q-Q图
plt.show()

结果如图7所示。图7是一个Quantile-Quantile Plot,就是我们平常所说的Q-Q图。Q-Q图是将一组数据作为参考,另一组数据作为样本,样本数据每个值在样本数据集中的百分位数(percentile)作为其在Q-Q图上的横坐标值,而该值放到参考数据集中时的百分位数作为其在Q-Q图上的纵坐标。一般我们会在Q-Q图上做一条45度的参考线。如果两组数据来自同一分布,那么样本数据集的点应该都落在参考线附近;反之如果距离越远,这说明这两组数据很可能来自不同的分布。可以看到绝大部分数据就分布于这条红线附近,可以判断我们转换过后的数据已经是服从正态分布了。

图7. 转换后的帕累托数据的Q-Q图

接下来再来看一个指数分布的例子。我们随机生成一个指数分布的数据集,再将其通过BOX-COX变换,转换成正态分布的数据,代码如下。

state = np.random.RandomState(20) #设置随机状态
data2 = state.exponential(size = 500) #生成指数分布数据集
converted_data2 = stats.boxcox(data2)[0] #将数据进行BOX-COX变换

然后再分别绘制原数据和经过BOX-COX变换后的数据的直方图。

fig, ax = plt.subplots(figsize=[12,8])
sns.distplot(data2) #绘制原始指数分布数据的直方图
plt.show()

fig, ax = plt.subplots(figsize=[12,8])
sns.distplot(converted_data2) #绘制转换后数据的直方图
plt.show()

图8. 指数分布数据直方图

图9. 转换后的指数分布数据直方图

结果如图8和图9所示。通过对比图8和图9,我们可以看到数据经过转换之后,正态性明显有了改善,但我们还要验证一下。这里我们不再用前面例子中的验证方法,而是使用另外一种方法,代码如下。

k1, p1 = stats.normaltest(data2)
k2, p2 = stats.normaltest(converted_data2)

这里stats.normaltest就是检验数据正态性的方法,该方法也会返回两个值,其中第二个是假设检验中常用到的P值,我们用这个值来判断数据是否具有正态性。我们得到的p1值为5.580577119276143e-57,这个值几乎为0,说明该数据不服从正态分布,而p2值为0.5322400503708197,说明该数据大概率服从正态分布。这也说明BOX-COX变换对原数据的转换效果还是很好的。

本文通过两个例子来说明BOX-COX变换对非正态分布数据的转换,也介绍了一些scipy当中数据正态性验证的方法。对于BOX-COX变换更深入的使用,感兴趣的读者也可以自行查找相关资料。

作者简介:Mort,数据分析爱好者,擅长数据可视化,比较关注机器学习领域,希望能和业内朋友多学习交流。

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码