Sci-Kit了解具有不同行数的FeatureUnion

时间:2016-12-16 23:24:18

标签: python pandas scikit-learn pipeline feature-extraction

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

我正在从数据库中的两个不同表创建两个功能。我有一个fetch_x1,fetch_x2方法从数据库表中获取感兴趣的数据作为pandas DataFrames。我将两个DataFrame打包成一个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

这是我拥有的数据的基础。 feature1表中不存在许多user_id,类似地,feature2表中不存在多个user_id。这是数据的基础 - 如果用户在feature1表中没有数据,他/她从未在应用程序中使用该功能,例如没有数据=没有参与该功能。为了使示例明确,下面是传递给每个转换器的两个df的示例:

df(for feature1)

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

df(for feature2)

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

请注意feature1的DataFrame如何没有用户3,而feature2的DataFrame没有用户1.当我没有使用Pipelines时,我会做一个外连接,然后在生成的合并数据框上执行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方法似乎没有任何方法可以做到这一点。而且我似乎无法想到Pipeline框架中的一个干净的解决方法......我必须运行单独的管道,转换每个管道,在pandas中执行外部连接和fillna,然后将完成的特征矩阵运行到下游建模管道?有没有更好的办法?期待社区的帮助。

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

1 个答案:

答案 0 :(得分:0)

为什么,你不建立自己的,基于熊猫的联盟吗? 像这样......(我没有测试过,只看到了想法)

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)