Как создать удобные для пользователя склеарн-регрессоры, способные работать с нечисленными c целями? - PullRequest
4 голосов
/ 24 апреля 2020

Цель

Я пытаюсь создать регрессоры, которые инкапсулируют процесс

  1. преобразования цели из нечислительного c в числовое c формат
  2. внутри, используйте числа для всех вычислений
  3. обратное преобразование чисел c - возвращает значения в исходный формат перед тем, как представить их пользователю.

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

Prototype Demo

С помощью sklearn.compose.TransformedTargetRegressor я смог построить модель линейной регрессии, которая принимает временные метки в качестве целей и внутренне преобразует их в секунды, выделенные с 1970-01-01 00:00:00 (Unix эпоха). Методы fit и predict уже работают должным образом.

import pandas as pd
from sklearn.compose import TransformedTargetRegressor
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import FunctionTransformer

_check_inverse = False

# helper to convert a 2D numpy array of timestamps to a 2D array of seconds
def _to_float(timestamps):
    deltas = pd.DataFrame(timestamps).sub(pd.Timestamp(0))
    return deltas.apply(lambda s: s.dt.total_seconds()).values

# helper to convert a 2D numpy array of seconds to a 2D array of timestamps
def _to_timestamp(seconds):
    return pd.DataFrame(seconds).apply(pd.to_datetime, unit='s').values

# build transformer from helper functions
time_transformer = FunctionTransformer(
    func=_to_float,
    inverse_func=_to_timestamp,
    validate=True,
    check_inverse=_check_inverse
)

# build TransformedTargetRegressor
tt_reg = TransformedTargetRegressor(
    regressor=LinearRegression(),
    transformer=time_transformer,
    check_inverse=_check_inverse
)

Использование:

>>> import numpy as np
>>> X = np.array([[1], [2], [3]], dtype=float)
>>> y = pd.date_range(start=0, periods=3, freq='min')
>>> tt_reg = tt_reg.fit(X, y)
>>> tt_reg.predict(X)
array(['1970-01-01T00:00:00.000000000', '1970-01-01T00:01:00.000000000',
       '1970-01-01T00:02:00.000000000'], dtype='datetime64[ns]')

Однако методы, которые используют результат predict внутри, например score (и, возможно, другие методы более сложных регрессоров sklearn) не работают, потому что они не могут обработать вывод _to_timestamp:

>>> tt_reg.score(X, y)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "C:\Users\actualpanda\.virtualenvs\SomeProject--3333Ox_\lib\site-packages\sklearn\base.py", line 435, in score
    return r2_score(y, y_pred, sample_weight=sample_weight,
  File "C:\Users\actualpanda\.virtualenvs\SomeProject--3333Ox_\lib\site-packages\sklearn\metrics\_regression.py", line 591, in r2_score
    numerator = (weight * (y_true - y_pred) ** 2).sum(axis=0,
TypeError: ufunc 'square' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''

Чтобы получить оценку, пользователь должен знать внутреннюю часть tt_reg.regressor_.

>>> tt_reg.regressor_.score(X, y.to_series().sub(pd.Timestamp(0)).dt.total_seconds())
1.0

Вопрос

Существует ли реальный способ создания надежных, удобных в использовании регуляторов sklearn, которые могут работать с нечисленными c целями и не протекать изнутри

1 Ответ

6 голосов
/ 28 апреля 2020

Обновление метода score может решить вашу проблему, как указано в комментариях.

from sklearn.utils import check_array


class MyTransformedTargetRegressor(TransformedTargetRegressor):

    def score(self, X, y):
        y = check_array(y, accept_sparse=False, force_all_finite=True,
                        ensure_2d=False)
        if y.ndim == 1:
            y_2d = y.reshape(-1, 1)
        else:
            y_2d = y
        y_trans = self.transformer_.transform(y_2d)

        if y_trans.ndim == 2 and y_trans.shape[1] == 1:
            y_trans = y_trans.squeeze(axis=1)

        return self.regressor_.score(X, y_trans)

Давайте попробуем с другим регрессором

from sklearn.ensemble import BaggingRegressor
tt_reg = MyTransformedTargetRegressor(
    regressor=BaggingRegressor(),
    transformer=time_transformer,
    check_inverse=_check_inverse
)


import numpy as np
n_samples =10000
X = np.arange(n_samples).reshape(-1,1)
y = pd.date_range(start=0, periods=n_samples, freq='min')
tt_reg = tt_reg.fit(X, y)
tt_reg.predict(X)
print(tt_reg.score(X, y))

# 0.9999999891236799
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...