act*_*nda 4 python pandas scikit-learn
我正在尝试构建封装过程的回归器
理想情况下,最终用户应该能够在不知道目标转换的内部结构的情况下使用回归器。开发人员应提供实现变换和逆变换逻辑的函数。
在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
)
Run Code Online (Sandbox Code Playgroud)
用法:
>>> 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]')
Run Code Online (Sandbox Code Playgroud)
但是,使用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''
Run Code Online (Sandbox Code Playgroud)
为了获得分数,用户必须知道tt_reg.regressor_.
>>> tt_reg.regressor_.score(X, y.to_series().sub(pd.Timestamp(0)).dt.total_seconds())
1.0
Run Code Online (Sandbox Code Playgroud)
是否有一种可行的方法来构建强大的、用户友好的 sklearn 回归器,该回归器可以处理非数字目标并且不会泄漏其内部结构?
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)
Run Code Online (Sandbox Code Playgroud)
让我们尝试使用不同的回归器
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
Run Code Online (Sandbox Code Playgroud)