2016-12-16 8 views
0

Я пытаюсь использовать функциональные возможности FeatureUnion scycit-learn Pipelines в проекте, где данные находятся в базе данных. У меня возникают некоторые фундаментальные проблемы в том, как структурировать то, что я делаю.Sci-Kit Learn FeatureUnion с различным количеством строк

Я создаю две функции из двух разных таблиц в базе данных. У меня есть метод fetch_x1, fetch_x2 для захвата интересующих данных из таблиц базы данных в виде pandas DataFrames. Я упаковываю два DataFrames в словарь данных. В каждом трансформаторе я распаковываю интересующий 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) 

Я бегу в другую более основополагающий вопрос - после трансформации двух функциональных матриц, которые выходят из каждого трубопровода имеют различное количество строк. Следовательно, простой hstack в конце FeatureUnion не удается, так как:

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

Это имеет фундаментальное значение для данных у меня есть. Существует ряд user_id, которые не присутствуют в таблице feature1, аналогично существует ряд user_id, которых нет в таблице feature2. Это имеет фундаментальное значение для данных - если у пользователя нет данных в таблице feature1, он/она никогда не использовал эту функцию в приложении, например. нет данных = нет взаимодействия с этой функцией. Для того, чтобы сделать пример явным, вот пример из двух ДФ-х, которые передается каждому трансформатору:

ДФ (для Feature1)

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

ДФ (для feature2)

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

Примечание как DataFrame для feature1 не имеет пользователя 3, а DataFrame для функции2 не имеет пользователя 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 ... Я должен запускать отдельные конвейеры, преобразовывать каждую из них, выполнять внешнее соединение и заполнять в пандах, а затем запускать завершенную матрицу функций в нисходящий поток моделирование трубопровода? Есть ли способ лучше? Глядя в сообщество за помощью.

ПРИМЕЧАНИЕ. Я НЕ знаю user_ids перед началом работы. Я запрашиваю таблицы на основе диапазона метка времени ... не user_id. Сам запрос сообщает мне, какие пользователи должны иметь в настройке обучения (или теста).

+0

Это трудно следовать, что вы просите. Дайте нам некоторые примеры данных или небольшой ввод/вывод, чтобы мы могли проверить проблему, с которой вы сталкиваетесь. Я не уверен, почему вы не можете заполнить один набор данных, чтобы иметь только то же количество строк, что и другое (заполните его «Нет или что-то»), а затем выполните FeatureUnion – mwm314

+0

. Вы правы, я отредактирую надлежащим образом ... Я не знаю всех user_ids перед рукой, хотя --- вот почему я делал внешнее соединение ... я не хочу отслеживать это отдельно. Я отредактирую это, чтобы быть более сосредоточенным с хорошим примером. –

ответ

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) 
+0

Хорошо, это интересно - но я не совсем понимаю, как это вписывается в описание Pipeline ... Кроме того, должен ли я подкласс FeatureUnion? –