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
中添加其他列,然后转换器将在列表理解中创建。
用例: 我有多个资产(例如 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
中添加其他列,然后转换器将在列表理解中创建。