dxy logo
首页丁香园病例库全部版块
搜索
登录

干货 | 数据预处理之Normalization

已认证的机构号 · 最后编辑于 2022-10-09 · IP 湖北湖北
3019 浏览
这个帖子发布于 4 年零 297 天前,其中的信息可能已发生改变或有所发展。

在代谢组学研究中,我们通过一系列的提取和上机实验,可以获得各种代谢物在样本中的定量信息。

在广靶和非靶模式下,更是一次性收获大量代谢物数据,满足感爆棚有木有~o(* ̄︶ ̄*)o~

然而,我们拿到的原始数据(Raw data),必须经过一系列的处理,变成Clean Data,才能用于后续的数据挖掘。这里的处理过程,我们统称为数据预处理(Data Pretreatment)。

今天我们就来唠唠数据预处理中的Normalization

太长不看版本

1.数据Normalization非常重要,能有效降低数据集噪音,改善生物学解释性;

2.常见的数据Normalization包括有中心化(Centering),缩放(Scaling)和转换(Transformation),多种方法可以联合使用;

3.不同类型的统计方法,需要不同的Normalization操作;

4.Log转换,Power转换,Autoscaling方法对广靶/非靶定量结果和大部分基于线性模型/正态分布的方法都比较适用;


一、什么是数据库Normalization?

数据Normalization,在我们代谢组学中,指的是通过对多个样本,多个代谢物的定量数据进行一系列的中心化,缩放,以及转换操作,减少数据集的噪声干扰,强调其生物学信息,使其适用后续的统计分析方法,并改善其生物学解释性。

简单来说,就是对代谢数据集进行一些变化,把数据拉到一个特定范围里,变得更有统计意义。

二、为什么要进行Normalization?

来康康实际数据的一个缩影:

img


注:该数据来自迈维代谢实际项目数据的子集,数据已做了脱敏处理,代谢物ID,样本名均进行了替换。

很明显,代谢数据有着典型的高维度、高噪声等特性,并且不同代谢物或者样本间,存在数量级的差异

例如:表格中标记出来的代谢物 Met0009,在 6 个样本中,就存在 1000 多倍的差异,与 Met0009 的生物学相关性并不成比例。

另外,很多统计方法,对数据的分布非常敏感,统计的效力往往会集中在那些浓度高或者倍数变化差异大的代谢物之上,然而真正起到作用的可能是那些浓度低的代谢物的变化之上。

因此,针对不同的统计方法,进行合理的数据Normalization就有了必要性。

三、怎样进行Normalization?

常见的方法,可以大体上分为三个类别:

  • 中心化(Centering):将所有数据减去均值,让数据分布在 0 值左右而非均值左右,聚焦于数据的差异;
  • 缩放(Scaling):将数据统一乘或者除一个因子,消除量级差异,有多种缩放方法适应不同需求;
  • 转换(Transformation):进行 Log 或者 Power 变换,消除异质性;

在 2006 年的时候,有一篇文献[1]做了一个总结:

img


下面表格是对其的解释和补充:

img


四、Normalization方法大评比

前面我们提到过,有些统计方法对规范化方法非常敏感,其中 PCA 就是一个典型。

下面我们对 2 个实际数据集进行不同的规范化处理,然后进行 PCA 分析,来看看不同方法的效果。

数据来自迈维代谢实际项目数据,数据已做了脱敏处理,代谢物ID,样本名,分组名均进行了替换,并删除了部分数据。

篇幅所限,我们选择了平时最常见的 5 种方法的结果进行展示。

1.数据集 1:2个组别3个地域群体;共 221 个样本,加上 13 个 mix,检测出 600+个代谢物。

img
  • 上图中一共有四个样本分组和一个mix分组;
  • 样本分组中,AE(橙色)AS(橄榄色)AW (绿色)是同一组群体在不同地域的样本;BW (蓝色)是另一组群体,但是和AW在同一个地域;
  •  mix 分组(粉色)应该聚成一个点;
  • 上图中,Auto scaling(标准化)和两种转换方法明显效果较好;


2.数据集 2:多个个体以及个体不同组织;共31 个样本加上 3 个 mix,检测出 600+个代谢物。

img
  • 上图中一共有四个样本分组和一个mix分组;
  • 样本分组种,A(橙色)是一个组织,B1(橄榄色)B2 (绿色)是同一个组织不同部位;C (蓝色)是另一个组织;
  • mix 分组(粉色)应该聚成一个点;
  • 上图中,同样是Auto scaling(标准化)和两种转换方法明显效果较好,并且 Log 转换方法效果最好;

2018 年,有一篇文章[2]统计了在代谢组相关文献中,使用率最高的规范化方法,正好就是 Log 转换,可见Log 转换方法的适应性最广。

