news 2026/6/10 19:53:13

实战房价竞赛

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
实战房价竞赛

下载数据集

# 导入所需的库 import hashlib # 用于计算文件的SHA-1哈希值,验证文件完整性 import os # 用于操作系统路径、目录等操作 import tarfile # 用于处理.tar或.gz压缩文件 import zipfile # 用于处理.zip压缩文件 import requests # 用于发送HTTP请求,下载文件 # @save 是d2l库的标记,表示该函数会被保存或复用 DATA_HUB = dict() # 全局字典,存储数据集名称和对应的(URL, SHA-1哈希值) DATA_URL = 'http://d2l-data.s3-accelerate.amazonaws.com/' # 数据集基础URL def download(name, cache_dir=os.path.join('..', 'data')): #@save """下载一个DATA_HUB中的文件,返回本地文件名""" # 断言:确保要下载的文件名在DATA_HUB中已定义 assert name in DATA_HUB, f"{name} 不存在于 {DATA_HUB}" # 从DATA_HUB获取URL和期望的SHA-1哈希值 url, sha1_hash = DATA_HUB[name] # 创建缓存目录(如果不存在) os.makedirs(cache_dir, exist_ok=True) # 生成本地文件路径:缓存目录 + URL中的文件名 fname = os.path.join(cache_dir, url.split('/')[-1]) # 如果文件已存在,检查其哈希值是否匹配 if os.path.exists(fname): sha1 = hashlib.sha1() # 以二进制模式打开文件,分块读取(每次1MB) with open(fname, 'rb') as f: while True: data = f.read(1048576) # 1MB = 1024 * 1024 if not data: break sha1.update(data) # 如果哈希值匹配,直接返回缓存的文件路径 if sha1.hexdigest() == sha1_hash: return fname # 命中缓存 # 如果文件不存在或哈希不匹配,则重新下载 print(f'正在从{url}下载{fname}...') r = requests.get(url, stream=True, verify=True) # 发送GET请求下载文件 with open(fname, 'wb') as f: f.write(r.content) # 将下载的内容写入文件 return fname def download_extract(name, folder=None): #@save """下载并解压zip/tar文件""" fname = download(name) # 调用download函数获取文件路径 base_dir = os.path.dirname(fname) # 获取文件所在目录 data_dir, ext = os.path.splitext(fname) # 分离文件名和扩展名 # 根据扩展名选择解压方式 if ext == '.zip': fp = zipfile.ZipFile(fname, 'r') # 打开ZIP文件 elif ext in ('.tar', '.gz'): fp = tarfile.open(fname, 'r') # 打开TAR/GZ文件 else: assert False, '只有zip/tar文件可以被解压缩' # 解压到基础目录 fp.extractall(base_dir) # 如果指定了子文件夹,返回该子文件夹路径;否则返回解压后的目录 return os.path.join(base_dir, folder) if folder else data_dir def download_all(): #@save """下载DATA_HUB中的所有文件""" for name in DATA_HUB: download(name) # 如果没有安装pandas,请取消下一行的注释 # !pip install pandas # 设置matplotlib为内联模式,图像直接显示在Notebook中 %matplotlib inline # 导入常用库 import numpy as np # 数值计算库 import pandas as pd # 数据处理和分析库 import torch # PyTorch深度学习框架 from torch import nn # PyTorch神经网络模块 from d2l import torch as d2l # 导入d2l的PyTorch版本 # 定义Kaggle房价预测训练集的信息 DATA_HUB['kaggle_house_train'] = ( #@save DATA_URL + 'kaggle_house_pred_train.csv', # 文件URL '585e9cc93e70b39160e7921475f9bcd7d31219ce') # 文件的SHA-1哈希值 # 定义Kaggle房价预测测试集的信息 DATA_HUB['kaggle_house_test'] = ( #@save DATA_URL + 'kaggle_house_pred_test.csv', 'fa19780a7b011d9b009e8bff8e99922a8ee2eb90') # 下载并读取训练数据到pandas DataFrame train_data = pd.read_csv(download('kaggle_house_train')) # 下载并读取测试数据到pandas DataFrame test_data = pd.read_csv(download('kaggle_house_test'))

