【Datawhale AI 夏令营2024】药效预测(2)
数据的特征工程
把序列特征的问题转化为表格问题的方法,并在表格数据上做特征工程。
- 处理类别型变量
如何知道一个变量是类别型的呢,只需看下其值的分布,或者唯一值的个数
df.gene_target_symbol_name.nunique()
df.gene_target_symbol_name.value_counts()
这段代码
df.gene_target_symbol_name.nunique()
是用来计算 DataFrame(或者 Pandas Series)中gene_target_symbol_name
这一列(或者属性)中唯一值的数量。具体来说:
df
是一个 Pandas DataFrame。gene_target_symbol_name
是 DataFrame 中的一列,可能存储了基因或者目标符号的名称。.nunique()
是 Pandas 提供的一个方法,用来计算给定列中唯一值的数量,即不同的基因或目标符号的名称的个数。
如果相较于数据的总行数很少,那么其很可能就是类别变量了,比如gene_target_symbol_name。此时,我们可以使用get_dummie函数来实现one-hot特征的构造
# 如果有40个类别,那么会产生40列,如果第i行属于第j个类别,那么第j列第i行就是1,否则为0
df_gene_target_symbol_name = pd.get_dummies(df.gene_target_symbol_name)
df_gene_target_symbol_name.columns = [
f"feat_gene_target_symbol_name_{c}" for c in df_gene_target_symbol_name.columns
]
- 可能的时间特征构造
siRNA_duplex_id的编码方式很有意思,其格式为AD-1810676.1
siRNA_duplex_id_values = df.siRNA_duplex_id.str[3:-2].str.strip(".").astype("int")
df.siRNA_duplex_id
: 假设df
是一个 Pandas DataFrame,.siRNA_duplex_id
是 DataFrame 中的一列,可能存储了 siRNA (小干扰RNA)的双链ID。.str[3:-2]
: 对siRNA_duplex_id
这一列进行字符串操作,从第3个字符到倒数第2个字符(不包括倒数第2个字符),提取子字符串。.str.strip(".")
: 对上一步提取的子字符串进行操作,去除字符串两端的点号"."
。.astype("int")
: 将上一步处理后的字符串转换为整数类型。
- 包含某些单词
df_cell_line_donor = pd.get_dummies(df.cell_line_donor)
df_cell_line_donor.columns = [
f"feat_cell_line_donor_{c}" for c in df_cell_line_donor.columns
]
# 包含Hepatocytes
df_cell_line_donor["feat_cell_line_donor_hepatocytes"] = (
(df.cell_line_donor.str.contains("Hepatocytes")).fillna(False).astype("int")
)
# 包含Cells
df_cell_line_donor["feat_cell_line_donor_cells"] = (
df.cell_line_donor.str.contains("Cells").fillna(False).astype("int")
)
df_cell_line_donor.columns = [...]
: 将生成的独热编码列的列名重新命名,以便后续识别和使用。列名的命名规则是在原始列名前加上 “feat_cell_line_donor_”。
(df.cell_line_donor.str.contains("Hepatocytes"))
: 使用.str.contains("Hepatocytes")
方法判断cell_line_donor
列中的每个字符串是否包含子字符串 “Hepatocytes”。返回一个布尔类型的 Series。
.fillna(False)
: 对于可能存在缺失值的情况,用 False 填充缺失值。.astype("int")
: 将布尔类型的 Series 转换为整数类型(0 或 1),表示该行是否包含 “Hepatocytes”。
df.cell_line_donor.str.contains("Cells")
: 同样使用.str.contains("Cells")
方法判断cell_line_donor
列中的每个字符串是否包含子字符串 “Cells”。.fillna(False)
: 对于可能存在缺失值的情况,用 False 填充缺失值。.astype("int")
: 将布尔类型的 Series 转换为整数类型(0 或 1),表示该行是否包含 “Cells”。
- 根据序列模式提取特征
def siRNA_feat_builder(s: pd.Series, anti: bool = False):
name = "anti" if anti else "sense"
df = s.to_frame()
# 序列长度
df[f"feat_siRNA_{name}_seq_len"] = s.str.len()
for pos in [0, -1]:
for c in list("AUGC"):
# 第一个和最后一个是否是A/U/G/C
df[f"feat_siRNA_{name}_seq_{c}_{'front' if pos == 0 else 'back'}"] = (
s.str[pos] == c
)
# 是否以某一对碱基开头和某一对碱基结尾
df[f"feat_siRNA_{name}_seq_pattern_1"] = s.str.startswith("AA") & s.str.endswith(
"UU"
)
df[f"feat_siRNA_{name}_seq_pattern_2"] = s.str.startswith("GA") & s.str.endswith(
"UU"
)
df[f"feat_siRNA_{name}_seq_pattern_3"] = s.str.startswith("CA") & s.str.endswith(
"UU"
)
df[f"feat_siRNA_{name}_seq_pattern_4"] = s.str.startswith("UA") & s.str.endswith(
"UU"
)
df[f"feat_siRNA_{name}_seq_pattern_5"] = s.str.startswith("UU") & s.str.endswith(
"AA"
)
df[f"feat_siRNA_{name}_seq_pattern_6"] = s.str.startswith("UU") & s.str.endswith(
"GA"
)
df[f"feat_siRNA_{name}_seq_pattern_7"] = s.str.startswith("UU") & s.str.endswith(
"CA"
)
df[f"feat_siRNA_{name}_seq_pattern_8"] = s.str.startswith("UU") & s.str.endswith(
"UA"
)
# 第二位和倒数第二位是否为A
df[f"feat_siRNA_{name}_seq_pattern_9"] = s.str[1] == "A"
df[f"feat_siRNA_{name}_seq_pattern_10"] = s.str[-2] == "A"
# GC占整体长度的比例
df[f"feat_siRNA_{name}_seq_pattern_GC_frac"] = (
s.str.contains("G") + s.str.contains("C")
) / s.str.len()
return df.iloc[:, 1:]
返回结果:
return df.iloc[:, 1:]
返回处理后的 DataFrame
df
,从第二列开始返回,因为第一列是原始的siRNA序列。
基于lightgbm的baseline
# 划分训练集和测试集
train_data = lgb.Dataset(X_train, label=y_train)
test_data = lgb.Dataset(X_test, label=y_test, reference=train_data)
def print_validation_result(env):
result = env.evaluation_result_list[-1]
print(f"[{env.iteration}] {result[1]}'s {result[0]}: {result[2]}")
# 参数设置
params = {
"boosting_type": "gbdt",
"objective": "regression",
"metric": "root_mean_squared_error",
"max_depth": 7,
"learning_rate": 0.02,
"verbose": 0,
}
#模型训练
gbm = lgb.train(
params,
train_data,
num_boost_round=15000,
valid_sets=[test_data],
callbacks=[print_validation_result],
)