特征工程技巧—Bert

前段时间在参加比赛,发现有一些比赛上公开的代码,其中的数据预处理步骤值得我们参考。

平常我们见到的都是数据预处理,现在我们来讲一下特征工程跟数据预处理的区别。

  1. 数据预处理是指对原始数据进行清洗、转换、缩放等操作,以便为后续的建模或分析任务做准备。这包括处理缺失值、异常值、重复值,以及对数据进行归一化、标准化等操作,使数据适合模型处理。

  2. 特征工程则更侧重于从原始数据中提取、构建或转换特征,以提高模型的性能。这包括特征选择、特征抽取、特征转换等过程。在特征工程中,可以创建新的特征、组合现有特征、进行降维等操作,以便使模型更好地捕捉数据中的模式和关系

 训练集

测试集

注:这个代码也可以用在自己的工程项目中,还是比较不错的!也是目前在Kaggle社区里公开代码分数比较高的一个单模型。

1、安装库

!pip install rdkit
!pip install -U /kaggle/input/lightning-2-2-1/lightning-2.2.1-py3-none-any.whl

RDKit:是一个用于化学信息学和药物发现的开源软件包。它提供了丰富的化学信息处理功能和工具,用于分子建模、药物设计、化合物筛选等领域。

PyTorch Lightning:于简化和加速深度学习项目开发的库。它构建在PyTorch之上,提供了高级抽象和预定义模板,使得构建、训练和调试神经网络模型变得更加简单和高效。

2、导入所需的Python库和模块

from pathlib import Path
import numpy as np
import polars as pl
from sklearn.model_selection import train_test_split
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import Dataset, DataLoader
from torchmetrics import AveragePrecision
import lightning as L
from lightning.pytorch.callbacks import (EarlyStopping,ModelCheckpoint,TQDMProgressBar,
)
from transformers import AutoConfig, AutoTokenizer, AutoModel, DataCollatorWithPadding
import datasets
from rdkit import Chem

 导入数据处理、深度学习、Lightning等相关模块

3、配置超参数 

DEBUG = False
NORMALIZE = True
N_ROWS = 180_000_000
assert N_ROWS is None or N_ROWS % 3 == 0
if DEBUG:N_SAMPLES = 10_000
else:N_SAMPLES = 2_000_000
PROTEIN_NAMES = ["BRD4", "HSA", "sEH"]
data_dir = Path("/kaggle/input/leash-BELKA")
model_name = "DeepChem/ChemBERTa-10M-MTR"
batch_size = 256
trainer_params = {"max_epochs": 5,"enable_progress_bar": True,"accelerator": "auto","precision": "16-mixed","gradient_clip_val": None,"accumulate_grad_batches": 1,"devices": [0],
}
  1. DEBUG = False:设置调试标志,表示是否处于调试模式。

  2. NORMALIZE = True:设置规范化标志,表示是否对化学分子的SMILES表示进行规范化处理。

  3. N_ROWS = 180_000_000:设置处理的最大行数,这里指定了处理的数据集的行数上限。

  4. assert N_ROWS is None or N_ROWS % 3 == 0:使用assert语句确保数据行数是3的倍数,因为后面的代码根据这个假设进行数据处理。

  5. if DEBUG::检查是否处于调试模式。

  6. N_SAMPLES = 10_000 if DEBUG else 2_000_000:根据是否处于调试模式,设置样本数目。

  7. PROTEIN_NAMES = ["BRD4", "HSA", "sEH"]:定义了需要处理的蛋白质名称列表。

  8. data_dir = Path("/kaggle/input/leash-BELKA"):指定数据存储的目录路径。

  9. model_name = "DeepChem/ChemBERTa-10M-MTR":指定使用的预训练BERT模型的名称。

  10. batch_size = 256:指定训练中使用的批量大小。

  11. trainer_params:定义了训练器的参数,包括最大训练周期数、是否启用进度条、使用的加速器、精度、梯度裁剪值、累积梯度批次数以及使用的设备。

4、准备数据集

df = pl.read_parquet(Path(data_dir, "train.parquet"),columns=["molecule_smiles", "protein_name", "binds"],n_rows=N_ROWS,
)
test_df = pl.read_parquet(Path(data_dir, "test.parquet"),columns=["molecule_smiles"],n_rows=10000 if DEBUG else None,
)
df.head()

这里读取了训练数据和测试数据,并显示了训练数据的前几行。

