Suffix Zeroes

本文介绍了一个算法挑战,目标是找到最小的自然数n,使得n!的末尾恰好包含k个0。通过分析5和2的因子比例,采用二分搜索方法确定满足条件的n值。文章提供了一段C++代码实现,展示了如何高效解决问题。

Suffix Zeroes

时间限制: 1 Sec  内存限制: 128 MB

题目描述

这个游戏超休闲的~。现在你需要找一个自然数n,你找的自然数需要满足n!的末尾恰好有k个0(当然我们都是十进制下的数,n! = 1*2*3*…*n)。比如:5!= 120,尾部恰好有一个0。

输入

先输入T,代表有T组数据(T ≤10000)
接下来的T行每一行都包括一个数字k(1≤k≤108)。具体含义请见题意。

输出

 如果能找到这样的数,请输出满足条件的最小的自然数n,如果不存在这样的自然数,请输出impossible

样例输入

2
1
5

样例输出

Case 1: 5
Case 2: impossible

来源/分类

2018浙江理工大学新生赛 

题解:

末尾有一个零就代表有一个因数10,而10=2*5

当n>=5时,2的个数肯定比5多,所以只要枚举5的个数就行了

而能分解出5的数量为n/5+n/(5^2)+n/(5^3)……

所以5的个数小于5e8——直接二分答案再以上述方法检查就AC了

代码:

#include<bits/stdc++.h>
#define N 10005
#define Mod 1000007
#define M 10005
#define eps 1
using namespace std;
int check(int x)
{
    int sum=0,a=5;
    while(x>=a)
    {
        sum += x / a;
        a *= 5;
    }
    return sum;
}
int main()
{
    int t;
    scanf("%d",&t);
    for(int i = 1;i <= t; ++i)
    {
        int k;
        scanf("%d",&k);
        int l = 1,r = 5e8;
        while(r - l > eps)
        {
            int mid = (l + r) / 2;
            if(check(mid) >= k) r = mid;
            else l = mid;
        }
        printf("Case %d: ",i);
        if(check(r) == k) printf("%d\n",r);
        else puts("impossible");
    }
    return 0;
}

 