主要功能总结:

  1. download():智能下载文件,支持缓存和完整性校验(SHA-1)。

  2. download_extract():下载并自动解压压缩文件。

  3. download_all():批量下载所有数据集。

结果:

数据预处理(key 不熟)

all_features = pd.concat( (train_data.iloc[:, 1:-1], test_data.iloc[:, 1:]) )

把训练集的特征列和测试集的特征列拼在一起,形成一个新的 DataFrame(因为是pandas)。(没想到)

合并训练和测试集的特征(为了统一预处理)

结果:

填充缺失值和归一化特征

# 特征预处理 # 1. 识别数值特征 numeric_features = all_features.dtypes[all_features.dtypes != 'object'].index # 2. 数值特征标准化(Z-score标准化) # 注意:这里使用了整个数据集(训练+测试)计算均值和标准差 # 实际生产中应该只使用训练集统计量 all_features[numeric_features] = all_features[numeric_features].apply( lambda x: (x - x.mean()) / (x.std()) ) # 3. 标准化后,缺失值用0填充(因为标准化后均值为0) all_features[numeric_features] = all_features[numeric_features].fillna(0) # 4. 类别特征进行独热编码,dummy_na=True会将缺失值也视为一个类别 all_features = pd.get_dummies(all_features, dummy_na=True) # 获取特征数量 print(f"预处理后的特征维度: {all_features.shape}") # 分离回训练和测试集 n_train = train_data.shape[0] # 训练集样本数 train_features = torch.tensor(all_features[:n_train].values, dtype=torch.float32) test_features = torch.tensor(all_features[n_train:].values, dtype=torch.float32) # 获取训练标签 train_labels = torch.tensor( train_data.SalePrice.values.reshape(-1, 1), dtype=torch.float32 ) # 打印数据形状 print(f"训练特征形状: {train_features.shape}") print(f"训练标签形状: {train_labels.shape}") print(f"测试特征形状: {test_features.shape}")
1细节 处理连续数据 取出数字列

指的是和object比较得到结果是布尔型序列(因为有很多个特征列) 下图所示

取出索引(类似于字典)

2细节 数字列归一化

先标准化再填充缺失值

处理离散特征,独热编码:

机器学习中处理离散特征(分类特征)的一种常用方法,叫做独热编码(One-Hot Encoding)

简单来说,它的目的是把文字类别变成计算机能读懂的数字向量

1. 为什么要这么做?

原始的表格里,像MSZoning( zoning 分类)这样的列,里面的值是文字,比如 "RL"(住宅低密), "RM"(住宅中等密), 或者是空的(NaN)。

  • 计算机不认识字:模型只能计算数字。

  • 不能随便编数字:如果你把 "RL" 编成 1,"RM" 编成 2,模型可能会误以为 "RM" 比 "RL" 大,或者它们有高低之分,但这在现实中是不成立的(它们是平等的类别)。

2. 它是怎么工作的?(以 "RL" 为例)

独热编码的做法是:既然它们是平等的,那就给每个类别发一个专属的“开关”(0或1)。

不再有MSZoning这个列了

检查结果是否正确:
# 检查每一列的数据类型 print(all_features.dtypes) # 找出所有非数值类型的列(object 或 string) non_numeric_cols = all_features.select_dtypes(include=['object', 'string']).columns print("以下列是非数值类型,导致了报错:") print(non_numeric_cols)

弄出训练集和测试集(分割,因为最开始时候concat了)

通过values属性,我们可以 [pandas格式中提取NumPy格式,并将其转换为张量表示]用于训练。