dfs = []
for i, protein_name in enumerate(PROTEIN_NAMES):sub_df = df[i::3]sub_df = sub_df.rename({"binds": protein_name})if i == 0:dfs.append(sub_df.drop(["id", "protein_name"]))else:dfs.append(sub_df[[protein_name]])
df = pl.concat(dfs, how="horizontal")
df = df.sample(n=N_SAMPLES)
print(df.head())
print(df[PROTEIN_NAMES].sum())
  1. dfs = []:初始化一个空列表,用于存储每个蛋白质的子数据框。

  2. for i, protein_name in enumerate(PROTEIN_NAMES)::使用enumerate函数遍历PROTEIN_NAMES列表中的每个蛋白质名称,同时获取其对应的索引值i和名称protein_nameenumerate函数用于同时遍历一个可迭代对象(如列表、元组)中的元素及其对应的索引。

  3. sub_df = df[i::3]:根据索引i对原始数据框df进行切片操作,每隔3行取出一个子数据框。这样可以将原始数据按照每个蛋白质分成3份,分别处理。

  4. sub_df = sub_df.rename({"binds": protein_name}):将子数据框的列名binds重命名为当前蛋白质的名称,以便后续处理和识别。

  5. if i == 0::如果是第一个蛋白质,则将子数据框中的"id"和"protein_name"列删除,并将处理后的子数据框添加到dfs列表中。

  6. else::如果不是第一个蛋白质,则只保留当前蛋白质的绑定情况数据,并将处理后的子数据框添加到dfs列表中。

  7. df = pl.concat(dfs, how="horizontal"):将所有处理后的子数据框按水平方向拼接成一个新的数据框df

  8. df = df.sample(n=N_SAMPLES):从新的数据框df中随机抽样N_SAMPLES个样本。

  9. print(df.head()):打印新数据框df的前几行。

  10. print(df[PROTEIN_NAMES].sum()):计算新数据框df中每个蛋白质的绑定情况,并打印出来。

def normalize(x):mol = Chem.MolFromSmiles(x)smiles = Chem.MolToSmiles(mol, canonical=True, isomericSmiles=False)return smilesif NORMALIZE:df = df.with_columns(pl.col("molecule_smiles").map_elements(normalize, return_dtype=pl.Utf8))test_df = test_df.with_columns(pl.col("molecule_smiles").map_elements(normalize, return_dtype=pl.Utf8))

这部分代码定义了一个函数normalize(),用于对分子结构的SMILES表示进行规范化。如果NORMALIZE为True,则对训练数据和测试数据中的分子SMILES进行规范化处理。

  1. normalize 函数:这个函数接受一个 SMILES 表示的分子作为输入,并返回规范化后的 SMILES 表示。在这里,它使用了 RDKit 包中的功能。Chem.MolFromSmiles() 将输入的 SMILES 字符串转换为 RDKit 的分子对象,然后 Chem.MolToSmiles() 将这个分子对象转换回 SMILES 字符串,使用了 canonical=True 参数确保生成的 SMILES 是规范化的,isomericSmiles=False 则确保不考虑分子的立体异构体。

  2. if NORMALIZE::这个条件语句检查一个名为 NORMALIZE 的变量是否为真。如果为真,就会对数据进行规范化操作。如果 NORMALIZE 是一个布尔值,这个条件通常会在前面被定义,以确定是否要进行规范化处理。

  3. df = df.with_columns(pl.col("molecule_smiles").map_elements(normalize, return_dtype=pl.Utf8)):这一行代码应该是 Pandas 或类似的数据处理库(比如 Dask 或 Modin)的语法。它将 DataFrame 中的 "molecule_smiles" 列中的每个元素都应用 normalize 函数进行规范化处理,然后将结果保存回原来的列中。这里使用了 map_elements() 函数,它是 Pandas 的 apply() 方法的替代,用于元素级别的操作。

  4. test_df = test_df.with_columns(pl.col("molecule_smiles").map_elements(normalize, return_dtype=pl.Utf8)):同上一行,只是这一行是对另一个 DataFrame test_df 执行同样的操作。

train_idx, val_idx = train_test_split(np.arange(len(df)), test_size=0.2)
train_df, val_df = df[train_idx], df[val_idx]
len(train_df), len(val_df)

这段代码将数据拆分为训练集和验证集,比例为80:20。
 

  1. train_test_split(np.arange(len(df)), test_size=0.2):这行代码使用了 train_test_split 函数来将索引数组 np.arange(len(df)) 分割成训练集和验证集的索引。参数 test_size=0.2 指定了验证集所占的比例,这里是20%。训练集和验证集的索引分别存储在 train_idxval_idx 中。

  2. train_df, val_df = df[train_idx], df[val_idx]:这行代码使用了 Pandas 或类似的库的索引功能,将原始 DataFrame df 中对应索引的行划分给训练集和验证集,分别存储在 train_dfval_df 中。

  3. len(train_df), len(val_df):这一行简单地打印出了训练集和验证集的长度,以确认它们的大小是否符合预期。

