Iawen's Blog

我喜欢这样自由的随手涂鸦, 因为我喜欢风......

近几年, 随着硬件算力设备和算法模型逐渐在标准化、模块化发展的趋势下, 数据成为了最不可控的变量。从算力、算法、数据三大基本要素来看, 算力是最容易作为标准化来衡量的, 而且通用性最高, 可以在任何深度学习任务中都能够使用, 比如使用Tesla V100可以做一般的检测分类任务、分割任务、生成任务, 也可以做普通的语言模型任务、强化学习模型任务等。

数据作为三者之中不容易用标准化的元素来说, 其不可控的原因主要是由于不同的任务要使用不同的数据集, 所以很难对数据做到真正的标准化和模块化, 无法像算法模型一样直接对其调用。在学术界, 真正通用的数据就那么几个, 比如COCO数据集, VOC数据集, ImageNet数据集, 都是用来发表论文时使用的, 在工业界, 大多数任务都是指定的数据, 无法直接使用这类数据集的, 最多也就是使用其数据作为预训练的模型。比如很多知名的神经网络模型, 像早期的ResNet, 后来的Efficientnet, 以及YOLO系列近期发出的最强的版本YOLOX, 都是在COCO数据集上作比较。而工业界都是根据各自的任务来选取或者采集相关的数据的。

一般来说, 数据处理(data processing)是对数据的采集、存储、查找、加工、变换和传输。根据处理设备的结构方式、工作方式, 以及数据的时间空间分布方式的不同, 数据处理有不同的方式。不同的处理方式要求不同的处理工具。每种处理方式都有自己的特点, 应当根据应用问题的实际环境选择合适的处理方式。

数据、信息与知识的关系如下图所示。这个过程是先从实验中收集数据, 再从数据中提取信息, 最后对信息进行细致的分析, 从中获取知识。 0

1. 数值处理

在数据的标准化方法中, 常用的有Batch Norm、Layer Norm、Instance Norm、Group Norm, 除此以外还有不太常用的Switchable Normalization、Filter Response Normalization

  • 均值中心化(mean-centering)
  • Z-Score规范化
  • 区间缩放法(最大-最小标准化)
  • 二次型规范化

1.1 均值中心化(mean-centering)

就是通过与平均分的比较来决定一个评分为正或者为负。 中心化均值方法有个有趣的性质就是:用户对物品喜好倾向可以直接观察标准化后的评分值的正负情况。同时评分可以表示用户对物品喜好或厌恶的程度。

import pandas as pd
moive_matrix = {
    "John": {"The Matrix": 5, "Titanic":1, "Forrest Gump": 2, "Wall-E":2},
    "Lucy": {"The Matrix": 1, "Titanic":5, "Die Hard": 2, "Forrest Gump": 5, "Wall-E":5},
    "Eric": {"The Matrix": 2, "Die Hard": 3, "Forrest Gump": 5, "Wall-E": 4},
    "Diane": {"The Matrix": 4, "Titanic":3, "Die Hard": 5, "Forrest Gump": 3}
}
df = pd.DataFrame(moive_matrix).T

f = lambda x: x-x.mean()
print('________物品均值中心化________')
print(df.apply(f))
print('________用户均值中心化________')
print(df.apply(f, axis=1))

均值中心化方法移除来针对平均评分的不同感受而导致的偏差, 而Z-score标准化方法则考虑来个人评分范围不同带来的差异性。

1.1 无量纲处理

无量纲化使不同规格的数据转换到同一规格, 常见的方法有: 标准化(Z-Score规范化)和区间缩放法(最大-最小标准化)、二次型规范化。 标准化的前提是特征值服从正态分布, 标准化后, 其转换成标准正态分布。区间缩放法利用了边界值信息, 将特征的取值区间缩放到某个特定的范围, 例如[0,1]等。

import numpy as np
from sklearn import preprocessing

x = np.array([
  [1., -1., 2.],
  [2., 0., 0.],
  [0., 1., -1.]
])
# 标准化(Z-Score规范化) x¹ = (x-x⁻)/S
x_scaled = preprocessing.scale(x)
print(x_scaled)

# 区间缩放法 x¹ = (x -Min) / (Max -Min)
x_max_min_scaled = preprocessing.MinMaxScaler().fit_transform(x)
print(x_max_min_scaled)

# 二次型规范化
x_normalize = preprocessing.normalize(x, norm='l2')
print(x_normalize)

1.2 非线性变换

常用的变换有基于多项式、基于指数函数和基于对数函数的变换等。一般对数变换后特征分布更平稳。对数变换能很好地解决随着自变量的增加, 因变量的方差增大的问题。另外一方面, 将非线性的数据通过对数变换, 转换为线性数据, 便于使用线性模型进行学习。

1.3 离散化

离散化后的特征对异常数据有很强的鲁棒性

  • 无监督离散化 无监督的离散化方法通常为对特征进行装箱, 分为等宽度离散化方法和等频度离散化方法。等宽度离散方法, 就是根据箱的个数得出固定的宽度, 使得分到每个箱中的数据的宽度是相等的。 等频分箱法是使得分到每个箱中的数据的个数是相同的。 基于聚类分析的离散化方法也是一种无监督的离散化方法。

  • 有监督离散化 有监督的离散化方法相较无监督的离散化方法拥有更多的表现形式及处理方式, 但目前比较常用的方法为基于熵的离散化方法和基于卡方的离散化方法。

