Как выбрать характеристики, подходящие для сложных нелинейных моделей, и избежать перенастройки модели — это ключ к повышению точности прогнозирования финансовых задач.

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

В этом документе используется модель DoubleEnsemble для решения вышеуказанных проблем, двухэтапная модель интеграции. DoubleEnsemble — это инфраструктура двойной интеграции, использующая взвешивание выборки и выбор признаков. В частности, (1) взвешивание выборки: в соответствии с функцией потерь выборки делятся на простые для изучения образцы, трудные для изучения образцы и образцы шума, а трудным для изучения образцам присваивается больший вес. (2) Выбор функции: Нарушение соответствующей взаимосвязи между факторами и запасами, оценка производительности модели до и после нарушения. Если производительность модели значительно хуже, это указывает на то, что факторы важны, и наоборот. (3) Обучить K раундов. В каждом раунде выполняется взвешивание выборки и выбор признаков на основе предыдущего раунда для получения подмоделей. Наконец, интегрируйте все подмодели для использования.

В этой статье проводятся эксперименты по задаче прогнозирования цен криптовалюты и торговли акциями с использованием DNN и дерева решений градиентного подъема в качестве базовой модели. DoubleEnsemble добился лучшей производительности. По сравнению с несколькими базовыми методами годовая доходность увеличилась более чем на 30%, а коэффициент Шарпа увеличился более чем на 70%.

В этой статье предлагается структура DoubleEnsemble для решения вышеуказанных проблем и повышения точности прогнозирования финансовых задач. Платформа DoubleEnsemble имеет следующие три характеристики:

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

2. Компания DoubleEnsemble предложила новую схему повторного взвешивания выборки, основанную на траектории обучения, которая полностью интегрирует траекторию обучения в построение весов выборки. Эта схема повторного взвешивания может эффективно уменьшить веса простых выборок и выборок шума, а также улучшить веса сложных выборок, которые более полезны для модели.

3. Традиционные методы (такие как обратное исключение и рекурсивное исключение признаков) обычно пытаются удалить избыточные признаки в соответствии с их важностью и переобучить всю модель после перемещения признаков. Переобучение создает огромные вычислительные затраты. Более того, когда нейронная сеть используется для обучения, удаление признаков может полностью изменить распределение входных данных, что приведет к крайне нестабильному процессу обучения. Чтобы решить эту проблему, DoubleEnsemble предложила новый метод выбора признаков, основанный на перемешивании. Переставляя функцию в обучающей выборке и измеряя изменение Loss. Небольшое изменение указывает на то, что корреляция между функцией и задачей прогнозирования невелика.

Код алгоритма 2:

def sample_reweight(self, loss_curve, loss_values, k_th):
    """
    the SR module of Double Ensemble
    :param loss_curve: the shape is NxT
    the loss curve for the previous sub-model, where the element (i, t) if the error on the i-th sample
    after the t-th iteration in the training of the previous sub-model.
    :param loss_values: the shape is N
    the loss of the current ensemble on the i-th sample.
    :param k_th: the index of the current sub-model, starting from 1
    :return: weights
    the weights for all the samples.
    """
    # normalize loss_curve and loss_values with ranking
    loss_curve_norm = loss_curve.rank(axis=0, pct=True)
    loss_values_norm = (-loss_values).rank(pct=True)

    # calculate l_start and l_end from loss_curve
    N, T = loss_curve.shape
    part = np.maximum(int(T * 0.1), 1)
    l_start = loss_curve_norm.iloc[:, :part].mean(axis=1)
    l_end = loss_curve_norm.iloc[:, -part:].mean(axis=1)

    # calculate h-value for each sample
    h1 = loss_values_norm
    h2 = (l_end / l_start).rank(pct=True)
    h = pd.DataFrame({"h_value": self.alpha1 * h1 + self.alpha2 * h2})

    # calculate weights
    h["bins"] = pd.cut(h["h_value"], self.bins_sr)
    h_avg = h.groupby("bins")["h_value"].mean()
    weights = pd.Series(np.zeros(N, dtype=float))
    for b in h_avg.index:
        weights[h["bins"] == b] = 1.0 / (self.decay**k_th * h_avg[b] + 0.1)
    return weights

Код алгоритма 3:

def feature_selection(self, df_train, loss_values):
    """
    the FS module of Double Ensemble
    :param df_train: the shape is NxF
    :param loss_values: the shape is N
    the loss of the current ensemble on the i-th sample.
    :return: res_feat: in the form of pandas.Index
    """
    x_train, y_train = df_train["feature"], df_train["label"]
    features = x_train.columns
    N, F = x_train.shape
    g = pd.DataFrame({"g_value": np.zeros(F, dtype=float)})
    M = len(self.ensemble)

    # shuffle specific columns and calculate g-value for each feature
    x_train_tmp = x_train.copy()
    for i_f, feat in enumerate(features):
        x_train_tmp.loc[:, feat] = np.random.permutation(x_train_tmp.loc[:, feat].values)
        pred = pd.Series(np.zeros(N), index=x_train_tmp.index)
        for i_s, submodel in enumerate(self.ensemble):
            pred += (
                pd.Series(
                    submodel.predict(x_train_tmp.loc[:, self.sub_features[i_s]].values), index=x_train_tmp.index
                )
                / M
            )
        loss_feat = self.get_loss(y_train.values.squeeze(), pred.values)
        g.loc[i_f, "g_value"] = np.mean(loss_feat - loss_values) / (np.std(loss_feat - loss_values) + 1e-7)
        x_train_tmp.loc[:, feat] = x_train.loc[:, feat].copy()

    # one column in train features is all-nan # if g['g_value'].isna().any()
    g["g_value"].replace(np.nan, 0, inplace=True)

    # divide features into bins_fs bins
    g["bins"] = pd.cut(g["g_value"], self.bins_fs)

    # randomly sample features from bins to construct the new features
    res_feat = []
    sorted_bins = sorted(g["bins"].unique(), reverse=True)
    for i_b, b in enumerate(sorted_bins):
        b_feat = features[g["bins"] == b]
        num_feat = int(np.ceil(self.sample_ratios[i_b] * len(b_feat)))
        res_feat = res_feat + np.random.choice(b_feat, size=num_feat, replace=False).tolist()
    return pd.Index(set(res_feat))

Экспериментальный результат:

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

Документ: https://arxiv.org/abs/2010.01265

код: https://github.com/microsoft/qlib/blob/main/qlib/contrib/model/double_ensemble.py