# 获取训练集的样本数量(行数) n_train = train_data.shape[0] # train_data.shape[0]返回训练数据的行数,即样本数量 # 从合并的特征数据all_features中取出前n_train行作为训练特征 # all_features[:n_train] 通过切片获取前n_train行(训练集部分) # .values 将DataFrame转换为NumPy数组 # torch.tensor(...) 将NumPy数组转换为PyTorch张量,并指定数据类型为float32 train_features = torch.tensor(all_features[:n_train].values, dtype=torch.float32) # 从合并的特征数据all_features中取出从n_train行开始到最后一行的数据作为测试特征 # all_features[n_train:] 获取从第n_train行开始到最后一行的数据(测试集部分) # 同样转换为PyTorch张量 test_features = torch.tensor(all_features[n_train:].values, dtype=torch.float32) # 获取训练集的标签(房价) # train_data.SalePrice 是训练集中的房价列 # .values 转换为NumPy数组 # .reshape(-1, 1) 将一维数组转换为二维数组,形状为[n, 1](n行1列) # 这里-1表示自动计算该维度的大小,即自动根据原数组元素数量和指定的其他维度(1)来推断 # 例如,原数组有1460个元素,reshape(-1, 1)就会转换成1460行1列的二维数组 # 最后将其转换为PyTorch张量,数据类型为float32 train_labels = torch.tensor( train_data.SalePrice.values.reshape(-1, 1), dtype=torch.float32)

训练:

以简单的线性模型为baseline作为对比的

# 定义均方误差损失函数(Mean Squared Error Loss) loss = nn.MSELoss() # 获取输入特征的维度,即特征的数量 # train_features.shape[1] 返回训练特征张量的列数,即每个样本的特征数 in_features = train_features.shape[1] # 定义一个函数用于创建神经网络模型 def get_net(): # 使用nn.Sequential定义一个简单的线性回归模型 # 该模型只包含一个全连接层(Linear),输入维度为in_features,输出维度为1 net = nn.Sequential(nn.Linear(in_features,1)) return net # 定义一个函数,计算对数均方根误差(Log Root Mean Squared Error) # 在房价预测任务中,通常使用对数均方根误差作为评估指标,因为房价的分布通常是偏态的,取对数可以使误差更接近正态分布 def log_rmse(net, features, labels): # 使用模型net对特征features进行预测 # 通过torch.clamp将预测值限制在1到正无穷之间,避免取对数时出现负值或零(因为log(0)是负无穷,log(负数)是NaN) clipped_preds = torch.clamp(net(features), 1, float('inf')) # 计算对数均方根误差: # 1. 对预测值和真实值分别取对数 # 2. 计算两者之间的均方误差(使用之前定义的MSE损失函数) # 3. 对均方误差开方,得到均方根误差 rmse = torch.sqrt(loss(torch.log(clipped_preds), torch.log(labels))) # 返回一个标量(Python浮点数),通过.item()将张量转换为浮点数 return rmse.item() # 定义训练函数 def train(net, train_features, train_labels, test_features, test_labels, num_epochs, learning_rate, weight_decay, batch_size): # 初始化两个列表,分别用于记录训练集和测试集在每个epoch后的对数均方根误差 train_ls, test_ls = [], [] # 使用d2l库中的load_array函数,将训练特征和训练标签转换为一个可以迭代的数据加载器 # 每次迭代返回一个批次的数据(包含batch_size个样本) train_iter = d2l.load_array((train_features, train_labels), batch_size) # 定义优化器,这里使用Adam优化算法 # net.parameters()返回网络中所有需要训练的参数 # lr:学习率 # weight_decay:权重衰减(L2正则化)系数,用于防止过拟合 optimizer = torch.optim.Adam(net.parameters(), lr = learning_rate, weight_decay = weight_decay) # 开始训练,迭代num_epochs个周期 for epoch in range(num_epochs): # 每个epoch中,遍历数据加载器中的每一个批次 for X, y in train_iter: # 在计算梯度之前,先将优化器中之前存储的梯度清零 optimizer.zero_grad() # 前向传播:计算模型在当前批次上的预测值,并计算损失 l = loss(net(X), y) # 反向传播:计算损失函数关于模型参数的梯度 l.backward() # 更新模型参数:根据梯度使用优化器更新参数 optimizer.step() # 一个epoch结束后,计算整个训练集上的对数均方根误差,并记录 train_ls.append(log_rmse(net, train_features, train_labels)) # 如果提供了测试标签(即test_labels不为None),则计算测试集上的对数均方根误差并记录 if test_labels is not None: test_ls.append(log_rmse(net, test_features, test_labels)) # 返回训练和测试过程中每个epoch的对数均方根误差列表 return train_ls, test_ls

