Машинное обучение: автоматическая категоризация строк - «неизвестный тип метки» и «неверная форма ввода»

Я пытаюсь написать код, который автоматически классифицирует мои банковские транзакции с помощью Python (и Scikit Learn). В настоящее время у меня около 1,7 тыс. Транзакций, уже классифицированных по 70 категориям (меткам) - всего у меня около 3,5 тыс. Строк, но не все организованы, это моя первая попытка. В основном я импортировал файл CSV с:

Description             | Value | Label
RSHOP-SABORES DA -25/04 | -30   | Restaurants
RSHOP-MERCATTINO -28/04 | -23   | Bars
RSHOP-HORTISABOR -07/05 | -65   | Supermarket
TBI 3712.06663-9 tokpag | 1.000 | Salary

Описание и значение - это мои особенности, а ярлык - это мой ярлык. Описание может быть немного сложным с разными персонажами и т. д. Итак, я узнал, что мне нужно векторизовать описание с помощью Tf-IDF и LabelEncode для меток.


На данный момент у меня есть:

# Loads data
data = pd.read_csv('classifications.csv',
                    encoding='latin1',
                    error_bad_lines=False,
                    delimiter=';')

# Assigns features and labels - I chose to use only the description to make it simpler for a first time. I want to use the value later as well.
data.columns = ['desc', 'value', 'label']
data_base    = data.values
features_base= data_base[:,[0]]
labels_base  = data_base[:,[2]]

# Printing features returns a (1722,1) array - looks good.
print(features_base.shape)

# Printing labels returns a (1722,1) array - looks good.
print(labels_base.shape)

# Encodes labels, printing returns (1722,) - don't know why the "1" is missing on the y.
encoder       = LabelEncoder()
label_encoded = encoder.fit_transform((labels_base.astype(str)).ravel())
print(label_encoded.shape)

# Encodes features. Printing returns (1722, 1012) - don't know what's the "1012" on the y axis... the only thing I can think of the number of unique values on the vector, but can't be sure.
vectorizer = TfidfVectorizer()
vectors     = vectorizer.fit_transform(features_base.ravel().astype('U'))
print(vectors.shape)


#Test
train_features, train_labels, test_features, test_labels = tts(vectors, label_encoded, test_size=0.2)

А затем я пробую несколько оценщиков, каждая с другой ошибкой (записанной в первой строке комментария):

# Random Forest Classifier - returns "ValueError: Unknown label type: 'continuous-multioutput'"
clf1 = RandomForestClassifier()
print("Using", clf1)
clf1.fit(train_features.toarray(), train_labels.toarray())
predictions1 = clf1.predict(test_features)
print( "\nPredictions:", predictions1)
score = 0
for i in range(len(predictions1)):
    if predictions[i] == test_labels[i]:
        score += 1
print("Accuracy:", (score / len(predictions)) * 100, "%")


# Decision Tree Classifier - returns "ValueError: Unknown label type: 'continuous-multioutput'"
clf2 = tree.DecisionTreeClassifier()
print("Using", clf2)
clf2.fit(train_features.toarray(), train_labels.toarray())
predictions2 = clf2.predict(test_features)
print( "\nPredictions:", predictions2)
score = 0
for i in range(len(predictions2)):
    if predictions[i] == test_labels[i]:
        score += 1
print("Accuracy:", (score / len(predictions)) * 100, "%")


#SVC Linear - returns "ValueError: bad input shape (345, 1012)"
clf3 = svm.SVC(kernel='linear')
print("Using", clf3)
clf3.fit(train_features, train_labels)
predictions3 = clf3.predict(test_features)
print( "\nPredictions:", predictions3)
score = 0
for i in range(len(predictions1)):
    if predictions[i] == test_labels[i]:
        score += 1
print("Accuracy:", (score / len(predictions)) * 100, "%")


# SVC Non Linear - returns "ValueError: bad input shape (345, 1012)"
clf4 = svm.SVC()
print("Using", clf4)
clf4.fit(train_features.toarray(), train_labels.toarray())
predictions4 = clf4.predict(test_features)
print( "\nPredictions:", predictions4)
score = 0
for i in range(len(predictions1)):
    if predictions[i] == test_labels[i]:
        score += 1
print("Accuracy:", (score / len(predictions)) * 100, "%")

Конечная цель - загрузить файл CSV с описанием / суммой, и он предлагает мне метку (было бы здорово узнать уровень уверенности в предложении).

Обобщить:

  1. Разумен ли метод векторизации текста описания? Любое предложение?
  2. Правильно ли я использую LabelEncoder для векторизации своих этикеток?
  3. Что я делаю неправильно? Что за ошибка в коде?

Большое спасибо.

Когда вы делаете train_labels.toarray(), почему вы не получаете ошибок? Ваш код кажется слишком запутанным. Вы говорите, что у вас есть 3.5k total rows, а почему "Printing features only returns a (1722,1) array"? В вашем примере CSV в качестве разделителя используется «|», но вы используете delimiter=';' ??

