Fit/transform 将 sklearn 转换器分离到单列的分区

Fit/transform separate sklearn transformers to partitions of single column

用例: 我有多个资产(例如 AAPL、MSFT)和多个特征(例如 MACD、波动率等)的时间序列数据。我正在构建一个 ML 模型以对该数据的一个子集进行分类预测。

问题: 对于每项资产和功能 - 我想适应并应用转换。例如:对于波动率,我想为 AAPL、MSFT 等安装一个转换器 - 然后将该转换应用于该数据分区。

当前状态: 我目前使用 compose.make_column_transformer 但这只对整个列应用了一个转换器 volatility 并且不允许对数据进行分区& 个别变压器 fit/applied 到这些分区。

研究: 我做了一些研究,发现 sklearn.preprocessing.FunctionTransformer 这似乎是我可以使用的构建基块。但是还没想好怎么办。

主要问题:构建可以将转换器适合单个列中的分区(即 groupby)的 sklearn 管道的最佳方法是什么?任何代码指针都会很棒。 TY

示例数据集:

Date Ticker Volatility transformed_vol
01/01/18 AAPL X A(X)
01/02/18 AAPL X A(X)
... AAPL X A(X)
12/30/22 AAPL X A(X)
12/31/22 AAPL X A(X)
01/01/18 GOOG X B(X)
01/02/18 GOOG X B(X)
... GOOG X B(X)
12/30/22 GOOG X B(X)
12/31/22 GOOG X B(X)

我认为使用 Scikit 的 built-in 功能无法以“优雅”的方式做到这一点,原因很简单,因为转换器应用于整个列。但是,可以使用 FunctionalTransformer (正如您正确指出的那样)来规避此限制:

我正在使用以下示例:

print(df)

  Ticker  Volatility  OtherCol
0   AAPL           0         1
1   AAPL           1         1
2   AAPL           2         1
3   AAPL           3         1
4   AAPL           4         1
5   GOOG           5         1
6   GOOG           6         1
7   GOOG           7         1
8   GOOG           8         1
9   GOOG           9         1

我添加了另一列只是为了演示。

from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import FunctionTransformer

# The index should dictate the groups along the column.
df = df.set_index('Ticker')


def A(x):
    return x*x


def B(x):
    return 2*x


def C(x):
    return 10*x


# Map groups to function. A dict for each column and each group in the index.
f_dict = {'Volatility': {'AAPL':A, 'GOOG':B}, 'OtherCol': {'AAPL':A, 'GOOG':C}}


def pick_transform(df):
    return df.groupby(df.index).apply(lambda df: f_dict[df.columns[0]][df.index[0]](df))
                   

ct = ColumnTransformer(
                       [(f'transformed_{col}', FunctionTransformer(func=pick_transform), [col])
                        for col in f_dict]
                      )

df[[f'transformed_{col}' for col in f_dict]] = ct.fit_transform(df)

print(df)

这导致:

        Volatility  OtherCol  transformed_vol  transformed_OtherCol
Ticker                                                             
AAPL             0         1                0                     1
AAPL             1         1                1                     1
AAPL             2         1                4                     1
AAPL             3         1                9                     1
AAPL             4         1               16                     1
GOOG             5         1               10                    10
GOOG             6         1               12                    10
GOOG             7         1               14                    10
GOOG             8         1               16                    10
GOOG             9         1               18                    10

在这里你可以在f_dict中添加其他列,然后转换器将在列表理解中创建。