scikit-learn - создание многоуровневой классификации с помощью классификатора svm.svc, возможно ли это без вероятности = True?

Я попытался добиться многоуровневой классификации с помощью классификатора Pipeline\onevsrest в scikit-learn. Код приведен ниже, но сначала позвольте мне упомянуть, что я строю свои примеры с несколькими метками из кадра данных pandas.

Код ниже:

df = pd.read_csv(fileIn, header = 0, encoding='utf-8-sig')
rows = random.sample(df.index, int(len(df) * 0.9))

work = df.ix[rows]

work_test = df.drop(rows)

X_train = []

y_train = []

X_test = []

y_test = []
for i in work[[i for i in list(work.columns.values) if i.startswith('Change')]].values:
    X_train.append(','.join(i.T.tolist()))

X_train = np.array(X_train)

for i in work[[i for i in list(work.columns.values) if i.startswith('Corax')]].values:
    y_train.append(list(i))


for i in work_test[[i for i in list(work_test.columns.values) if i.startswith('Change')]].values:
    X_test.append(','.join(i.T.tolist()))

X_test = np.array(X_test)

for i in work_test[[i for i in list(work_test.columns.values) if i.startswith('Corax')]].values:
    y_test.append(list(i))


lb = preprocessing.MultiLabelBinarizer()

Y = lb.fit_transform(y_train)

classifier = Pipeline([('vectorizer', CountVectorizer()),('tfidf', TfidfTransformer()),('clf', OneVsRestClassifier(SVC(kernel='rbf')))])

classifier.fit(X_train, Y)

predicted = classifier.predict(X_test)

Но проблема в том, что когда вы используете этот набор преобразований: CountVectorizer -> TfidfTransformer вы получаете разреженную матрицу. Проблема в том, что когда вы пытаетесь предсказать метки с помощью классификатора OneVsRest, он ищет методы decision_function или predict_proba. predict_proba недоступен на svm.SVC, если вы не укажете probability=True. С другой стороны, как я вижу в коде, decision_function не реализовано для разреженных матриц. Таким образом, мой код не работает, поскольку ни один из этих двух обязательных методов недоступен. Но может я что-то не так делаю? Можно ли каким-то образом добиться многоуровневой классификации с помощью svm.SVC без указания probability=True? (это значительно увеличивает нагрузку на обучение классификатора), возможно, каким-то образом заставив TfidfTransformer выводить плотную матрицу вместо разреженной?


person Maksim Khaitovich    schedule 09.12.2014    source источник


Ответы (1)


Это хорошо известная проблема, и на данный момент не существует простого решения.

Вы можете использовать Pipeline для "уплотнения" разреженных данных. (путем вызова .toarray), но это может увеличить потребление памяти. Вы можете сделать TruncatedSVD (насколько мне известно, это единственная размерность метод сокращения, который работает с разреженными данными), но он может испортить ваши данные, так что производительность SVM снизится.

person Artem Sobolev    schedule 10.12.2014
comment
Это интересно, спасибо. Метод toarray у меня работает (по крайней мере, на данный момент я не работаю со слишком большими наборами данных, поэтому я мог бы использовать такие методы для сравнения производительности разных ядер svm и решения, какое из них использовать). - person Maksim Khaitovich; 10.12.2014
comment
К сожалению, уплотнение не работает — когда я добавляю toarray в конвейер: TfIdfTransformer.toarray(), он все равно считает, что вывод разреженный. Я не ошибаюсь? - person Maksim Khaitovich; 11.12.2014
comment
@MaximHaytovich, без реального кода сложно сказать. - person Artem Sobolev; 11.12.2014
comment
@Barmalay.exe Все то же, что и в исходном вопросе, только определение конвейера изменено на это: classifier = Pipeline([('vectorizer', CountVectorizer()),('tfidf', TfidfTransformer().toarray()), ('clf', OneVsRestClassifier (SVC (ядро = 'rbf')))]) - person Maksim Khaitovich; 11.12.2014
comment
@MaximHaytovich, вы уверены, что запускаете новый код? Потому что код, который вы предоставили, является абсолютной ерундой: TfidfTransformer не имеет метода toarray, и он выдает мне AttributeError. Вы должны написать свой собственный Transformer (как класс), реализующий метод transform (подробности см. в документации Pipeline). - person Artem Sobolev; 12.12.2014
comment
Lol, извините, я внес изменения в файл кода, но забыл, что запускал скомпилированную версию и не пересобирал ее. Да, у него просто нет метода .toarray. Просто хотел уточнить, мой класс преобразователя (его метод преобразования) должен просто получать входные данные от TfIdfTransofrmer (разреженная матрица), вызывать для него toarray() и возвращать результат? Я имею в виду, будет ли работать вызов toarray() на разреженной матрице, или я должен написать даже свой собственный метод уплотнения? - person Maksim Khaitovich; 12.12.2014
comment
@MaximHaytovich, по моему опыту, вызов .toarray на разреженной матрице работает. - person Artem Sobolev; 12.12.2014