我正在尝试在数据位于数据库中的项目中使用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。查询本身告诉我在训练(或测试)集中应该有哪些用户。
答案 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)