Обмен технологиями

[Практические боевые действия в области машинного обучения] Летний лагерь Datawhale: базовые примечания к интенсивному чтению 2

2024-07-08

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

# Летний лагерь AI # Datawhale # Летний лагерь

Помимо перекрестной проверки исходного базового уровня, существует также ключевой метод оптимизации, а именно разработка функций.

Способ оптимизации функций связан с тем, как мы повышаем точность прогнозирования модели. Разработка функций часто является той частью, с которой хорошо справляются люди с глубоким пониманием предметной области, потому что нам приходится думать о трансформации.

Помимо функций Smiles, есть множество функций, которые могут извлечь ценную информацию. Например, InChI состоит из ряда частей и предоставляет подробную информацию о молекулярной структуре.напримерНачальная идентификация, молекулярная формула, таблица соединений, количество атомов водорода, количество многовращающихся связей, стереохимическая информация, информация об изомере, информация о смеси или таутомере, информация о зарядовой и спиновой множественности и т. д.

Кроме того, если вы хотите повысить точность модели, неплохо было бы ее изменить.

Оптимизация функций

Извлечь молекулярную формулу

Из строки InChI мы видим, что молекулярная формула дана непосредственно в/C47H61N7O6S часть. Это означает, что молекула состоит из 47 атомов углерода, 61 атома водорода, 7 атомов азота, 6 атомов кислорода и 1 атома серы;

Рассчитать молекулярную массу

Молекулярную массу можно найти, умножив атомную массу каждого атома на его номер, а затем сложив их.

нравиться

  • Атомная масса углерода (С) составляет примерно 12,01 г/моль.

  • Атомная масса водорода (H) составляет примерно 1,008 г/моль.

  • Атомная масса азота (N) составляет примерно 14,01 г/моль.

  • Атомная масса кислорода (О) составляет примерно 16,00 г/моль.

  • Атомная масса серы (S) составляет примерно 32,07 г/моль.

Умножив на количества и сложив, мы получим молекулярную массу.

Атомный счет

Непосредственно посчитайте количество различных атомов и разложите их.

import pandas as pd
import re

atomic_masses = {
    'H': 1.008, 'He': 4.002602, 'Li': 6.94, 'Be': 9.0122, 'B': 10.81, 'C': 12.01,
    'N': 14.01, 'O': 16.00, 'F': 19.00, 'Ne': 20.180, 'Na': 22.990, 'Mg': 24.305,
    'Al': 26.982, 'Si': 28.085, 'P': 30.97, 'S': 32.07, 'Cl': 35.45, 'Ar': 39.95,
    'K': 39.10, 'Ca': 40.08, 'Sc': 44.956, 'Ti': 47.867, 'V': 50.942, 'Cr': 52.00,
    'Mn': 54.938, 'Fe': 55.845, 'Co': 58.933, 'Ni': 58.69, 'Cu': 63.55, 'Zn': 65.38
}

# 函数用于解析单个InChI字符串
def parse_inchi(row):
    inchi_str = row['InChI']
    formula = ''
    molecular_weight = 0
    element_counts = {}

    # 提取分子式
    formula_match = re.search(r"InChI=1S/([^/] )/c", inchi_str)
    if formula_match:
        formula = formula_match.group(1)

    # 计算分子量和原子计数
    for element, count in re.findall(r"([A-Z][a-z]*)([0-9]*)", formula):
        count = int(count) if count else 1
        element_mass = atomic_masses.get(element.upper(), 0)
        molecular_weight  = element_mass * count
        element_counts[element.upper()] = count

    return pd.Series({
        'Formula': formula,
        'MolecularWeight': molecular_weight,
        'ElementCounts': element_counts
    })

# 应用函数到DataFrame的每一行
train[['Formula', 'MolecularWeight', 'ElementCounts']] = train.apply(parse_inchi, axis=1)

# 定义存在的key
keys = ['H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na', 'Mg', 'Al', 'Si', 'P', 'S', 'Cl', 'Ar', 'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu', 'Zn']