5、建立数据集

tokenizer = AutoTokenizer.from_pretrained(model_name)

这行代码根据给定的模型名称加载了相应的tokenizer,用于将文本数据转换成模型输入。

def tokenize(batch, tokenizer):output = tokenizer(batch["molecule_smiles"], truncation=True)return outputclass LMDataset(Dataset):def __init__(self, df, tokenizer, stage="train"):assert stage in ["train", "val", "test"]self.tokenizer = tokenizerself.stage = stagedf = (datasets.Dataset.from_pandas(df.to_pandas()).map(tokenize, batched=True, fn_kwargs={"tokenizer": self.tokenizer}).to_pandas())self.df = pl.from_pandas(df)def __len__(self):return len(self.df)def __getitem__(self, index):data = self._generate_data(index)data["label"] = self._generate_label(index)return data        def _generate_data(self, index):data = {"input_ids": np.array(self.df[index, "input_ids"]),"attention_mask": np.array(self.df[index, "attention_mask"]),}return datadef _generate_label(self, index):if self.stage == "test":return np.array([0, 0, 0])else:return self.df[index, PROTEIN_NAMES].to_numpy()[0]LMDataset(train_df[:100], tokenizer)[0]
  1. tokenize 函数:这是一个辅助函数,接受一个批次的数据和一个分词器(tokenizer),并对批次中的分子 SMILES 进行分词处理。在这里,使用了 Hugging Face Transformers 库提供的 tokenizer 对批次中的分子 SMILES 进行分词,设置了 truncation=True 以确保分词后的序列长度不超过指定的最大长度。

  2. LMDataset 类:这是一个自定义的 PyTorch Dataset 类,用于加载数据集。主要功能包括:

    • __init__ 方法:初始化数据集对象。接受一个 DataFrame df、一个分词器 tokenizer 和一个阶段 stage(默认为 "train")。在这个方法中,将输入的 DataFrame 转换为 PyTorch 的 Dataset 对象,并使用 map 方法对数据进行分词处理,得到包含分词结果的 DataFrame,并将其转换为 Polars 的 DataFrame。
    • __len__ 方法:返回数据集的长度,即数据集中样本的数量。
    • __getitem__ 方法:根据给定的索引 index 返回对应的样本数据和标签。在这里,调用了 _generate_data_generate_label 方法来生成数据和标签。
    • _generate_data 方法:根据给定的索引 index 生成数据。返回一个字典,包含 "input_ids" 和 "attention_mask"。
    • _generate_label 方法:根据给定的索引 index 生成标签。如果阶段为 "test",则返回一个全为 0 的数组;否则,根据索引获取对应的样本的标签值。
  3. LMDataset(train_df[:100], tokenizer)[0]:创建了一个 LMDataset 对象,并取出第一个样本的数据和标签。

class LBDataModule(L.LightningDataModule):def __init__(self, train_df, val_df, test_df, tokenizer):super().__init__()self.train_df = train_dfself.val_df = val_dfself.test_df = test_dfself.tokenizer = tokenizerdef _generate_dataset(self, stage):if stage == "train":df = self.train_dfelif stage == "val":df = self.val_dfelif stage == "test":df = self.test_dfelse:raise NotImplementedErrordataset = LMDataset(df, self.tokenizer, stage=stage)return datasetdef _generate_dataloader(self, stage):dataset = self._generate_dataset(stage)if stage == "train":shuffle=Truedrop_last=Trueelse:shuffle=Falsedrop_last=Falsereturn DataLoader(dataset,batch_size=batch_size,shuffle=shuffle,drop_last=drop_last,pin_memory=True,collate_fn=DataCollatorWithPadding(self.tokenizer),)def train_dataloader(self):return self._generate_dataloader("train")def val_dataloader(self):return self._generate_dataloader("val")def test_dataloader(self):return self._generate_dataloader("test")datamodule = LBDataModule(train_df, val_df, test_df, tokenizer)

  1. __init__ 方法:初始化 DataModule 类,接受训练集、验证集、测试集的 DataFrame 数据以及一个分词器 tokenizer。在这个方法中,将输入的数据和分词器保存到类的属性中。

  2. _generate_dataset 方法:根据给定的阶段("train"、"val" 或 "test"),生成对应阶段的数据集对象。根据阶段选择对应的 DataFrame 数据,然后使用 LMDataset 类创建相应的数据集对象,并传入对应的 DataFrame 和分词器。

  3. _generate_dataloader 方法:根据给定的阶段("train"、"val" 或 "test"),生成对应阶段的数据加载器对象。调用 _generate_dataset 方法生成对应阶段的数据集对象,然后根据阶段设定加载器的参数,如是否打乱数据、是否丢弃最后一个不完整的批次等,最后使用 PyTorch 的 DataLoader 类创建数据加载器对象。

  4. train_dataloaderval_dataloadertest_dataloader 方法:分别返回训练、验证和测试阶段的数据加载器对象,通过调用 _generate_dataloader 方法实现。

  5. datamodule 实例:使用给定的训练集、验证集、测试集和分词器创建了一个 DataModule 对象。