k折交叉验证:重点

获取k折数据+进行k折验证:

# 定义一个函数,用于获取K折交叉验证中第i折的训练数据和验证数据 def get_k_fold_data(k, i, X, y): # 断言k必须大于1,因为至少需要2折才能进行交叉验证 assert k > 1 # 计算每一折的大小(样本数),这里使用整数除法,所以可能不能整除,余数部分被忽略 fold_size = X.shape[0] // k # 初始化训练数据和标签为None X_train, y_train = None, None # 遍历k折 for j in range(k): # 计算当前折的索引范围,slice对象用于切片 idx = slice(j * fold_size, (j + 1) * fold_size) # 根据索引切片获取当前折的特征和标签 X_part, y_part = X[idx, :], y[idx] # 如果当前折是第i折,则作为验证集 if j == i: X_valid, y_valid = X_part, y_part # 否则,将当前折合并到训练集中 # 如果训练集为空,则直接赋值 elif X_train is None: X_train, y_train = X_part, y_part # 如果训练集不为空,则通过torch.cat在0维度(行方向)进行拼接 else: X_train = torch.cat([X_train, X_part], 0) y_train = torch.cat([y_train, y_part], 0) # 返回训练集特征、训练集标签、验证集特征、验证集标签 return X_train, y_train, X_valid, y_valid # 定义一个函数,执行K折交叉验证 def k_fold(k, X_train, y_train, num_epochs, learning_rate, weight_decay, batch_size): # 初始化训练和验证误差总和 train_l_sum, valid_l_sum = 0, 0 # 遍历每一折 for i in range(k): # 获取当前折的训练和验证数据 data = get_k_fold_data(k, i, X_train, y_train) # 创建一个新的网络模型 net = get_net() # 训练模型,并返回训练和验证的误差列表 # 注意:这里使用了*data将返回的四个值作为参数传递给train函数 train_ls, valid_ls = train(net, *data, num_epochs, learning_rate, weight_decay, batch_size) # 将最后一轮的训练和验证误差累加到总和中 train_l_sum += train_ls[-1] valid_l_sum += valid_ls[-1] # 如果是第一折,绘制训练和验证误差曲线 if i == 0: d2l.plot(list(range(1, num_epochs + 1)), [train_ls, valid_ls], xlabel='epoch', ylabel='rmse', xlim=[1, num_epochs], legend=['train', 'valid'], yscale='log') # 打印当前折的训练和验证误差(最后一轮) print(f'折{i + 1},训练log rmse{float(train_ls[-1]):f}, ' f'验证log rmse{float(valid_ls[-1]):f}') # 返回K折交叉验证的平均训练误差和平均验证误差 return train_l_sum / k, valid_l_sum / k

核心思想:把训练数据分成K份,轮流用其中K-1份训练,1份验证,重复K次,取平均结果。

类比

你有5个老师教同一个学生,每个老师用4/5的内容教,用剩下的1/5考试,最后看5个老师的平均分数。

例子:

eg:

# 遍历5折 for j in range(5): idx = slice(j*200, (j+1)*200) # 当前折的索引范围 if j == 0: # 第0折 → 验证集 X_valid, y_valid = X[0:200], y[0:200] elif j == 1: # 第1折 → 训练集第一部分 X_train, y_train = X[200:400], y[200:400] else: # 第2,3,4折 → 拼接到训练集 X_train = torch.cat([X_train, X[400:600]], 0) # 第2折 # ...继续拼接
划分数据代码解读:

我习惯第一种拼接写法
# 对比两种写法: # 写法1:先创建空列表,再拼接 X_train_parts = [] for j in range(k): if j != i: # 如果不是验证折 X_train_parts.append(X_part) # 最后用torch.cat拼接所有部分 # 写法2:当前代码的写法 X_train = None for j in range(k): if j != i: # 如果不是验证折 if X_train is None: # 第一次遇到训练折 X_train = X_part else: # 后续训练折 X_train = torch.cat([X_train, X_part], 0)

0 1是dim参数的值

验证代码解读:

------------------

----------------------

train_l_sum += train_ls[-1] # 只取最后一个epoch来加入
# 但有时最佳模型在中间epoch
# 应该取验证误差最小的那个epoch 但为了初学者懂

train_ls, valid_ls = train(net, *data, num_epochs, learning_rate,
weight_decay, batch_size)
train_l_sum += train_ls[-1]
valid_l_sum += valid_ls[-1]

和return train_l_sum / k, valid_l_sum / k 关系:

每个epoch都进行k折验证

train_ls, valid_ls是训练了num_epochs的结果 最后 train_l_sum每次都只用最后一个epoch结果

所以最后 train_l_sum就只包含了k份数据,然后➗️得到平均值

模型选择(调参数):
先用部分数据(比如下图的某折来验证)来调参
k, num_epochs, lr, weight_decay, batch_size = 5, 100, 5, 0, 64 train_l, valid_l = k_fold(k, train_features, train_labels, num_epochs, lr, weight_decay, batch_size) print(f'{k}-折验证: 平均训练log rmse: {float(train_l):f}, ' f'平均验证log rmse: {float(valid_l):f}')

上图是选择了一组未调优的超参数,并将其留给读者来改进模型。 找到一组调优的超参数可能需要时间,这取决于一个人优化了多少变量。 有了足够大的数据集和合理设置的超参数,折交叉验证往往对多次测试具有相当的稳定性。 然而,如果我们尝试了不合理的超参数,我们可能会发现验证效果不再代表真正的误差。

有时一组超参数的训练误差可能非常低,但折交叉验证的误差要高得多, 这表明模型过拟合了。 在整个训练过程中,我们希望监控训练误差和验证误差这两个数字。较少的过拟合可能表明现有数据可以支撑一个更强大的模型, 较大的过拟合可能意味着我们可以通过正则化技术来获益。

用全部数据(已经得到合适的超参数了)来训练:
def train_and_pred(train_features, test_features, train_labels, test_data, num_epochs, lr, weight_decay, batch_size): """ 完整的训练和预测函数 参数: train_features: 训练集特征 (Tensor) test_features: 测试集特征 (Tensor) train_labels: 训练集标签 (Tensor) test_data: 原始的测试数据集 (Pandas DataFrame,包含Id列) num_epochs: 训练轮数 lr: 学习率 weight_decay: 权重衰减 (L2正则化系数) batch_size: 批次大小 """ # 1. 创建新的神经网络模型实例 net = get_net() # 2. 使用全部训练数据训练模型 # train函数的第4、5个参数设为None,表示不传入验证集/测试集 # 所以只返回训练误差列表train_ls,第二个返回值用_接收表示忽略 train_ls, _ = train(net, train_features, train_labels, None, None, num_epochs, lr, weight_decay, batch_size) # 3. 绘制训练误差随训练轮次变化的曲线 d2l.plot(np.arange(1, num_epochs + 1), # x轴:1到num_epochs [train_ls], # y轴:训练误差列表 xlabel='epoch', # x轴标签 ylabel='log rmse', # y轴标签 xlim=[1, num_epochs], # x轴范围 yscale='log') # y轴使用对数刻度(误差值通常较小) # 4. 打印最终训练误差 print(f'训练log rmse:{float(train_ls[-1]):f}') # 5. 使用训练好的模型在测试集上进行预测 # net(test_features):模型前向传播,得到预测结果 # .detach():从计算图中分离,不记录梯度 # .numpy():转换为NumPy数组 preds = net(test_features).detach().numpy() # 6. 将预测结果重新格式化以便导出到Kaggle # preds.reshape(1, -1):将预测结果重塑为1行多列的二维数组 # [0]:取第一行(因为是1行,所以就是取所有预测值) # pd.Series:转换为Pandas Series,方便添加到DataFrame test_data['SalePrice'] = pd.Series(preds.reshape(1, -1)[0]) # 7. 创建提交文件 # 提取测试集的Id列和预测的SalePrice列 submission = pd.concat([test_data['Id'], test_data['SalePrice']], axis=1) # 8. 将结果保存为CSV文件,用于Kaggle提交 # index=False:不保存行索引 submission.to_csv('submission.csv', index=False) train_and_pred(train_features, test_features, train_labels, test_data, num_epochs, lr, weight_decay, batch_size)

