具有不同行数的 Scikit Learn 特征联合

Posted

技术标签:

【中文标题】具有不同行数的 Scikit Learn 特征联合【英文标题】:Sci-Kit Learn FeatureUnion with different number of rows 【发布时间】:2017-05-02 19:21:04 【问题描述】:

我正在尝试在数据位于数据库中的项目中使用 scikit-learn Pipelines 的 FeatureUnion 功能。我在如何构建我正在做的事情上遇到了一些基本问题。

我正在从数据库中的两个不同表中创建两个特征。我有一个 fetch_x1, fetch_x2 方法来从数据库表中获取感兴趣的数据作为 pandas DataFrames。我将两个 DataFrame 打包成一个数据框字典。在每个转换器中,我解压感兴趣的 DataFrame 并对其进行操作。我有点遵循post 的模式。

我的代码如下:

class Feature1Extractor(TransformerMixin):

    def transform(self, dictionary_of_dataframes):
        df = dictionary_of_dataframes['feature1_raw_data']
        x = df.groupby('user_id').count()['x1']
        return df

class Feature2Extractor(TransformerMixin):

    def transform(self, dictionary_of_dataframes):
        df = dictionary_of_dataframes['feature2']
        x = df.groupby('user_id').sum()['x2']
        return x

pipeline = Pipeline([
    ('union', FeatureUnion(
        transformer_list=[
            ('feature1', Feature1Extractor()),
            ('feature2', Feature2Extractor())])),
    ('null', None)
])

pipeline.transform(dictionary_of_dataframes)

我遇到了另一个更基础的问题——在转换后,每个管道产生的两个特征矩阵具有不同的行数。因此,FeatureUnion 末尾的简单 hstack 会像这样失败:

ValueError: all the input array dimensions except for the concatenation axis must match exactly

这是我拥有的数据的基础。有许多 user_ids 不存在于 feature1 表中,同样有许多 user_ids 不存在于 feature2 表中。这是数据的基础——如果用户在 feature1 表中没有数据,他/她从未在应用程序中使用过该功能,例如没有数据 = 没有参与该功能。为了使示例更明确,这里是传递给每个转换器的两个 df 的示例:

df(用于特征 1)

user_id, x1, timestamp
1, 'click', 1/1/2016
1, 'click', 1/2/2016
2, 'click', 1/2/2016

df(用于特征 2)

user_id, x2, timestamp
2, 12.3, 1/2/2016
3, 14,5, 1/4/2016

请注意,feature1 的 DataFrame 没有用户 3,而 feature2 的 DataFrame 没有用户 1。当我在没有管道的情况下执行此操作时,我会先进行外部连接,然后在生成的合并数据帧上进行 fillna(0) ,例如

merged_df = pd.merge(df1, df1, how='outer', left_on=['user_id'], right_on=['user_id'])
final_df = merged_df.fillna(0)

但似乎没有任何方法可以使用 FeatureUnion 方法来做到这一点。而且我似乎无法在管道框架中想到一个干净的解决方法......我必须运行单独的管道,转换它们中的每一个,在熊猫中进行外部连接和填充,然后将完成的特征矩阵运行到下游建模管道?有没有更好的办法?向社区寻求帮助。

注意:我事先不知道 user_ids。我正在根据时间戳范围查询表……而不是 user_id。查询本身告诉我应该在训练(或测试)集中拥有哪些用户。

【问题讨论】:

很难按照您的要求进行操作。给我们一些示例数据或少量输入/输出,以便我们验证您遇到的问题。我不确定为什么不能将一个数据集填充为与另一个数据集具有相同的行数(用Nones 或其他内容填充),然后执行 FeatureUnion 你说得对,我会适当地编辑...虽然我事先并不知道所有的 user_id ---这就是我做外部连接的原因...我不想单独跟踪。我将通过一个很好的示例对其进行编辑以更加集中。 【参考方案1】:

为什么不建立自己的基于 pandas 的联盟? 这样的东西...(我没有测试过,只是看看想法)

class DataMerging(BaseEstimator):

    def __init__(self):
        return self

    def fit(self, x, y=None):
        return self

    def transform(self, dfs):
        df1, df2 = dfs
        merged_df = pd.merge(df1, df2, how='outer', left_on=['user_id'], right_on=['user_id']).fillna(0)
        return merged_df.values #(return shape (n_features, n_samples))


pipeline = Pipeline([
    ('union', DataMerging,
    ('other thing', ...)
])        

pipeline.fit(df1, df2)  

【讨论】:

好吧,这很有趣——但我并不完全理解它如何适合 Pipeline 描述......另外,我应该继承 FeatureUnion 吗?

以上是关于具有不同行数的 Scikit Learn 特征联合的主要内容,如果未能解决你的问题,请参考以下文章

在 scikit learn 中训练具有不同特征维度的逻辑回归模型

Scikit-learn RandomForestClassifier() 特征选择,只选择训练集?

如何使用 scikit-learn PCA 进行特征缩减并知道哪些特征被丢弃

Scikit-learn 中的特征选择遇到了混合变量类型的问题

特征不匹配:通过 scikit-learn 管道进行预测

scikit-learn 估算另一个特征中标称值组内特征的平均值