许多机器学习算法期望数据被一致地缩放。
在为机器学习扩展数据时,你应该考虑两种常用的方法。
在这个教程中,您将了解如何为机器学习重新缩放您的数据。阅读完这个教程后,您将知道:
- 如何从头开始对您的数据进行标准化。
- 如何从头开始标准化您的数据。
- 何时归一化数据而不是标准化数据。
描述
许多机器学习算法期望输入和输出数据的规模是相当的。
它可以帮助在加权输入以进行预测的方法中,例如线性回归和逻辑回归。
在结合加权输入以复杂方式的方法中(如人工神经网络和深度学习)实际上需要这样做。
在这个教程中,我们将练习对一个标准的机器学习数据集进行重新缩放,该数据集以CSV格式提供。
具体来说,是皮马印第安人数据集。它包含768行和9列。文件中的所有值都是数值,特别是浮点数。我们将首先学习如何加载文件,然后稍后学习如何将加载的字符串转换为数值。
- 数据集文件.
- 数据集详情.
教程
本教程分为3个部分:
- 标准化数据。
- 标准化数据。
- 何时进行归一化和标准化。
这些步骤将为你处理扩展自己的数据提供必要的基础。
1. 数据归一化
正则化可以根据上下文指代不同的技术。
在这里,我们将归一化定义为将输入变量重新缩放至0到1的范围内。
归一化要求你知道每个属性的最小值和最大值。
这可以通过训练数据进行估算,或者如果你对问题领域有深入的了解,可以直接指定。
您可以通过枚举数据集中的值来轻松估计每个属性的最小和最大值。
下面的代码片段定义了dataset_minmax() 函数,该函数计算数据集中每个属性的最小值和最大值,然后返回这些最小值和最大值的数组。
# Find the min and max values for each column
def dataset_minmax(dataset):minmax = list()for i in range(len(dataset[0])):col_values = [row[i] for row in dataset]value_min = min(col_values)value_max = max(col_values)minmax.append([value_min, value_max])return minmax
我们可以构造一个用于测试的小数据集如下:
x1 x2
50 30
20 90
使用这个人为的数据集,我们可以测试我们的函数,以计算每列的最小值和最大值。
# Find the min and max values for each column
def dataset_minmax(dataset):minmax = list()for i in range(len(dataset[0])):col_values = [row[i] for row in dataset]value_min = min(col_values)value_max = max(col_values)minmax.append([value_min, value_max])return minmax# Contrive small dataset
dataset = [[50, 30], [20, 90]]
print(dataset)
# Calculate min and max for each column
minmax = dataset_minmax(dataset)
print(minmax)
运行示例将产生以下输出。
首先,数据集以列表的形式打印,然后以格式打印每列的最小值和最大值列1: 最小值,最大值 和 列2: 最小值,最大值。
例如:
[[50, 30], [20, 90]]
[[20, 50], [30, 90]]
一旦我们得到了每列允许的最大值和最小值的估计,我们现在就可以将原始数据归一化到0到1的范围内。
将单个值归一化的计算方法是:
scaled_value = (value - min) / (max - min)
下面是一个在名为normalize_dataset()的函数中的实现,该函数对提供的数据集中的每一列进行值的标准化。
# Rescale dataset columns to the range 0-1
def normalize_dataset(dataset, minmax):for row in dataset:for i in range(len(row)):row[i] = (row[i] - minmax[i][0]) / (minmax[i][1] - minmax[i][0])
我们可以将这个函数与dataset_minmax()函数结合,并对人为数据集进行归一化。
# Find the min and max values for each column
def dataset_minmax(dataset):minmax = list()for i in range(len(dataset[0])):col_values = [row[i] for row in dataset]value_min = min(col_values)value_max = max(col_values)minmax.append([value_min, value_max])return minmax# Rescale dataset columns to the range 0-1
def normalize_dataset(dataset, minmax):for row in dataset:for i in range(len(row)):row[i] = (row[i] - minmax[i][0]) / (minmax[i][1] - minmax[i][0])# Contrive small dataset
dataset = [[50, 30], [20, 90]]
print(dataset)
# Calculate min and max for each column
minmax = dataset_minmax(dataset)
print(minmax)
# Normalize columns
normalize_dataset(dataset, minmax)
print(dataset)
运行此示例将打印以下输出,包括标准化的数据集。
[[50, 30], [20, 90]]
[[20, 50], [30, 90]]
[[1, 0], [0, 1]]
我们可以将此代码与加载CSV数据集的代码结合起来,加载并标准化皮马印第安人糖尿病数据集。
下载皮马印第安人数据集,并将其放置在当前目录中,文件名pima-indians-diabetes.csv。
- 数据集文件.
打开文件并删除底部的任何空行。
该示例首先加载数据集,并将每列的值从字符串转换为浮点数。从数据集中估计每列的最小值和最大值,最后对数据集中的值进行归一化。
from csv import reader# Load a CSV file
def load_csv(filename):file = open(filename, "rb")lines = reader(file)dataset = list(lines)return dataset# Convert string column to float
def str_column_to_float(dataset, column):for row in dataset:row[column] = float(row[column].strip())# Find the min and max values for each column
def dataset_minmax(dataset):minmax = list()for i in range(len(dataset[0])):col_values = [row[i] for row in dataset]value_min = min(col_values)value_max = max(col_values)minmax.append([value_min, value_max])return minmax# Rescale dataset columns to the range 0-1
def normalize_dataset(dataset, minmax):for row in dataset:for i in range(len(row)):row[i] = (row[i] - minmax[i][0]) / (minmax[i][1] - minmax[i][0])# Load pima-indians-diabetes dataset
filename = 'pima-indians-diabetes.csv'
dataset = load_csv(filename)
print('Loaded data file {0} with {1} rows and {2} columns').format(filename, len(dataset), len(dataset[0]))
# convert string columns to float
for i in range(len(dataset[0])):str_column_to_float(dataset, i)
print(dataset[0])
# Calculate min and max for each column
minmax = dataset_minmax(dataset)
# Normalize columns
normalize_dataset(dataset, minmax)
print(dataset[0])
运行示例会生成以下输出。
从数据集中打印出第一条评论,在标准化之前和之后,显示了缩放的效果。
Loaded data file pima-indians-diabetes.csv with 768 rows and 9 columns
[6.0, 148.0, 72.0, 35.0, 0.0, 33.6, 0.627, 50.0, 1.0]
[0.35294117647058826, 0.7437185929648241, 0.5901639344262295, 0.35353535353535354, 0.0, 0.5007451564828614, 0.23441502988898377, 0.48333333333333334, 1.0]
2. 标准化数据
标准化是一种重新缩放技术,指的是将数据的分布以0为中心,并将标准差调整到1。
平均值和标准差可以一起用来总结正态分布,也称为高斯分布或钟形曲线。
它要求在缩放之前已知每列值的均值和标准差。与上面的归一化类似,我们可以从训练数据中估计这些值,或者使用领域知识来指定它们的值。
让我们从创建函数开始,以从数据集中估计每列的均值和标准差统计数据。
均值描述了一组数字的中间或集中趋势。列的均值是通过将列的所有值相加并除以总值数量来计算的。
mean = sum(values) / total_values
下面的函数 column_means() 用于计算数据集中每列的平均值。
# calculate column means
def column_means(dataset):means = [0 for i in range(len(dataset[0]))]for i in range(len(dataset[0])):col_values = [row[i] for row in dataset]means[i] = sum(col_values) / float(len(dataset))return means
标准差描述了值从平均值的平均偏差。它可以通过将每个值与平均值的差值平方后求和,然后除以值的数量减去1,再开方来计算。
standard deviation = sqrt( (value_i - mean)^2 / (total_values-1))
下面的函数 column_stdevs() 计算数据集中每列的值的标准差,并假定已经计算出均值。
# calculate column standard deviations
def column_stdevs(dataset, means):stdevs = [0 for i in range(len(dataset[0]))]for i in range(len(dataset[0])):variance = [pow(row[i]-means[i], 2) for row in dataset]stdevs[i] = sum(variance)stdevs = [sqrt(x/(float(len(dataset)-1))) for x in stdevs]return stdevs
再次,我们可以构造一个小型数据集来演示从数据集中估计均值和标准差。
x1 x2
50 30
20 90
30 50
使用Excel电子表格,我们可以估算出每列的均值和标准差如下:
x1 x2
mean 33.3 56.6
stdev 15.27 30.55
使用人为构造的数据集,我们可以估计总结统计量。
from math import sqrt# calculate column means
def column_means(dataset):means = [0 for i in range(len(dataset[0]))]for i in range(len(dataset[0])):col_values = [row[i] for row in dataset]means[i] = sum(col_values) / float(len(dataset))return means# calculate column standard deviations
def column_stdevs(dataset, means):stdevs = [0 for i in range(len(dataset[0]))]for i in range(len(dataset[0])):variance = [pow(row[i]-means[i], 2) for row in dataset]stdevs[i] = sum(variance)stdevs = [sqrt(x/(float(len(dataset)-1))) for x in stdevs]return stdevs# Standardize dataset
dataset = [[50, 30], [20, 90], [30, 50]]
print(dataset)
# Estimate mean and standard deviation
means = column_means(dataset)
stdevs = column_stdevs(dataset, means)
print(means)
print(stdevs)
执行此示例将产生以下输出,与电子表格中计算的数字匹配。
[[50, 30], [20, 90], [30, 50]]
[33.333333333333336, 56.666666666666664]
[15.275252316519467, 30.550504633038933]
一旦计算了汇总统计数据,我们就可以轻松地对每列中的值进行标准化。
将给定值标准化的计算方法如下:
standardized_value = (value - mean) / stdev
下面是一个名为standardize_dataset()的函数,实现了这个方程
# standardize dataset
def standardize_dataset(dataset, means, stdevs):for row in dataset:for i in range(len(row)):row[i] = (row[i] - means[i]) / stdevs[i]
将这些函数与用于估计均值和标准差的汇总统计数据结合起来,我们可以对我们的虚构数据集进行标准化。
from math import sqrt# calculate column means
def column_means(dataset):means = [0 for i in range(len(dataset[0]))]for i in range(len(dataset[0])):col_values = [row[i] for row in dataset]means[i] = sum(col_values) / float(len(dataset))return means# calculate column standard deviations
def column_stdevs(dataset, means):stdevs = [0 for i in range(len(dataset[0]))]for i in range(len(dataset[0])):variance = [pow(row[i]-means[i], 2) for row in dataset]stdevs[i] = sum(variance)stdevs = [sqrt(x/(float(len(dataset)-1))) for x in stdevs]return stdevs# standardize dataset
def standardize_dataset(dataset, means, stdevs):for row in dataset:for i in range(len(row)):row[i] = (row[i] - means[i]) / stdevs[i]# Standardize dataset
dataset = [[50, 30], [20, 90], [30, 50]]
print(dataset)
# Estimate mean and standard deviation
means = column_means(dataset)
stdevs = column_stdevs(dataset, means)
print(means)
print(stdevs)
# standardize dataset
standardize_dataset(dataset, means, stdevs)
print(dataset)
执行此示例将生成以下输出,显示人为数据集的标准化值。
[[50, 30], [20, 90], [30, 50]]
[33.333333333333336, 56.666666666666664]
[15.275252316519467, 30.550504633038933]
[[1.0910894511799618, -0.8728715609439694], [-0.8728715609439697, 1.091089451179962], [-0.21821789023599253, -0.2182178902359923]]
再次强调,我们可以展示机器学习数据集的标准化。
下面的示例展示了如何加载和标准化Pima Indians糖尿病数据集,假设该数据集位于当前工作目录,如之前的标准化示例所示。
from csv import reader
from math import sqrt# Load a CSV file
def load_csv(filename):file = open(filename, "rb")lines = reader(file)dataset = list(lines)return dataset# Convert string column to float
def str_column_to_float(dataset, column):for row in dataset:row[column] = float(row[column].strip())# calculate column means
def column_means(dataset):means = [0 for i in range(len(dataset[0]))]for i in range(len(dataset[0])):col_values = [row[i] for row in dataset]means[i] = sum(col_values) / float(len(dataset))return means# calculate column standard deviations
def column_stdevs(dataset, means):stdevs = [0 for i in range(len(dataset[0]))]for i in range(len(dataset[0])):variance = [pow(row[i]-means[i], 2) for row in dataset]stdevs[i] = sum(variance)stdevs = [sqrt(x/(float(len(dataset)-1))) for x in stdevs]return stdevs# standardize dataset
def standardize_dataset(dataset, means, stdevs):for row in dataset:for i in range(len(row)):row[i] = (row[i] - means[i]) / stdevs[i]# Load pima-indians-diabetes dataset
filename = 'pima-indians-diabetes.csv'
dataset = load_csv(filename)
print('Loaded data file {0} with {1} rows and {2} columns').format(filename, len(dataset), len(dataset[0]))
# convert string columns to float
for i in range(len(dataset[0])):str_column_to_float(dataset, i)
print(dataset[0])
# Estimate mean and standard deviation
means = column_means(dataset)
stdevs = column_stdevs(dataset, means)
# standardize dataset
standardize_dataset(dataset, means, stdevs)
print(dataset[0])
运行示例会打印数据集的第一行,首先以原始格式加载,然后进行标准化,这样我们可以进行比较以查看差异。
Loaded data file pima-indians-diabetes.csv with 768 rows and 9 columns
[6.0, 148.0, 72.0, 35.0, 0.0, 33.6, 0.627, 50.0, 1.0]
[0.6395304921176576, 0.8477713205896718, 0.14954329852954296, 0.9066790623472505, -0.692439324724129, 0.2038799072674717, 0.468186870229798, 1.4250667195933604, 1.3650063669598067]
3. 归一化和标准化的时机
标准化是一种假设您的数据符合正态分布的缩放技术。
如果给定的数据属性是正常或接近正常,这可能是应该使用的缩放方法。
记录标准化过程中使用的摘要统计数据是良好的实践,这样你可以在将来标准化你可能希望用于模型的数据时应用它们。
归一化是一种不需要假设任何特定分布的缩放技术。
如果您的数据不是正态分布的,请在应用机器学习算法之前考虑将其标准化。
在归一化过程中,记录每个列的最小值和最大值是良好的实践,以便将来在使用您的模型时,可以对新数据进行归一化。