输入数据

创建新模型

用全部训练数据训练


绘制训练误差曲线

打印最终训练误差

在测试集上预测

格式化预测结果

保存为提交文件

细节:

竞赛总结:

10行代码战胜90%数据科学家?

10行代码战胜90%数据科学家?_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1rh411m7Hb/?from=search&seid=14820697425740410884&spm_id_from=333.788.comment.all.click&vd_source=5252d3cdd5246bf9326ccfc5acb9064410行代码战胜90%数据科学家?_哔哩哔哩_bilibili
第三h2o:

https://www.kaggle.com/wuwawa/automl-using-h2o
第四 随机森林:

https://www.kaggle.com/jackzh/the-4th-place-approach-random-forest

https://www.bilibili.com/video/BV15Q4y1o7vc/?spm_id_from=333.999.0.0&vd_source=5252d3cdd5246bf9326ccfc5acb90644

MLP效果不好

eg:

1有些特征文本很多,比如房子介绍

可以直接舍弃文本信息/transform等处理 但不能onehot编码,因为不会有两个文本一样的数据,这样维度就很高了,数据里面是10w条这样

2 数据较大

房子价格美金 差距很大,可以先取log再归一化处理

评分较高的automl:一样是集成模型

【机器学习】解放双手!AutoML入门:从原理到Auto-sklearn实战,告别繁琐调参_automl 开源框架-CSDN博客

一、 文本特征(地址、介绍)怎么处理?

在传统的机器学习中,直接把“我爱我家,温馨两居”这种文本扔进树模型(如XGBoost/LightGBM)是不行的。不能直接塞进去,必须先进行“结构化”或“向量化”提取。

1. 地址类文本:靠“正则表达式”提取标签

地址往往很长,但包含的关键信息(学区、地铁、商圈)对房价影响巨大。不要试图把整个地址字符串当作一个特征,而是要用正则把关键信息抠出来变成数值或类别:

  • 提取硬性配套:用正则匹配是否包含“地铁”、“学区”、“三甲医院”、“万达广场”等关键词,转换成has_subway(0或1)、school_district(学区等级) 等布尔或数值特征。

  • 结构化解析:比如把“广州市天河区珠江新城保利心语”拆解成城市=广州行政区=天河商圈=珠江新城小区=保利心语

  • 高阶玩法(聚类):如果小区名称有几千个,可以计算每个小区的历史均价,然后用 K-Means 把这几千个小区聚类成 5-10 个档次(如:豪宅盘、刚需盘),用聚类的标签代替原始小区名,既降维又保留了地理价值。

2. 介绍类文本(房源描述):靠“Embedding”获取语义

对于“南北通透,采光极佳,拎包入住”这种描述心情和状态的文本:

  • 传统方法(TF-IDF):简单粗暴,把词变成数字。但如果介绍太长,维度会爆炸,容易过拟合。

  • 深度学习方法(强烈推荐):使用 NLP 领域的预训练模型(如BERT、Word2Vec)。

    • 把一段介绍文本输入 BERT,它会输出一个固定长度(比如 768 维)的向量。

    • 这个向量就代表了这段描述的“整体语义氛围”。

    • 将这个向量作为额外的特征拼接到你的表格数据中,能让模型理解“豪华装修”和“毛坯简装”在语义上的巨大差异。