熵是最常用的离散化度量之一。基于熵的离散化方法使用类分布信息计算和确定分裂点, 是一种有监督的、自顶向下的分裂技术。 ID3 和 C4.5 是两种常用的使用熵的度量准则来建立决策树的算法, 基于这两种方法进行离散化特征儿乎与建立决策树的方法一致。在上述方法上又产生了 MDLP 方法(最小描述距离长度法则)

不同于基于熵的离散化方法, 基于卡方的离散化方法是采用自底向上的策略, 首先将数据取值范围内的所有数据值列为一个单独的区间, 再递归找出最佳邻近可合井的区间, 然后合并它们, 进而形成较大的区间。最常用的基于卡方的离散化方法是 ChiMerge 方法.

2. 离散处理

2.1 One-Hot 编码

如果一个特征有 m 个可能值, 那么通过 One-Hot 编码后就变成了 m 个二元特征, 并且这些特征互斥。One-Hot 编码可以将离散特征的取值扩展到欧式空间, 离散特征的某个取值就是对应欧式空间的某个点, 可以方便在学习算法中进行相似度等计算, 并且可以稀疏表示, 减少存储, 同时可以一定程度上起到扩充特征的作用。

import numpy as np
from sklearn import preprocessing

one_hot_enc = preprocessing.OneHotEncoder()
one_hot_enc.fit([[1, 1, 2], [0, 1, 0], [0, 2, 1], [3, 0, 3]])
after_one_hot = one_hot_enc.transform([[3, 2, 3]]).toarray()
print(after_one_hot)

2.2 特征哈希

特征哈希法的目标是把原始的高维特征向量压缩成较低维特征向量, 且尽量不损失原始特征的表达能力, 是一种快速且很节省空间的特征向量化方法。

def hashing_vectorizer(s, N):
  x = [0 for i in range(N)]
  for f in s.split():
    h = hash(f)
    x[h % N] += 1
  return x

print(hashing_vectorizer('make a hash feature', 3))

2.3 时间特征处理

通常方案是按照业务逻辑以及业务目的进行相关特征的处理, Christ, M 等提出了一种层次化处理时间特征的方案, 其中包含了时间窗口统计特征: 最大、最小、均值、分位数, 并利用标签相关性对特征进行选择。

3. 单变量

3.1 皮尔森相关系数

皮尔森相关系数是一种最简单的、能帮助理解特征和响应变量之间关系的方法, 该方法衡量的是变量之间的线性相关性, 结果的取值区间为[-1, 1], -1 表示完全的负相关(这个变量下降, 那个变量就会上升), +1 表示完全的正相关, 0 表示没有线性相关。 15

import numpy as np
from scipy.stats import pearsonr

np.random.seed(0)
size = 300
x = np.random.normal(0, 1, size)
print("Lower noise", pearsonr(x, x + np.random.normal(0, 1, size)))
print("Higher noise", pearsonr(x, x + np.random.normal(0, 10, size)))

3.2 距离相关系数

距离相关系数是为了克服皮尔森相关系数的弱点而产生的。它是基于距离协方差进行变量 间相关性度量, 它的一个优点为变量的大小不是必须一致的, 其计算方法如式 所示, 注意通常使用的值为其平方根: 16

def dist(x, y):
    return np.abs(x[:, None] - y)

def d_n(x):
    d = dist(x, x)
    dn = d - d.mean(0) - d.mean(1)[:, None] + d.mean()
    return dn

def dcov_all(x, y):
    dnx = d_n(x)
    dny = d_n(y)
    
    denom = np.product(dnx.shape)
    dc = (dnx * dny).sum() / denom
    dvx = (dnx ** 2).sum() / denom
    dvy = (dny ** 2).sum() / denom
    dr = dc /(np.sqrt(dvx) * np.sqrt(dvy))
    return np.sqrt(dr)

x = np.random.uniform(-1, 1, 10000)
dc = dcov_all(x, x ** 2)
print(dc)

3.3 卡方检验

卡方检验最基本的思想就是通过观察实际值与理论值的偏差来确定理论的正确与否。

4. 数据标注

数据标注的工作一般是借助标注工具来完成的, 其中图像视频数据的标注工具又占了大部分, 常用的图像视频标注工具有labelme、labelbox、labelimg、精灵标注助手等工具, 值得一提的是精灵标注助手是一款非常强大的免费标注工具, 标注类型涵盖了图像数据、视频数据、语音数据、文本数据、3D点云数据, 而且适应目前主流的操作系统。

数据标注的类型包括了图像数据标注、视频数据标注、语音数据标注、文本数据标注、3D点云数据标注。标注的方式有人工标注、半自动标注、自动标注、众包等。具体选用哪种方式标注数据, 要看数据量和数据的类型, 有些通用数据是开源采样自动标注方法的, 比如使用训练好的人脸检测模型来标注人脸框的位置, 而有些特殊数据只能使用人工标注的方法。

4. 数据增强

数据增强方法一般分为光照变换、几何变换、遮挡变换、混合变换等。

  • 其中光照变换包括了随机亮度变换、对比度变换、色彩度变换、饱和度变换、噪声变换。
  • 几何变换包括了随机缩放、裁剪、翻转、旋转、平移等变换。
  • 遮挡变换包括了图像马赛克、随机图块删除等。主要方法有以下几种:Random erase, Cutout, hide and seek, Grid Mask, Dropblock

5. 开源数据集

开放科学数据云( Open Science Data Cloud, OSDC), https://www.opensciencedatacloud.org/