Как комбинировать элементы с выводом разных размеров с помощью scikit-learn

Я использую scikit-learn с Pipeline и FeatureUnion для извлечения функций из разных источников. Каждый образец (экземпляр) в моем наборе данных относится к документам различной длины. Моя цель состоит в том, чтобы вычислить верхний tfidf для каждого документа независимо, но я продолжаю получать это сообщение об ошибке:

ValueError: blocks [0 ,:] имеет несовместимые размеры строк. Получили блоки [0,1].shape [0] == 1, ожидаемый 2000.

2000 - размер данных обучения. Это основной код:

book_summary= Pipeline([
   ('selector', ItemSelector(key='book')),
   ('tfidf', TfidfVectorizer(analyzer='word', ngram_range(1,3), min_df=1, lowercase=True, stop_words=my_stopword_list, sublinear_tf=True))
])

book_contents= Pipeline([('selector3', book_content_count())]) 

ppl = Pipeline([
    ('feats', FeatureUnion([
         ('book_summary', book_summary),
         ('book_contents', book_contents)])),
    ('clf', SVC(kernel='linear', class_weight='balanced') ) # classifier with cross fold 5
]) 

Я написал два класса для обработки каждой функции конвейера. Моя проблема связана с конвейером book_contents, который в основном касается каждого образца и возвращает матрицу TFidf для каждой книги независимо.

class book_content_count(): 
  def count_contents2(self, bookid):
        book = open('C:/TheCorpus/'+str(int(bookid))+'_book.csv', 'r')       
        book_data = pd.read_csv(book, header=0, delimiter=',', encoding='latin1',error_bad_lines=False,dtype=str)
                      corpus=(str([user_data['text']]).strip('[]')) 
        return corpus

    def transform(self, data_dict, y=None):
        data_dict['bookid'] #from here take the name 
        text=data_dict['bookid'].apply(self.count_contents2)
        vec_pipe= Pipeline([('vec', TfidfVectorizer(min_df = 1,lowercase = False, ngram_range = (1,1), use_idf = True, stop_words='english'))])
        Xtr = vec_pipe.fit_transform(text)
        return Xtr

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

Пример данных (пример):

title                         Summary                          bookid
The beauty and the beast      is a traditional fairy tale...    10
ocean at the end of the lane  is a 2013 novel by British        11

Затем каждый идентификатор будет ссылаться на текстовый файл с фактическим содержимым этих книг

Я попытался toarray и reshape функции, но не повезло. Любая идея, как решить эту проблему. Спасибо

Ответ 1

Вы можете использовать Neuraxle Feature Union с пользовательским соединителем, который вам нужно будет написать самостоятельно. Joiner - это класс, переданный Neuraxle FeatureUnion для объединения результатов так, как вы ожидали.

1. Импортируйте классы Neuraxle.

from neuraxle.base import NonFittableMixin, BaseStep
from neuraxle.pipeline import Pipeline
from neuraxle.steps.sklearn import SKLearnWrapper
from neuraxle.union import FeatureUnion

2. Определите свой пользовательский класс, унаследовав его от BaseStep:

class BookContentCount(BaseStep): 

    def transform(self, data_dict, y=None):
        transformed = do_things(...)  # be sure to use SKLearnWrapper if you wrap sklearn items.
        return Xtr

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

3. Создайте столяра, чтобы присоединиться к результатам объединения функций так, как вы хотите:

class CustomJoiner(NonFittableMixin, BaseStep):
    def __init__(self):
        BaseStep.__init__(self)
        NonFittableMixin.__init__(self)

    # def fit: is inherited from 'NonFittableMixin' and simply returns self.

    def transform(self, data_inputs):
        # TODO: insert your own concatenation method here.
        result = np.concatenate(data_inputs, axis=-1)
        return result

4. Наконец, создайте свой конвейер, передав соединителю в FeatureUnion:

book_summary= Pipeline([
    ('selector', SKLearnWrapper(ItemSelector(key='book'))),
    ('tfidf', SKLearnWrapper(TfidfVectorizer(analyzer='word', ngram_range(1,3), min_df=1, lowercase=True, stop_words=my_stopword_list, sublinear_tf=True)))
])

p = Pipeline([
    ('feats', FeatureUnion([
        ('book_summary', book_summary),
        ('book_contents', BookContentCount())
    ], 
        joiner=CustomJoiner()
    )),
    ('clf', SKLearnWrapper(SVC(kernel='linear', class_weight='balanced')))
]) 

Примечание: если вы хотите, чтобы ваш конвейер Neuraxle превратился в конвейер scikit-learn, вы можете сделать это p = p.tosklearn().