def load_image(filename): ext = splitext(filename)[1] if ext == '.npy': return Image.fromarray(np.load(filename)) elif ext in ['.pt', '.pth']: return Image.fromarray(torch.load(filename).numpy()) else: return Image.open(filename) def unique_mask_values(idx, mask_dir, mask_suffix): mask_file = list(mask_dir.glob(idx + mask_suffix + '.*'))[0] mask = np.asarray(load_image(mask_file)) if mask.ndim == 2: return np.unique(mask) elif mask.ndim == 3: mask = mask.reshape(-1, mask.shape[-1]) return np.unique(mask, axis=0) else: raise ValueError(f'Loaded masks should have 2 or 3 dimensions, found {mask.ndim}') class BasicDataset(Dataset): def __init__(self, images_dir: str, mask_dir: str, img_newsize: int, mask_suffix: str = ''): self.images_dir = Path(images_dir) self.mask_dir = Path(mask_dir) self.img_newsize = img_newsize self.mask_suffix = mask_suffix self.ids = [splitext(file)[0] for file in listdir(images_dir) if isfile(join(images_dir, file)) and not file.startswith('.')] if not self.ids: raise RuntimeError(f'No input file found in {images_dir}, make sure you put your images there') logging.info(f'Creating dataset with {len(self.ids)} examples') logging.info('Scanning mask files to determine unique values') with Pool() as p: unique = list(tqdm(p.imap(partial(unique_mask_values, mask_dir=self.mask_dir, mask_suffix=self.mask_suffix), self.ids), total=len(self.ids))) self.mask_values = list(sorted(np.unique(np.concatenate(unique), axis=0).tolist())) logging.info(f'Unique mask values: {self.mask_values}') def __len__(self): return len(self.ids) @staticmethod def preprocess(mask_values, input_img, img_newsize, is_mask): w, h = input_img.shape[1], input_img.shape[0] newW, newH = int(img_newsize[1]), int(img_newsize[0]) img = cv2.resize(input_img, (newW, newH), interpolation=cv2.INTER_NEAREST if is_mask else cv2.INTER_CUBIC) # img = np.asarray(pil_img) if is_mask: mask = np.zeros((newH, newW), dtype=np.int64) for i, v in enumerate(mask_values): if img.ndim == 2: mask[img == v] = i else: mask[(img == v).all(-1)] = i return mask else: if img.ndim == 2: img = img[np.newaxis, ...] else: img = img.transpose((2, 0, 1)) if (img > 1).any(): img = img / 255.0 return img def __getitem__(self, idx): name = self.ids[idx] mask_file = list(self.mask_dir.glob(name + self.mask_suffix + '.*')) img_file = list(self.images_dir.glob(name + '.*')) assert len(img_file) == 1, f'Either no image or multiple images found for the ID {name}: {img_file}' assert len(mask_file) == 1, f'Either no mask or multiple masks found for the ID {name}: {mask_file}' mask = cv2.imread(str(mask_file[0]),0) # gray img = cv2.imread(str(img_file[0])) # gray -> bgr img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) # rgb # assert img.size == mask.size, f'Image and mask {name} should be the same size, but are {img.size} and {mask.size}' img = self.preprocess(self.mask_values, img, self.img_newsize, is_mask=False) mask = self.preprocess(self.mask_values, mask, self.img_newsize, is_mask=True) return {'image': torch.as_tensor(img.copy()).float().contiguous(), 'mask': torch.as_tensor(mask.copy()).long().contiguous()} 解析此段代码
06-10
clear; close all; %% 固定随机数种子以确保结果可重复 rng(42); % 固定随机数种子 %% 第一部分:特征提取 - 每5000点提取一次特征 % 加载数据文件 load("2、9个负载,都去掉前面补0的值,并转置为列向量.mat"); % 定义模型 train_models = {'Diancilu_1', 'Jiashiqi_1'}; % 只使用这两个模型训练 test_models = {'Diancilu_1', 'Jiashiqi_1', 'LED_1', 'TV_1', 'bingxiang_1', 'dianfanbao_1', 'fengshan_1', 'kongtiaoguiji_1'}; % 测试这八个模型 % 定义每段数据点数 segment_size = 5000; % 每5000点作为一个样本 % 初始化特征存储矩阵 train_feature_matrix = []; train_labels = []; test_feature_matrix = []; test_labels = []; %% 处理训练数据 (Diancilu_1和Jiashiqi_1) for model_idx = 1:length(train_models) model_name = train_models{model_idx}; fprintf('正在处理训练模型: %s\n', model_name); % 获取原始数据 raw_data = eval(model_name); % 小波包分解 wpt = wpdec(raw_data, 4, 'rbio3.1'); reconstructed = wprcoef(wpt, [4, 2]); % 计算可以提取的完整段数 num_segments = floor(length(reconstructed) / segment_size); for seg = 1:num_segments start_idx = (seg-1)*segment_size + 1; end_idx = seg*segment_size; segment_data = reconstructed(start_idx:end_idx); % 计算能量特征(分成5段,每段1000点) energy_features = []; subseg_size = 1000; for subseg = 1:5 subseg_start = (subseg-1)*subseg_size + 1; subseg_end = subseg*subseg_size; energy_features = [energy_features, sum(segment_data(subseg_start:subseg_end).^2)]; end % 计算统计特征 stat_features = [mean(segment_data), std(segment_data), skewness(segment_data), kurtosis(segment_data)]; % 组合所有特征 combined_features = [energy_features, stat_features]; % 存储特征和标签 train_feature_matrix = [train_feature_matrix; combined_features]; train_labels = [train_labels; model_idx]; end fprintf('完成 %s 的特征提取,生成 %d 个训练样本\n', model_name, num_segments); end %% 处理测试数据 (所有8个模型) for model_idx = 1:length(test_models) model_name = test_models{model_idx}; fprintf('正在处理测试模型: %s\n', model_name); % 获取原始数据 raw_data = eval(model_name); % 小波包分解 wpt = wpdec(raw_data, 4, 'rbio3.1'); reconstructed = wprcoef(wpt, [4, 2]); % 计算可以提取的完整段数 num_segments = floor(length(reconstructed) / segment_size); for seg = 1:num_segments start_idx = (seg-1)*segment_size + 1; end_idx = seg*segment_size; segment_data = reconstructed(start_idx:end_idx); % 计算能量特征(分成5段,每段1000点) energy_features = []; subseg_size = 1000; for subseg = 1:5 subseg_start = (subseg-1)*subseg_size + 1; subseg_end = subseg*subseg_size; energy_features = [energy_features, sum(segment_data(subseg_start:subseg_end).^2)]; end % 计算统计特征 stat_features = [mean(segment_data), std(segment_data), skewness(segment_data), kurtosis(segment_data)]; % 组合所有特征 combined_features = [energy_features, stat_features]; % 存储特征和标签 test_feature_matrix = [test_feature_matrix; combined_features]; test_labels = [test_labels; model_idx]; end fprintf('完成 %s 的特征提取,生成 %d 个测试样本\n', model_name, num_segments); end %% 第二部分:数据预处理 % 数据归一化到[0,1]范围(DBN/RBM要求) min_vals = min(train_feature_matrix); max_vals = max(train_feature_matrix); % 修正归一化,确保不会除以0 range_vals = max_vals - min_vals; range_vals(range_vals == 0) = 1; train_feature_matrix = (train_feature_matrix - min_vals) ./ range_vals; test_feature_matrix = (test_feature_matrix - min_vals) ./ range_vals; % 确保数据在[0,1]范围内 test_feature_matrix(test_feature_matrix < 0) = 0; test_feature_matrix(test_feature_matrix > 1) = 1; % 将训练标签转换为one-hot编码(只有2类) train_label_onehot = full(ind2vec(train_labels'))'; % 随机打乱训练数据顺序 rand_order = randperm(size(train_feature_matrix, 1)); train_feature_matrix = train_feature_matrix(rand_order, :); train_label_onehot = train_label_onehot(rand_order, :); %% 第三部分:Transformer对比学习模型 fprintf('\n=== 开始Transformer对比学习训练 ===\n'); % 转换为序列数据格式 train_seq = permute(reshape(train_feature_matrix', size(train_feature_matrix, 2), 1, size(train_feature_matrix, 1)), [3 1 2]); test_seq = permute(reshape(test_feature_matrix', size(test_feature_matrix, 2), 1, size(test_feature_matrix, 1)), [3 1 2]); % 定义Transformer参数 input_size = size(train_seq, 2); embed_dim = 64; % 确保嵌入维度是头数的整数倍 num_heads = 4; num_layers = 2; output_size = 32; batch_size = 64; num_epochs = 100; learning_rate = 0.001; temperature = 0.1; % 创建基础层 layers = [ sequenceInputLayer(input_size, 'Name', 'input') fullyConnectedLayer(embed_dim, 'Name', 'embedding') reluLayer('Name', 'relu_embed') ]; % 初始化层图 contrastive_net = layerGraph(layers); % 构建Transformer层 for i = 1:num_layers layer_suffix = num2str(i); % 添加层组 layer_group = [ sequenceFoldingLayer('Name', ['fold_' layer_suffix]) fullyConnectedLayer(embed_dim*3, 'Name', ['attention_proj_' layer_suffix]) functionLayer(@(x) customMultiheadAttention(x, num_heads, embed_dim), 'Name', ['attention_' layer_suffix]) sequenceUnfoldingLayer('Name', ['unfold_' layer_suffix]) fullyConnectedLayer(embed_dim, 'Name', ['fc_' layer_suffix]) additionLayer(2, 'Name', ['add_' layer_suffix]) batchNormalizationLayer('Name', ['bn_' layer_suffix]) ]; contrastive_net = addLayers(contrastive_net, layer_group); % 确定前一层输出 if i == 1 prev_output = 'relu_embed'; else prev_output = ['bn_' num2str(i-1)]; end % 定义连接关系 - 修复未连接的输入/输出问题 connection_pairs = { {prev_output, ['fold_' layer_suffix]}, {['fold_' layer_suffix], ['attention_proj_' layer_suffix]}, {['attention_proj_' layer_suffix], ['attention_' layer_suffix]}, {['attention_' layer_suffix], ['unfold_' layer_suffix]}, % 修复unfold层的输入连接 {['unfold_' layer_suffix], ['fc_' layer_suffix]}, {['fc_' layer_suffix], ['add_' layer_suffix '/in1']}, {prev_output, ['add_' layer_suffix '/in2']}, % 残差连接 {['add_' layer_suffix], ['bn_' layer_suffix]} }; % 添加连接 for k = 1:length(connection_pairs) source = connection_pairs{k}{1}; target = connection_pairs{k}{2}; if ~isConnectionPresent(contrastive_net, source, target) try contrastive_net = connectLayers(contrastive_net, source, target); catch e fprintf('连接失败: %s -> %s (%s)\n', source, target, e.message); end end end end % 添加输出层 - 修改为分类层以匹配对比学习目标 output_layers = [ globalAveragePooling1dLayer('Name', 'global_pool') fullyConnectedLayer(output_size, 'Name', 'projection') batchNormalizationLayer('Name', 'bn_proj') fullyConnectedLayer(max(train_labels), 'Name', 'classifier') softmaxLayer('Name', 'softmax') classificationLayer('Name', 'output') ]; contrastive_net = addLayers(contrastive_net, output_layers); % 连接输出层 output_connections = { {['bn_' num2str(num_layers)], 'global_pool'}, {'global_pool', 'projection'}, {'projection', 'bn_proj'}, {'bn_proj', 'classifier'}, {'classifier', 'softmax'}, {'softmax', 'output'} }; for k = 1:length(output_connections) source = output_connections{k}{1}; target = output_connections{k}{2}; if ~isConnectionPresent(contrastive_net, source, target) contrastive_net = connectLayers(contrastive_net, source, target); end end % 验证网络结构 analyzeNetwork(contrastive_net); % 设置训练选项 options = trainingOptions('adam', ... 'InitialLearnRate', learning_rate, ... 'MaxEpochs', num_epochs, ... 'MiniBatchSize', batch_size, ... 'Shuffle', 'every-epoch', ... 'Verbose', false, ... 'Plots', 'training-progress'); % 训练模型 fprintf('Transformer模型训练中...\n'); contrastive_net = trainNetwork(train_seq, categorical(train_labels), contrastive_net, options); % 提取特征 fprintf('提取Transformer特征...\n'); train_features = activations(contrastive_net, single(train_seq), 'bn_proj', 'OutputAs', 'rows'); test_features = activations(contrastive_net, single(test_seq), 'bn_proj', 'OutputAs', 'rows'); % 组合特征 train_combined_features = [train_feature_matrix, train_features]; test_combined_features = [test_feature_matrix, test_features]; %% 第四部分:DBN训练 fprintf('\n=== 开始DBN训练 ===\n'); % 设置DBN参数 dbn.sizes = [100 50]; opts.numepochs = 20; opts.batchsize = 64; opts.momentum = 0.5; opts.alpha = 0.1; % 调整batchsize total_samples = size(train_combined_features, 1); if mod(total_samples, opts.batchsize) ~= 0 opts.batchsize = gcd(total_samples, opts.batchsize); end % 训练DBN dbn = dbnsetup(dbn, train_combined_features, opts); dbn = dbntrain(dbn, train_combined_features, opts); % 微调神经网络 nn = dbnunfoldtonn(dbn, size(train_label_onehot, 2)); nn.activation_function = 'sigm'; nn = nntrain(nn, train_combined_features, train_label_onehot, opts); % 测试模型 nn.testing = 1; out_prob = nnff(nn, test_combined_features, zeros(size(test_combined_features, 1), nn.size(end))); nn.testing = 0; [~, predicted_labels] = max(out_prob.a{end}, [], 2); %% 第五部分:混淆矩阵 confusion_mat = zeros(8, 8); prediction_mapping = [1, 2]; for i = 1:length(test_labels) true_class = test_labels(i); pred_class_idx = predicted_labels(i); pred_class = prediction_mapping(1); if pred_class_idx <= length(prediction_mapping) pred_class = prediction_mapping(pred_class_idx); end confusion_mat(true_class, pred_class) = confusion_mat(true_class, pred_class) + 1; end % 可视化 figure; set(gcf, 'Position', [100, 100, 1000, 900]); imagesc(confusion_mat); colorbar; title('混淆矩阵'); xlabel('预测类别'); ylabel('真实类别'); % 保存模型 save('trained_model.mat', 'dbn', 'nn', 'contrastive_net'); %% 函数定义 function output = customMultiheadAttention(input, num_heads, embed_dim) % 修复reshape操作,确保元素数量匹配 [batch_size, seq_len, dim] = size(input); % 确保维度匹配 if dim ~= embed_dim error('输入维度与嵌入维度不匹配'); end % 计算每个头的维度 head_dim = embed_dim / num_heads; % 确保头维度是整数 if mod(embed_dim, num_heads) ~= 0 error('嵌入维度必须是头数的整数倍'); end % 将输入分割为QKV qkv = reshape(input, batch_size, seq_len, 3, num_heads, head_dim); % 分离查询(Q)、键(K)和值(V) q = qkv(:,:,1,:,:); % [batch, seq_len, num_heads, head_dim] k = qkv(:,:,2,:,:); v = qkv(:,:,3,:,:); % 计算注意力分数 attn_scores = zeros(batch_size, seq_len, seq_len, num_heads); for h = 1:num_heads % 提取当前头的Q、K q_head = squeeze(q(:,:,h,:)); % [batch, seq_len, head_dim] k_head = squeeze(k(:,:,h,:)); % 计算注意力分数 [batch, seq_len, seq_len] attn_scores(:,:,:,h) = pagemtimes(q_head, permute(k_head, [1,3,2])) / sqrt(head_dim); end % 应用softmax获取注意力权重 attn_weights = softmax(attn_scores, 3); % 应用注意力权重到值 context = zeros(batch_size, seq_len, num_heads, head_dim); for h = 1:num_heads % 提取当前头的V v_head = squeeze(v(:,:,h,:)); % [batch, seq_len, head_dim] % 应用注意力权重 [batch, seq_len, head_dim] context(:,:,h,:) = pagemtimes(attn_weights(:,:,:,h), v_head); end % 重塑并合并多头结果 context_reshaped = reshape(context, batch_size, seq_len, embed_dim); % 确保输出维度正确 output = context_reshaped; end function loss = contrastiveLoss(features, labels, temperature) sim_matrix = features * features'; sim_matrix = sim_matrix - max(sim_matrix(:)); exp_sim = exp(sim_matrix / temperature); mask = ~eye(size(exp_sim)); pos_mask = (labels == labels') & mask; pos_sum = sum(exp_sim .* pos_mask, 2); neg_sum = sum(exp_sim .* mask, 2); loss = -mean(log(pos_sum ./ neg_sum)); end function y = softmax(x, dim) x = x - max(x, [], dim); ex = exp(x); y = ex ./ sum(ex, dim); end function present = isConnectionPresent(net, source, target) present = false; connections = net.Connections; for i = 1:height(connections) if strcmp(connections.Source{i}, source) && contains(connections.Destination{i}, target) present = true; return; end end end层 'fold_1': 未连接的输出。每个层输出必须连接到另一层的输入。 层 'fold_2': 未连接的输出。每个层输出必须连接到另一层的输入。 层 'unfold_1': 未连接的输入。每个层输入必须连接到另一个层的输出。 层 'unfold_2': 未连接的输入。每个层输入必须连接到另一个层的输出。修改代码实现上述功能
05-28
import numpy as np import matplotlib.pyplot as plt from sklearn.model_selection import train_test_split from sklearn.metrics import (accuracy_score, precision_score, recall_score, f1_score, roc_auc_score, confusion_matrix, roc_curve, precision_recall_curve) import seaborn as sns # 1. 基础函数:sigmoid激活函数 def sigmoid(z): """sigmoid激活函数""" return 1 / (1 + np.exp(-z)) # 2. 数据生成函数 def generate_data(n_samples=500, n_features=2, random_state=42): """生成用于二分类的模拟数据""" np.random.seed(random_state) # 两类样本的均值和协方差 mean_class0 = np.zeros(n_features) mean_class1 = np.ones(n_features) * 2 cov = np.eye(n_features) * 1.5 cov[0, 1] = cov[1, 0] = 0.5 # 特征相关性 # 生成数据并划分 X_class0 = np.random.multivariate_normal(mean_class0, cov, n_samples // 2) X_class1 = np.random.multivariate_normal(mean_class1, cov, n_samples // 2) X = np.vstack((X_class0, X_class1)) y = np.hstack((np.zeros(n_samples // 2), np.ones(n_samples // 2))) # 分层划分训练集、验证集、测试集 X_train_val, X_test, y_train_val, y_test = train_test_split( X, y, test_size=0.2, random_state=random_state, stratify=y ) X_train, X_val, y_train, y_val = train_test_split( X_train_val, y_train_val, test_size=0.25, random_state=random_state, stratify=y_train_val ) return X_train, X_val, X_test, y_train, y_val, y_test # 3. 带L2正则化的逻辑回归模型 class RegularizedLogisticRegression: def __init__(self, learning_rate=0.01, num_iterations=1000, lambda_=0.1): self.learning_rate = learning_rate self.num_iterations = num_iterations self.lambda_ = lambda_ # 正则化系数(λ越大,惩罚越强) self.weights = None # 包含偏置项的权重 [w0, w1, ..., wn] self.train_losses = [] self.val_losses = [] self.val_accuracies = [] def _add_bias_term(self, X): """添加偏置项(全为1的列)""" return np.hstack((np.ones((X.shape[0], 1)), X)) def _compute_loss(self, y, y_pred): """计算带L2正则化的交叉熵损失""" epsilon = 1e-10 cross_entropy = -np.mean(y * np.log(y_pred + epsilon) + (1 - y) * np.log(1 - y_pred + epsilon)) # L2正则化项(不含偏置项w0) l2_regularization = (self.lambda_ / (2 * len(y))) * np.sum(self.weights[1:] ** 2) return cross_entropy + l2_regularization def fit(self, X_train, y_train, X_val, y_val): """训练模型(带正则化的梯度下降)""" n_samples, n_features = X_train.shape self.weights = np.zeros(n_features + 1) # 初始化权重(含偏置项) X_train_bias = self._add_bias_term(X_train) for i in range(self.num_iterations): # 计算预测值 z = np.dot(X_train_bias, self.weights) y_pred = sigmoid(z) # 计算梯度(含正则化项,偏置项无正则化) gradient = np.dot(X_train_bias.T, (y_pred - y_train)) / n_samples gradient[1:] += (self.lambda_ / n_samples) * self.weights[1:] # 仅对w1~wn加正则化梯度 # 更新权重 self.weights -= self.learning_rate * gradient # 记录训练损失 train_loss = self._compute_loss(y_train, y_pred) self.train_losses.append(train_loss) # 记录验证指标 val_pred = self.predict_proba(X_val) val_loss = self._compute_loss(y_val, val_pred) self.val_losses.append(val_loss) val_pred_class = (val_pred >= 0.5).astype(int) self.val_accuracies.append(accuracy_score(y_val, val_pred_class)) # 打印迭代信息 if i % 100 == 0: print(f"Iteration {i}: Train Loss = {train_loss:.4f}, Val Loss = {val_loss:.4f}, Val Acc = {self.val_accuracies[-1]:.4f}") def predict_proba(self, X): """预测正类概率""" X_bias = self._add_bias_term(X) return sigmoid(np.dot(X_bias, self.weights)) def predict(self, X, threshold=0.5): """预测类别""" return (self.predict_proba(X) >= threshold).astype(int) def plot_training_curves(self, title_suffix=""): """绘制训练曲线""" plt.figure(figsize=(12, 4)) # 损失曲线 plt.subplot(1, 2, 1) plt.plot(self.train_losses, label='Train Loss') plt.plot(self.val_losses, label='Validation Loss') plt.title(f'Loss Curves {title_suffix}') plt.xlabel('Iteration') plt.ylabel('Loss') plt.legend() plt.grid(alpha=0.3) # 准确率曲线 plt.subplot(1, 2, 2) plt.plot(self.val_accuracies, label='Validation Accuracy') plt.title(f'Validation Accuracy {title_suffix}') plt.xlabel('Iteration') plt.ylabel('Accuracy') plt.legend() plt.grid(alpha=0.3) plt.tight_layout() plt.show() # 4. 模型评估函数 def evaluate_model(model, X_test, y_test, title_suffix=""): """评估模型并可视化结果""" y_pred_proba = model.predict_proba(X_test) y_pred = model.predict(X_test) # 计算指标 metrics = { 'accuracy': accuracy_score(y_test, y_pred), 'precision': precision_score(y_test, y_pred), 'recall': recall_score(y_test, y_pred), 'f1': f1_score(y_test, y_pred), 'roc_auc': roc_auc_score(y_test, y_pred_proba) } # 打印指标 print(f"\n===== 模型评价指标 {title_suffix} =====") for name, value in metrics.items(): print(f"{name.capitalize()}: {value:.4f}") # 混淆矩阵 cm = confusion_matrix(y_test, y_pred) plt.figure(figsize=(5, 4)) sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', cbar=False, xticklabels=['Class 0', 'Class 1'], yticklabels=['Class 0', 'Class 1']) plt.xlabel('Predicted') plt.ylabel('Actual') plt.title(f'Confusion Matrix {title_suffix}') plt.show() # ROC曲线 fpr, tpr, _ = roc_curve(y_test, y_pred_proba) plt.figure(figsize=(5, 4)) plt.plot(fpr, tpr, label=f'ROC (AUC = {metrics["roc_auc"]:.4f})') plt.plot([0, 1], [0, 1], 'k--', alpha=0.3) plt.xlabel('False Positive Rate') plt.ylabel('True Positive Rate') plt.title(f'ROC Curve {title_suffix}') plt.legend() plt.grid(alpha=0.3) plt.show() return metrics # 5. 决策边界绘制函数 def plot_decision_boundary(model, X, y, title_suffix=""): """绘制决策边界""" plt.figure(figsize=(8, 6)) plt.scatter(X[y == 0][:, 0], X[y == 0][:, 1], label='Class 0', alpha=0.6) plt.scatter(X[y == 1][:, 0], X[y == 1][:, 1], label='Class 1', alpha=0.6) # 生成网格 x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1 xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.01), np.arange(y_min, y_max, 0.01)) grid = np.c_[xx.ravel(), yy.ravel()] # 预测并绘制决策边界 Z = model.predict_proba(grid).reshape(xx.shape) plt.contour(xx, yy, Z, levels=[0.5], linewidths=2, colors='red') plt.title(f'Decision Boundary {title_suffix}') plt.xlabel('Feature 1') plt.ylabel('Feature 2') plt.legend() plt.grid(alpha=0.3) plt.show() # 6. 对比实验:无正则化 vs 有正则化 if __name__ == "__main__": # 生成数据(增加特征数模拟可能过拟合的场景) X_train, X_val, X_test, y_train, y_val, y_test = generate_data( n_samples=500, n_features=10, random_state=42 # 10个特征易过拟合 ) # 训练无正则化模型 print("===== 训练无正则化模型 =====") model_baseline = RegularizedLogisticRegression( learning_rate=0.1, num_iterations=2000, lambda_=0 # lambda=0即无正则化 ) model_baseline.fit(X_train, y_train, X_val, y_val) model_baseline.plot_training_curves(title_suffix="(无正则化)") # 训练带正则化模型 print("\n===== 训练带L2正则化模型 =====") model_regularized = RegularizedLogisticRegression( learning_rate=0.1, num_iterations=2000, lambda_=1.0 # 正则化系数λ=1.0 ) model_regularized.fit(X_train, y_train, X_val, y_val) model_regularized.plot_training_curves(title_suffix="(带L2正则化)") # 对比测试集性能 metrics_baseline = evaluate_model(model_baseline, X_test, y_test, title_suffix="(无正则化)") metrics_regularized = evaluate_model(model_regularized, X_test, y_test, title_suffix="(带L2正则化)") # 对比决策边界(取前2个特征可视化) plot_decision_boundary(model_baseline, X_test[:, :2], y_test, title_suffix="(无正则化)") plot_decision_boundary(model_regularized, X_test[:, :2], y_test, title_suffix="(带L2正则化)") # 对比权重大小(正则化应使权重更小) print("\n===== 权重大小对比 =====") print(f"无正则化模型权重绝对值之和: {np.sum(np.abs(model_baseline.weights)):.4f}") print(f"带正则化模型权重绝对值之和: {np.sum(np.abs(model_regularized.weights)):.4f}")
09-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值