实现上述过程涉及很多步骤和细节。为了简化讲解,让我们通过一个简化的示例来展示这个过程如何工作。在这个示例中,我们将使用一个简单的数据集和简化的方法来模拟上述过程的一些关键部分。
1.创建数据集
import numpy as np
import pandas as pd
# 创建一个简单的训练数据集和生成数据集
np.random.seed(0)
training_data = pd.DataFrame({'Feature1': np.random.normal(0, 1, 100),
'Feature2': np.random.normal(0, 1, 100)})
generated_data = pd.DataFrame({'Feature1': np.random.normal(0.1, 1.1, 100),
'Feature2': np.random.normal(0.1, 1.1, 100)})
2.计算距离
from scipy.spatial.distance import cdist
# 计算训练数据和生成数据之间的欧式距离
distance_matrix = cdist(training_data, generated_data, metric='euclidean')
3.计算每个记录的最小距离
min_distance_train = np.min(distance_matrix, axis=1)
min_distance_gen = np.min(distance_matrix, axis=0)
np.min
函数是在distance_matrix
的每一行(由axis=1
指定)中找到最小值。每一行的最小值表示训练数据中的对应记录与生成数据中所有记录的最小距离。结果是一个数组,其中每个元素是训练数据中相应记录的最小距离。
np.min
函数是在distance_matrix
的每一列(由axis=0
指定)中找到最小值。每一列的最小值表示生成数据中的对应记录与训练数据中所有记录的最小距离。结果是一个数组,其中每个元素是生成数据中相应记录的最小距离。
4.计算Qδ统计量
def compute_q_delta(sample1, sample2, quantiles):
q_delta_values = []
for q in quantiles:
v_q = np.percentile(sample1, q * 100)
p_q = np.mean(sample2 <= v_q)
q_delta_values.append(p_q - q)
return np.mean(q_delta_values)
# 定义要测试的分位数,从0到1的10个等间隔的分位数
quantiles = np.linspace(0, 1, 10)
# 计算Qδ统计量
q_delta = compute_q_delta(min_distance_train, min_distance_gen, quantiles)
5.自举计算阈值
def bootstrap_threshold(data, alpha=0.95, n_rounds=500):
bootstrap_values = []
for _ in range(n_rounds):
# 从原始数据data中进行有放回抽样,抽样的大小与原始数据相同。
bootstrap_sample = np.random.choice(data, size=len(data), replace=True)
# 计算当前自助样本bootstrap_sample和原始数据data之间的Qδ统计量。
bootstrap_q_delta = compute_q_delta(bootstrap_sample, data, quantiles)
bootstrap_values.append(bootstrap_q_delta)
# 计算bootstrap_values列表的第alpha * 100百分位值,并将其返回作为阈值。
return np.percentile(bootstrap_values, alpha * 100)
# 计算阈值
threshold = bootstrap_threshold(min_distance_train)
现在,让我们通过一个简单的类比来理解它。假设你是一个老师,你想知道你的班级的学生在期末考试中的表现如何。但是,你不想仅仅依赖一个测试的结果,所以你决定多次随机抽取一些学生,让他们参加模拟考试,并记录每次模拟考试的平均分数。
- 自助法抽样 就像是每次从你的班级中随机抽取一些学生让他们参加模拟考试。
- 计算Qδ统计量 就像是计算每次模拟考试的平均分数。
- 存储所有Qδ值 就像是记录每次模拟考试的平均分数。
- 计算阈值 就像是从所有模拟考试的平均分数中找出一个你认为合适的分数,比如说,如果真正的期末考试平均分数低于这个值,你可能会认为班级的表现不好。
在代码的情况下,我们正在做的事情很类似。我们多次随机抽取数据,计算一个统计量(Qδ),记录它,并从这些记录中找出一个特定的值作为阈值。
6.早期停止
# 假设我们已经完成了一些训练周期,并有一个新的生成数据集
new_generated_data = pd.DataFrame({'Feature1': np.random.normal(0.05, 1.05, 100),
'Feature2': np.random.normal(0.05, 1.05, 100)})
# 重新计算距离和最小距离
new_distance_matrix = cdist(training_data, new_generated_data, metric='euclidean')
new_min_distance_train = np.min(new_distance_matrix, axis=1)
new_min_distance_gen = np.min(new_distance_matrix, axis=0)
# 重新计算Qδ统计量
new_q_delta = compute_q_delta(new_min_distance_train, new_min_distance_gen, quantiles)
# 检查是否应终止训练
if new_q_delta > threshold:
print("Stop training")
else:
print("Continue training")
下面是如何使用这个阈值来判断生成数据和训练数据的相似度是否超过了可接受程度的步骤:
-
计算生成数据的Qδ统计量:
- 首先,使用之前描述的方法计算生成数据与训练数据之间的Qδ统计量。
-
比较Qδ统计量与阈值:
- 然后,将实际计算出的Qδ统计量与通过自助法得到的阈值进行比较。
-
判断过拟合:
- 如果实际计算出的Qδ统计量大于阈值,这可能意味着生成数据过于接近训练数据,可能出现了过拟合。
- 如果Qδ统计量小于或等于阈值,那么生成数据的相似度可能处于可接受的范围内。