二、 公榜和私榜是什么意思?

这是数据科学竞赛(如 Kaggle)最核心的机制,也是你提到的第三点“数据切分”的真正用意。

1. 基本定义

  • 公榜 (Public Leaderboard):比赛期间实时更新的排行榜。你的模型在一部分隐藏的测试数据上跑出的分数会显示在这里,所有人都能看到你的实时排名。

  • 私榜 (Private Leaderboard):比赛结束后才揭晓的排行榜。你的模型在另一部分更深度的隐藏数据上跑分,这决定了你的最终奖金和获奖资格。

2. 为什么要分公榜和私榜?(防作弊与防过拟合)

这就回到了你说的“时间切分”:前6个月训练,公榜是后3个月,私榜是再后3个月

  • 公榜的作用:给你的模型一个“试错反馈”。让你知道模型能不能推广到稍微未来的数据。

  • 私榜的作用终极审判。用来检验你的模型是不是真的学到了普适规律,还是在公榜那3个月的数据上“死记硬背”(过拟合)了。

3. 实战中的“致命陷阱”:Shake-Up(排名震荡)

如果你为了让公榜排名更高,疯狂地针对公榜那3个月的数据调参、加特征,你的模型就会完美适应公榜,但到了私榜(再后3个月,市场行情可能变了,尤其这个房价预测,波动太大了)就会一塌糊涂。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 19:53:06

bgp策略

需求:1、使用PreVal策略,确保R4通过R2到达192.168.10.0/24 2、使用AS_Path策略,确保R4通过R3到达192.168.11.0/24 3、配置MED策略,确保R4通过R3到达192.168.12.0/24 4、使用Local Preference策略,确保R1通过R2到达192.…

作者头像 李华
网站建设 2026/6/10 19:52:24

Web分布式网站架构之-Squid缓存【20260608】001篇

文章目录 一、Squid 是啥? 二、代理的三种类型(重点) 三、怎么装 Squid? 四、两种常见代理怎么搭? 1️⃣ 传统代理 2️⃣ 透明代理(稍难) 五、ACL 访问控制(超实用) 用法两步走: 六、日志分析工具 SARG 七、一句话总结 这份文档讲的是 Squid 代理服务器 的入门到实战…

作者头像 李华
网站建设 2026/6/10 19:48:05

2026网盘隐私大测评!哪家文件加密最靠谱?高安全网盘横向盘点

日常存照片、证件资料、工作合同、学习文档,大家都离不开网盘。但很多人在2026年依然纠结:面对勒索病毒变种和复杂的数据环境,哪款网盘私密加密更靠谱,能真正保护私人文件、避免数据隐私风险? 2026年主流网盘层出不穷…

作者头像 李华
网站建设 2026/6/10 19:48:00

Spring AI实战:快速集成阿里通义千问

一、背景:AI时代,Java开发者如何不掉队? 最近AI Agent概念火得一塌糊涂,ChatGPT、Claude等大模型能写代码、能查资料,甚至能调用外部工具。但作为Java后端开发,我们最关心的是:如何把AI能力集成…

作者头像 李华
网站建设 2026/6/10 19:47:31

从原理到落地:本地消息表 + RocketMQ 分布式事务方案

如今的微服务架构中,分布式事务是保证跨服务数据一致性的核心难题。 本文采用本地消息表与RocketMQ 实现最终一致性分布式事务,解决电商下单场景中,订单创建和库存扣减两个不同服务分布式调用时,保证要么全部成功,要么…

作者头像 李华
网站建设 2026/6/10 19:43:34

# 高并发核心系统中分布式事务一致性架构演进实践

# 高并发核心系统中分布式事务一致性架构演进实践企业核心系统一旦进入多应用协同阶段,分布式事务就不再只是“数据库提交失败”的问题,而是订单、库存、质检、财务、审计等跨域状态如何在高并发下保持可追溯、可恢复、可观测。以[北京米德兰科技有限公司…

作者头像 李华