img

五、结论

两组不同的数据,两种 Transformation 方法和 Auto Scaling 方法都有不错的效果。虽然不能代表代谢组数据的所有情况,但是也能管中窥豹,略见一斑。

在我们没有放出的图片中,Pareto Scaling也有和Auto Scaling 方法相差无几的效果,其次是 Range Scaling 方法。

事实上,从结果来选择使用方法是不可取的,不管是哪种方法,之所以能够获得较好的结果,都是因为基于代谢组数据的本质特点。

常见的广靶非靶数据具有高维,高噪,稀疏,右偏的特点;而 PCA要求数据是同方差数据,对异方差敏感,对线性性敏感;上述几种效果较好的规范化方法刚好适合 PCA分析。

如果换一种统计方法,那么Normalization方法也需要根据实际情况调整。

其理论基础不是本文的重点,大家可以参看一下两篇引文。


参考文献:

[1]van den Berg, R.A., Hoefsloot, H.C., Westerhuis, J.A. et al. Centering, scaling, and transformations: improving the biological information content of metabolomics data. BMC Genomics 7, 142 (2006).

[2]李霜. 基于代谢组学的数据标准化方法的综合评价[D].重庆大学,2018.


附录:工具说明

上述分析使用的工具是 R 语言。Normalization使用的是自编函数,可结合表格中的公式进行理解。

有 R 语言基础的人也可以自己拿数据测试一下哦~ 欢迎大家在留言区告诉我们,哪种方法对你们的数据最友好。

centering <- function(data) {

    col_names <- colnames(data)

    row_names <- rownames(data)

    data <- as.matrix(data)

    df <- apply(data, 2, function(x) x - mean(x, na.rm=TRUE))

    colnames(df) <- col_names

    rownames(df) <- row_names

    df

}


auto_scale <- function(data) {

    col_names <- colnames(data)

    row_names <- rownames(data)

    data <- as.matrix(data)

    df <- apply(data, 2, function(x) (x - mean(x, na.rm=TRUE))/sd(x, na.rm=TRUE))

    colnames(df) <- col_names

    rownames(df) <- row_names

    df

}


range_scale <- function(data) {

    col_names <- colnames(data)

    row_names <- rownames(data)

    data <- as.matrix(data)

    df <- apply(data, 2, function(x) (x - mean(x, na.rm=TRUE))/(max(x) - min(x)))

    colnames(df) <- col_names

    rownames(df) <- row_names

    df

}


minmax_scale <- function(data) {

    col_names <- colnames(data)

    row_names <- rownames(data)

    data <- as.matrix(data)

    df <- apply(data, 2, function(x) (x - min(x))/(max(x) - min(x)))

    colnames(df) <- col_names

    rownames(df) <- row_names

    df

}


pareto_scale <- function(data) {

    col_names <- colnames(data)

    row_names <- rownames(data)

    data <- as.matrix(data)

    df <- apply(data, 2, function(x) (x - mean(x, na.rm=TRUE))/sqrt(sd(x, na.rm=TRUE)))

    colnames(df) <- col_names

    rownames(df) <- row_names

    df

}


vast_scale <- function(data) {

    col_names <- colnames(data)

    row_names <- rownames(data)

    data <- as.matrix(data)

    df <- apply(data, 2, function(x) (x - mean(x, na.rm=TRUE))*mean(x, na.rm=TRUE)/var(x, na.rm=TRUE))

    colnames(df) <- col_names

    rownames(df) <- row_names

    df

}


level_scale <- function(data) {

    col_names <- colnames(data)

    row_names <- rownames(data)

    data <- as.matrix(data)

    df <- apply(data, 2, function(x) (x - mean(x, na.rm=TRUE))/mean(x, na.rm=TRUE))

    colnames(df) <- col_names

    rownames(df) <- row_names

    df

}


log_transform <- function(data, base=2) {

    col_names <- colnames(data)

    row_names <- rownames(data)

    data <- as.matrix(data)

    if (min(data) < 0) {

        stop("Log transformation could not process negative data")

    }

    if (base == "e") {

        base = exp(1)

    } else {

        base = as.numeric(base)

    }

    df <- log(1+data, base = base)

    colnames(df) <- col_names

    rownames(df) <- row_names

    df

}


power_transform <- function(data) {

    col_names <- colnames(data)

    row_names <- rownames(data)

    data <- as.matrix(data)

    if (min(data) < 0) {

        stop("Power transformation could not process negative data")

    }

    df <- sqrt(data)

    colnames(df) <- col_names

    rownames(df) <- row_names

    df

}

回复收藏点赞

全部讨论(0)

默认最新
avatar
分享帖子
share-weibo分享到微博
share-weibo分享到微信
认证
返回顶部