6、建立模型

class LMModel(nn.Module):def __init__(self, model_name):super().__init__()self.config = AutoConfig.from_pretrained(model_name, num_labels=3)self.lm = AutoModel.from_pretrained(model_name, add_pooling_layer=False)self.dropout = nn.Dropout(self.config.hidden_dropout_prob)self.classifier = nn.Linear(self.config.hidden_size, self.config.num_labels)self.loss_fn = nn.BCEWithLogitsLoss(reduction="mean")def forward(self, batch):last_hidden_state = self.lm(batch["input_ids"],attention_mask=batch["attention_mask"],).last_hidden_statelogits = self.classifier(self.dropout(last_hidden_state[:, 0]))return {"logits": logits,}def calculate_loss(self, batch):output = self.forward(batch)loss = self.loss_fn(output["logits"], batch["labels"].float())output["loss"] = lossreturn outputLMModel(model_name)

  1. class LMModel(nn.Module):: 这是定义了一个名为 LMModel 的类,它继承自 nn.Module,表示这个类是一个 PyTorch 模型。

  2. def __init__(self, model_name):: 这是 LMModel 类的初始化函数,接受一个参数 model_name,表示要使用的预训练语言模型的名称。

  3. self.config = AutoConfig.from_pretrained(model_name, num_labels=3): 使用 Hugging Face 的 AutoConfig 类从预训练模型 model_name 中加载配置。num_labels=3 指定了模型的输出类别数量为 3。

  4. self.lm = AutoModel.from_pretrained(model_name, add_pooling_layer=False): 使用 Hugging Face 的 AutoModel 类从预训练模型 model_name 中加载模型,add_pooling_layer=False 表示不添加池化层。

  5. self.dropout = nn.Dropout(self.config.hidden_dropout_prob): 创建了一个 Dropout 层,用于在训练过程中随机将一部分神经元的输出置为零,以防止过拟合。

  6. self.classifier = nn.Linear(self.config.hidden_size, self.config.num_labels): 创建了一个线性层,将语言模型的隐藏状态映射到指定数量的标签上。

  7. self.loss_fn = nn.BCEWithLogitsLoss(reduction="mean"): 创建了一个二元交叉熵损失函数,用于计算模型的损失。这里使用 BCEWithLogitsLoss 是因为多标签分类问题中每个标签都是独立的,所以对每个标签使用二元交叉熵损失。

  8. def forward(self, batch):: 这是模型的前向传播函数,接受一个批次的输入数据 batch,包括输入的标记化的文本和注意力掩码。

  9. last_hidden_state = self.lm(: 使用加载的语言模型处理输入数据,得到最后一层的隐藏状态。

  10. logits = self.classifier(: 将最后一层隐藏状态经过线性层映射到标签空间,得到每个标签的预测概率。

  11. def calculate_loss(self, batch):: 这是计算模型损失的函数,接受一个批次的输入数据 batch

  12. output = self.forward(batch): 调用前向传播函数得到模型的输出结果。

  13. loss = self.loss_fn(output["logits"], batch["labels"].float()): 使用损失函数计算模型的损失,将预测的概率和真实标签进行比较。

  14. output["loss"] = loss: 将计算得到的损失保存在输出字典中。

class LBModelModule(L.LightningModule):def __init__(self, model_name):super().__init__()self.model = LMModel(model_name)self.map = AveragePrecision(task="binary")def forward(self, batch):return self.model(batch)def calculate_loss(self, batch, batch_idx):return self.model.calculate_loss(batch)def training_step(self, batch, batch_idx):ret = self.calculate_loss(batch, batch_idx)self.log("train_loss", ret["loss"], on_step=True, on_epoch=True, prog_bar=True, sync_dist=True)return ret["loss"]def validation_step(self, batch, batch_idx):ret = self.calculate_loss(batch, batch_idx)self.log("val_loss", ret["loss"], on_step=False, on_epoch=True, prog_bar=True, sync_dist=True)self.map.update(F.sigmoid(ret["logits"]), batch["labels"].long())def on_validation_epoch_end(self):val_map = self.map.compute()self.log("val_map", val_map, on_step=False, on_epoch=True, prog_bar=True, sync_dist=True)self.map.reset()def predict_step(self, batch, batch_idx, dataloader_idx=0):logits = self.forward(batch)["logits"]probs = F.sigmoid(logits)return probsdef configure_optimizers(self):optimizer = torch.optim.Adam(self.parameters(), lr=0.0001)return {"optimizer": optimizer,}modelmodule = LBModelModule(model_name)

  1. class LBModelModule(L.LightningModule):: 这是定义了一个名为 LBModelModule 的类,它继承自 PyTorch Lightning 的 LightningModule 类,表示这个类是一个 Lightning 模块。

  2. def __init__(self, model_name):: 这是 LBModelModule 类的初始化函数,接受一个参数 model_name,表示要使用的语言模型的名称。

  3. self.model = LMModel(model_name): 创建了一个 LMModel 类的实例作为模型的成员变量,用于处理输入数据并进行预测。

  4. self.map = AveragePrecision(task="binary"): 创建了一个用于计算平均精度的 AveragePrecision 类的实例。

  5. def forward(self, batch):: 这是模型的前向传播函数,接受一个批次的输入数据 batch,并调用模型的前向传播函数。

  6. def calculate_loss(self, batch, batch_idx):: 这是计算损失的函数,接受一个批次的输入数据 batch 和批次的索引 batch_idx

  7. def training_step(self, batch, batch_idx):: 这是训练步骤函数,在每个训练步骤中计算损失并更新训练日志。

  8. def validation_step(self, batch, batch_idx):: 这是验证步骤函数,在每个验证步骤中计算损失并更新验证日志。

  9. def on_validation_epoch_end(self):: 这是在每个验证轮结束后调用的函数,在这里计算验证集上的平均精度并重置计算器。

  10. def predict_step(self, batch, batch_idx, dataloader_idx=0):: 这是预测步骤函数,用于在每个预测步骤中生成预测概率。

  11. def configure_optimizers(self):: 这是配置优化器的函数,返回一个优化器的配置字典,这里使用 Adam 优化器。

7、训练

checkpoint_callback = ModelCheckpoint(filename=f"model-{{val_map:.4f}}",save_weights_only=True,monitor="val_map",mode="max",dirpath="/kaggle/working",save_top_k=1,verbose=1,
)
early_stop_callback = EarlyStopping(monitor="val_map", mode="max", patience=3)
progress_bar_callback = TQDMProgressBar(refresh_rate=1)
callbacks = [checkpoint_callback,early_stop_callback,progress_bar_callback,
]
  1. ModelCheckpoint: 这个回调函数用于在训练过程中保存模型的检查点,以便在训练结束后选择最佳的模型参数。参数解释如下:

    • filename: 模型文件名的格式,可以使用格式化字符串指定变量,这里使用了验证集的平均精度作为文件名。
    • save_weights_only: 设置为 True 表示只保存模型的权重。
    • monitor: 监控的指标,这里选择了验证集的平均精度。
    • mode: 模型选择的模式,这里选择了最大化验证集的平均精度。
    • dirpath: 模型保存的目录路径。
    • save_top_k: 保存最佳模型的数量,这里设置为 1。
    • verbose: 控制是否在保存模型时输出信息,设置为 1 表示输出信息。
  2. EarlyStopping: 这个回调函数用于在验证集指标停止提升时提前停止训练,以防止过拟合。参数解释如下:

    • monitor: 监控的指标,这里同样选择了验证集的平均精度。
    • mode: 模型选择的模式,这里同样选择了最大化验证集的平均精度。
    • patience: 容忍多少个 epoch 内指标没有提升。
  3. TQDMProgressBar: 这个回调函数用于在训练过程中显示进度条,以便实时监控训练进度。参数 refresh_rate 控制刷新频率,即进度条更新的时间间隔。

trainer = L.Trainer(callbacks=callbacks, **trainer_params)
trainer.fit(modelmodule, datamodule)
  1. trainer = L.Trainer(callbacks=callbacks, **trainer_params): 这行代码创建了一个 Lightning Trainer 对象,并设置了回调函数和训练参数。参数解释如下:

    • callbacks: 指定了训练过程中要使用的回调函数列表,这里使用了之前定义的 callbacks 列表,包括模型检查点、提前停止和进度条回调。
    • **trainer_params: 使用 ** 语法将字典 trainer_params 中的所有键值对作为参数传递给 Trainer 对象,这里包括了一系列训练参数,如最大 epoch 数、设备选择、精度设置等。
  2. trainer.fit(modelmodule, datamodule): 这行代码使用创建的 Trainer 对象开始了模型的训练过程。参数解释如下:

    • modelmodule: 指定了要训练的 Lightning 模型,这里是之前定义的 LBModelModule 对象。
    • datamodule: 指定了训练数据的 datamodule,这里是之前定义的 LBDataModule 对象,其中包含了训练、验证和测试数据集的处理逻辑。

8、推理

test_df = pl.read_parquet(Path(data_dir, "test.parquet"),columns=["molecule_smiles"],n_rows=10000 if DEBUG else None,
)
  • pl.read_parquet: 这是 PyTorch Lightning 库中的一个函数,用于从 Parquet 格式的文件中读取数据。Parquet 是一种列式存储格式,常用于大规模数据存储和处理。
  • Path(data_dir, "test.parquet"): 这是指定要读取的 Parquet 文件的路径。data_dir 是之前定义的数据目录路径,"test.parquet" 是要读取的文件名。
  • columns=["molecule_smiles"]: 这是指定要读取的列名,即从 Parquet 文件中选择的列。在这里,只选择了名为 "molecule_smiles" 的列。
  • n_rows=10000 if DEBUG else None: 这是指定要读取的行数。如果 DEBUG 变量为 True,则只读取文件的前 10000 行;否则,读取整个文件。这是一种常用的技术,用于在开发和调试阶段快速处理较小的数据样本,以加快开发速度。
working_dir = Path("/kaggle/working")
model_paths = working_dir.glob("*.ckpt")
test_dataloader = datamodule.test_dataloader()
for model_path in model_paths:print(model_path)modelmodule = LBModelModule.load_from_checkpoint(checkpoint_path=model_path,model_name=model_name,)predictions = trainer.predict(modelmodule, test_dataloader)predictions = torch.cat(predictions).numpy()pred_dfs = []for i, protein_name in enumerate(PROTEIN_NAMES):pred_dfs.append(test_df.with_columns(pl.lit(protein_name).alias("protein_name"),pl.lit(predictions[:, i]).alias("binds"),))pred_df = pl.concat(pred_dfs)submit_df = (pl.read_parquet(Path(data_dir, "test.parquet"), columns=["id", "molecule_smiles", "protein_name"]).join(pred_df, on=["molecule_smiles", "protein_name"], how="left").select(["id", "binds"]).sort("id"))submit_df.write_csv(Path(working_dir, f"submission_{model_path.stem}.csv"))
  1. 定义了一个工作目录 working_dir,这是保存模型和生成提交文件的目录。
  2. 使用 glob 方法获取工作目录中的所有模型文件的路径,并存储在 model_paths 变量中。
  3. 获取测试数据的数据加载器 test_dataloader
  4. 遍历模型文件路径列表 model_paths
  5. 加载每个模型并进行预测。首先,使用 LBModelModule.load_from_checkpoint 方法加载模型,并传入模型文件路径和模型名称。然后使用 trainer.predict 方法对测试数据进行预测,得到预测结果。
  6. 将预测结果与相应的蛋白质名称关联,并将结果存储在 pred_df 中。
  7. 读取测试数据的 Parquet 文件,并选择需要的列("id"、"molecule_smiles" 和 "protein_name")。
  8. 将预测结果与测试数据合并,并只保留 "id" 和 "binds" 列。
  9. 将合并后的结果按照 "id" 进行排序。
  10. 将生成的提交文件写入 CSV 格式,并根据当前模型文件的名称进行命名,存储在工作目录中。

9、集成

sub_files = list(working_dir.glob("submission_*.csv"))
sub_files

 sub_files 是一个列表,包含工作目录中所有以 "submission_" 开头且以 ".csv" 结尾的文件的路径。这些文件名可能会因为模型路径的不同而有所变化,但它们都是模型预测结果的提交文件。

sub_dfs = []
for sub_file in sub_files:sub_dfs.append(pl.read_csv(sub_file))
submit_df = (pl.concat(sub_dfs).group_by("id").agg(pl.col("binds").mean()).sort("id")
)
  1. 循环遍历 sub_files 中的每个文件路径。
  2. 对于每个文件,使用 pl.read_csv(sub_file) 读取 CSV 文件并将其添加到 sub_dfs 列表中。
  3. 使用 pl.concat(sub_dfs) 将所有 DataFrame 连接成一个大的 DataFrame。
  4. 使用 group_by("id") 将数据按照 "id" 列进行分组。
  5. 使用 .agg(pl.col("binds").mean()) 对每个分组计算 "binds" 列的平均值。
  6. 最后使用 .sort("id") 按照 "id" 列进行排序。
!rm -fr *

 这是一个Unix/Linux命令,用于删除当前目录下的所有文件和文件夹。具体地说:

  • rm 是 remove 的缩写,用于删除文件或目录。
  • -fr 是两个选项的结合:
    • -f 表示强制删除,即不会提示确认。
    • -r 表示递归删除,即删除目录及其下所有文件和子目录。
  • * 是通配符,代表当前目录下的所有文件和文件夹。

因此,这个命令的意思是:删除当前目录下的所有文件和文件夹,且不会提示确认。

submit_df.write_csv(Path(working_dir, "submission.csv"))
  • submit_df 是一个 DataFrame,其中包含了提交的数据。
  • write_csv 是一个方法,用于将 DataFrame 写入到 CSV 格式的文件中。
  • Path(working_dir, "submission.csv") 创建了一个路径对象,指定了要写入的文件路径,这个路径对象表示当前工作目录下的 "submission.csv" 文件。

 10、改进方向

  • 寻找最佳的交叉验证策略
  • 增加数据
  • 使用更多的特征
  • 更大的模型
  • 调整超参数
  • 集成模型

源代码:Leash Bio: ChemBERTa with all data (kaggle.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/339993.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue3状态管理,pinia的使用

​​​​​​​状态管理 我们知道组件与组件之间可以传递信息,那么我们就可以将一个信息作为组件的独立状态(例如,单个组件的颜色)或者共有状态(例如,多个组件是否显示)在组件之传递&#xff0c…

大容量异步电机直接转矩(DTC)控制matlab仿真

微❤关注“电气仔推送”获得资料(专享优惠) DTC简介 直接转矩控制的基本思想就是利用逆变器所产生的空间电压矢量来控制定子磁链的旋转速度,通过控制定子磁链的走停来改变定子磁链的平均旋转速度的大小,从而改变磁通角的大小进而…

【应用层】域名系统DNS

目录 1、互联网的域名结构 2、域名服务器 域名系统 DNS (Domain Name System) 是互联网使用的命名系统,用来把便于人们使用的机器名字转换为 IP 地址,域名系统其实就是名字系统。 互联网的域名系统 DNS 被设计成为一个联机分布式数据库系统&#xff0c…

使用 zxing 生成二维码以及条形码

需求背景 前期在做项目的时候,有一个需求是说要生成一张条形码,并且呢将条形码插入到 excel 中去,但是之前一直没有搞过找个条形码或者是二维码,最后是做出来了,这里呢就先看看怎么生成,后面再抽时间来写写…

模拟算法专题

特点: 思路比较简单, 主要考察代码能力 模拟算法流程(一定要在演草纸上过一遍流程)把流程转化为代码 优化: 一般是通过找规律 一. 替换所有问号 答案 二. 提莫攻击 答案 三. Z字形变换 答案 四. 外观数列 答案 五. 数青蛙 答案

Accelerate 笔记:保存与加载文件

保存和加载模型、优化器、随机数生成器和 GradScaler 使用 save_state() 将上述所有内容保存到一个文件夹位置使用 load_state() 加载之前通过 save_state() 保存的状态通过使用 register_for_checkpointing(),可以注册自定义对象以便自动从前两个函数中存储或加载 …

css-Ant-Menu 导航菜单更改为左侧列表行选中

1.Ant-Menu导航菜单 导航菜单是一个网站的灵魂&#xff0c;用户依赖导航在各个页面中进行跳转。一般分为顶部导航和侧边导航&#xff0c;顶部导航提供全局性的类目和功能&#xff0c;侧边导航提供多级结构来收纳和排列网站架构。 2.具体代码 html <!-- 左侧切换 --><…

每日一练——分糖果2

1103. 分糖果 II - 力扣&#xff08;LeetCode&#xff09; /*** Note: The returned array must be malloced, assume caller calls free().*/ int* distributeCandies(int candies, int num_people, int* returnSize) {int num 0;int* arr (int*)malloc(sizeof(int)*num_peo…

第100+9步 ChatGPT文献复现:ARIMA预测百日咳

基于WIN10的64位系统演示 一、写在前面 我们来继续换一篇文章来学习学习&#xff1a; 《BMC Public Health》杂志的2022年一篇题目为《ARIMA and ARIMA-ERNN models for prediction of pertussis incidence in mainland China from 2004 to 2021》文章的模拟数据做案例。 这…

Golang TCP网络编程

文章目录 网络编程介绍TCP网络编程服务器监听客户端连接服务器服务端获取连接向连接中写入数据从连接中读取数据关闭连接/监听器 简易的TCP回声服务器效果展示服务端处理逻辑客户端处理逻辑 网络编程介绍 网络编程介绍 网络编程是指通过计算机网络实现程序间通信的一种编程技术…

最小二乘法算法(个人总结版)

最小二乘法&#xff08;Least Squares Method&#xff09;是一种通过最小化误差平方和来拟合数据的回归分析方法。它被广泛应用于线性回归、多元回归以及其他数据拟合问题中。以下是详细的教程&#xff0c;涵盖基本概念、数学推导、具体步骤和实现代码。 1. 最小二乘法基本概念…

网络网络层之(6)ICMPv4协议

网络网络层之(6)ICMPv4协议 Author: Once Day Date: 2024年6月2日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章可参考专栏: 通信网络技术_Once-Day的博客-CS…

基于java的CRM客户关系管理系统(六)

目录 5.3 表现层设计 5.3.1 模型层&#xff08;M&#xff09; 5.3.2 视图层&#xff08;V&#xff09; 5.3.3 控制层&#xff08;C&#xff09; 5.4 系统主要功能模块的实现 5.4.1 登录功能的实现 5.4.2 客户管理的实现 5.5 本章小结 参考文献 前面内容请移步 基于java…

2.2 OpenCV随手简记(三)

图像的阈值处理定义 &#xff1a;将图像转化为二值图像&#xff08;黑白图&#xff09;, 也可以用于彩色图形&#xff0c;达到夸张的效果 目的&#xff1a;是用来提取图像中的目标物体&#xff0c;将背景和噪声区分开&#xff08;可以近似的认为除了目标全是噪声&#xff09;。…

Java进阶学习笔记36——算法

什么是算法&#xff1f; 解决某个实际问题的过程和方法。 1&#xff09;导航&#xff1b; 2&#xff09;滴滴打车&#xff1b; 3&#xff09;抖音&#xff1b; 不同的算法&#xff0c;效率高、性能好&#xff01; 在Java中&#xff0c;代码已经帮我们写好了&#xff0c;但为…

【Go语言精进之路】构建高效Go程序:零值可用、使用复合字面值作为初值构造器

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 引言一、深入理解并利用零值提升代码质量1.1 深入Go类型零值原理1.2 零值可用性的实践与优势1.2.1 切片(Slice)的零值与动态扩展1.2.2 Map的零值与安全访问1.2.3 函数参数与零值 二、使用复合字面值作为初值构造器2.1 结构体…

C语言 链表经典OJ题

链表经典OJ题 移除链表元素链表的中间节点反转链表合并两个有序链表分割链表 移除链表元素 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&#xff1a;head […

iOS18新功能大爆料,打破常规,全面升级,这些变化不容错过!

众所周知&#xff0c;苹果 iOS 操作系统近年来都没有发生重大变化&#xff0c;主要是添加小部件、锁屏编辑和手机屏幕编辑等功能&#xff0c;再加上bug偏多&#xff0c;以至于越来越多iPhone用户不愿意再升级系统了。这一点&#xff0c;从 iOS 17 明显降低的安装率中就能看出一…

Linux配置java,maven,marshalsec环境

文章目录 一. Linux配置java环境1.下载jdk文件2.解压tar.gz文件3.设置java环境变量4.验证是否成功 二. Linux配置maven环境1.下载压缩包2.解压tar.gz3. 配置环境变量 三. Linux配置marshalsec环境 一. Linux配置java环境 1.下载jdk文件 mkdir /opt/javawget https://repo.hua…

Mixly 开启WIFI AP UDP收发数据

一、开发环境 软件&#xff1a;Mixly 2.0在线版 硬件&#xff1a;ESP32-C3&#xff08;立创实战派&#xff09; 固件&#xff1a;ESP32C3 Generic(UART) 测试工工具&#xff1a;NetAssist V5.0.1 二、实现功能 ESP32开启WIFI AP&#xff0c;打印接入点IP地址&#xff0c;允许…