# 创建一个空的DataFrame,列名为keys
df_expanded = pd.DataFrame({key: pd.Series() for key in keys})

# 遍历数据,填充DataFrame
for index, item in enumerate(train['ElementCounts'].values):
    for key in keys:
        # 将字典中的值填充到相应的列中
        df_expanded.at[index, key] = item.get(key, 0)

df_expanded = pd.DataFrame(df_expanded)

Модель слияния

Как упоминалось в прошлый раз, мы используем модель catboost. Мы не пробовали Lightgbm и xgboost. Вы можете запустить эти три модели последовательно, а затем усреднить результаты трех моделей для слияния (это также область, которую можно улучшить). ).

def cv_model(clf, train_x, train_y, test_x, clf_name, seed = 2023):
    folds = 5
    kf = KFold(n_splits=folds, shuffle=True, random_state=seed)
    oof = np.zeros(train_x.shape[0])
    test_predict = np.zeros(test_x.shape[0])
    cv_scores = []
    for i, (train_index, valid_index) in enumerate(kf.split(train_x, train_y)):
        print('************************************ {} ************************************'.format(str(i 1)))
        trn_x, trn_y, val_x, val_y = train_x.iloc[train_index], train_y[train_index], train_x.iloc[valid_index], train_y[valid_index]

        if clf_name == "lgb":
            train_matrix = clf.Dataset(trn_x, label=trn_y)
            valid_matrix = clf.Dataset(val_x, label=val_y)
            params = {
                'boosting_type': 'gbdt',
                'objective': 'binary',
                'min_child_weight': 6,
                'num_leaves': 2 ** 6,
                'lambda_l2': 10,
                'feature_fraction': 0.8,
                'bagging_fraction': 0.8,
                'bagging_freq': 4,
                'learning_rate': 0.35,
                'seed': 2024,
                'nthread' : 16,
                'verbose' : -1,
            }
            model = clf.train(params, train_matrix, 2000, valid_sets=[train_matrix, valid_matrix],
                              categorical_feature=[], verbose_eval=1000, early_stopping_rounds=100)
            val_pred = model.predict(val_x, num_iteration=model.best_iteration)
            test_pred = model.predict(test_x, num_iteration=model.best_iteration)

        if clf_name == "xgb":
            xgb_params = {
              'booster': 'gbtree', 
              'objective': 'binary:logistic',
              'num_class':3,
              'max_depth': 5,
              'lambda': 10,
              'subsample': 0.7,
              'colsample_bytree': 0.7,
              'colsample_bylevel': 0.7,
              'eta': 0.35,
              'tree_method': 'hist',
              'seed': 520,
              'nthread': 16
              }
            train_matrix = clf.DMatrix(trn_x , label=trn_y)
            valid_matrix = clf.DMatrix(val_x , label=val_y)
            test_matrix = clf.DMatrix(test_x)

            watchlist = [(train_matrix, 'train'),(valid_matrix, 'eval')]

            model = clf.train(xgb_params, train_matrix, num_boost_round=2000, evals=watchlist, verbose_eval=1000, early_stopping_rounds=100)
            val_pred  = model.predict(valid_matrix)
            test_pred = model.predict(test_matrix)

        if clf_name == "cat":
            params = {'learning_rate': 0.35, 'depth': 5, 'bootstrap_type':'Bernoulli','random_seed':2024,
                      'od_type': 'Iter', 'od_wait': 100, 'random_seed': 11, 'allow_writing_files': False}

            model = clf(iterations=2000, **params)
            model.fit(trn_x, trn_y, eval_set=(val_x, val_y),
                      metric_period=1000,
                      use_best_model=True, 
                      cat_features=[],
                      verbose=1)

            val_pred  = model.predict_proba(val_x)
            test_pred = model.predict_proba(test_x)

        oof[valid_index] = val_pred
        test_predict  = test_pred / kf.n_splits

        F1_score = f1_score(val_y, np.where(val_pred