Vivek Kumar 10.09.2018 10:58

1) Не знаю почему. 2) Использование только части моего доступного набора данных, просто для проверки механизма 3) Это был просто пример упрощения визуализации.

lowercase00 10.09.2018 16:31
0
2
596
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Проблема заключается в метках, поскольку вы используете панды, они должны передаваться классификатору как категориальные данные. Я выложу код через несколько минут.

ОБНОВИТЬ: Итак, с вашим кодом возникли проблемы. При разработке модели машинного обучения для новой задачи я предлагаю начать с простого, а затем увеличивать ее сложность позже, когда у вас будет рабочий прототип. Я реализовал код только для RandomForestClassifier, вы сможете легко воспроизвести его для других классификаторов, которые вас интересуют. Вот:

import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.ensemble import RandomForestClassifier

data = pd.read_csv('classifications.csv',
                    encoding='latin1',
                    error_bad_lines=False,
                    delimiter=';')

data.columns = ['desc', 'value', 'label']
data['label'] = data['label'].astype('category')
data.info()
vectorizer = TfidfVectorizer()
vectors    = vectorizer.fit_transform(data['desc'])
print('Shape: ',vectors.shape)

clf = RandomForestClassifier(random_state=42)

clf.fit(vectors,data['label'])
print('Score: {}'.format(clf.score(vectors,data['label'])))
clf.predict(vectorizer.transform(data['desc']))

Вывод этого кода:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 3 columns):
desc     4 non-null object
value    4 non-null float64
label    4 non-null category
dtypes: category(1), float64(1), object(1)
memory usage: 340.0+ bytes
Shape:  (4, 14)
Score: 1.0
array(['Restaurants', 'Bars', 'Supermarket', 'Salary'], dtype=object)

Несколько комментариев:

1) Если вы используете панды, метки для классификации в идеале должны быть категориальными данными (pandas.Categorical). Это снижает вероятность того, что классификатор интерпретирует метки как упорядоченные данные и пытается соответствующим образом отсортировать свои прогнозы.

2) Если вы связываете несколько объектов из sklearn, таких как векторизатор и классификатор, лучше создать экземпляр объекта Pipeline, написав

from sklearn.pipeline import Pipeline
pipeline = Pipeline([('vectorizer',TfidfVectorizer()),
                     ('classifier',RandomForestClassifier())])

Это избавляет вас от необходимости передавать выходные данные метода .transform или .fit_transform из векторизатора в классификатор в любое время, когда вам нужно передать новые данные классификатору, поскольку конвейер делает это автоматически.

3) Установите random_state для случайных классификаторов для воспроизводимости результатов.

4) Непонятно, почему вы пытаетесь вычислить оценку вручную: метод .score () классификатора автоматически вычисляет среднюю оценку точности и предотвращает ошибки с такими функциями, как len (прогнозы). Когда в другом случае вы попытаетесь предсказать распределение вероятностей, а не одно-точечное предсказание, если вы разовьете привычку вызывать len (предсказания), вы можете незаметно провести вычисления в неправильном измерении массива. Если, однако, вы хотите получить оценку в процентах, а не в диапазоне от 0 до 1, просто умножьте оценку, полученную методом .score (), на 100.

Надеюсь это поможет.

Привет, большое спасибо за вдумчивый ответ - действительно, очень полезно. Несколько комментариев к вашим: 1) Понятно, я попытался сделать это через "LabelEncoder", но это был всего лишь один ненужный шаг при использовании категорий Pandas. 2) Не знаю, понимаю ли я, что вы имеете в виду, но проведу небольшое исследование по конвейеру. 3) Понятно. 4) Это был фрагмент кода, который у меня есть, но я заметил, что для этого есть встроенная функция, которая решает эту конкретную проблему ... Я получаю 0,94 (случайный лес) и 0,93 (дерево решений) , что, как я полагаю, довольно неплохое число.

lowercase00 10.09.2018 18:09

смог сделать прогнозы нового набора функций с помощью newPredictions = forest_model.predict (vectorizer.transform (newFeatures)). Следующая задача - включить столбец ['value'] в исходный набор функций, чтобы получить лучшие результаты. Большое спасибо!

lowercase00 10.09.2018 19:13

Добро пожаловать. Что касается конструктора конвейера, пожалуйста, наслаждайтесь этой страницей из документации sklearn: Трубопровод() С этого момента ваша жизнь станет намного проще :)

Daneel R. 10.09.2018 19:16

Из любопытства: только что попал в классификацию моей банковской выписки на 65-70% !! Потрясающие! Спасибо!

lowercase00 10.09.2018 19:28

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

Это полезное описание ошибки, но у OP было три части на свой вопрос. Можете ли вы затронуть и первые две части?

Derek T. Jones 20.09.2018 06:03

Другие вопросы по теме