Статьи

Pandas / scikit-learn: get_dummies test / train sets — ValueError: фигуры не выровнены

Я использовал функцию panda get_dummies для генерации фиктивных столбцов для категориальных переменных для использования с scikit-learn, но заметил, что иногда это работает не так, как я ожидаю.

Предпосылки

1
2
3
import pandas as pd
import numpy as np
from sklearn import linear_model

импортировать панд как pd импортировать numpy как np из sklearn import linear_model

Допустим, у нас есть следующие обучающие и тестовые наборы:

Обучающий набор

1
2
3
4
train = pd.DataFrame({"letter":["A", "B", "C", "D"], "value": [1, 2, 3, 4]})
X_train = train.drop(["value"], axis=1)
X_train = pd.get_dummies(X_train)
y_train = train["value"]

train = pd.DataFrame ({«letter»: [«A», «B», «C», «D»], «value»: [1, 2, 3, 4]}) X_train = train.drop ( [«Значение»], ось = 1) X_train = pd.get_dummies (X_train) y_train = train [«значение»]

Тестовый набор

1
2
3
4
test = pd.DataFrame({"letter":["D", "D", "B", "E"], "value": [4, 5, 7, 19]})
X_test = test.drop(["value"], axis=1)
X_test = pd.get_dummies(X_test)
y_test = test["value"]

test = pd.DataFrame ({«letter»: [«D», «D», «B», «E»], «value»: [4, 5, 7, 19]})) X_test = test.drop ( [«Значение»], ось = 1) X_test = pd.get_dummies (X_test) y_test = test [«value»]

Теперь предположим, что мы хотим обучить линейную модель на нашем обучающем наборе, а затем использовать ее для прогнозирования значений в нашем наборе испытаний:

Тренируй модель

1
2
lr = linear_model.LinearRegression()
model = lr.fit(X_train, y_train)

Протестируйте модель

1
model.score(X_test, y_test)
1
ValueError: shapes (4,3) and (4,) not aligned: 3 (dim 1) != 4 (dim 0)

Хм, это не пошло в план. Если мы напечатаем X_train и X_test, это может помочь пролить некоторый свет:

Проверка поездных / тестовых наборов данных

1
print(X_train)
1
2
3
4
5
letter_A  letter_B  letter_C  letter_D
0         1         0         0         0
1         0         1         0         0
2         0         0         1         0
3         0         0         0         1
1
print(X_test)
1
2
3
4
5
letter_B  letter_D  letter_E
0         0         1         0
1         0         1         0
2         1         0         0
3         0         0         1

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

Мы можем исправить это, сделав поле ‘letter’ категориальным, прежде чем запустить метод get_dummies над фреймом данных. На данный момент поле имеет тип «объект»:

Типы столбцов

1
print(train.info)
1
2
3
4
5
6
7
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 2 columns):
letter    4 non-null object
value     4 non-null int64
dtypes: int64(1), object(1)
memory usage: 144.0+ bytes

Мы можем исправить это, преобразовав поле ‘letter’ в тип ‘category’ и установив список допустимых значений в качестве уникального набора значений в наборах Train / Test.

Все допустимые значения

1
2
3
all_data = pd.concat((train,test))
for column in all_data.select_dtypes(include=[np.object]).columns:
    print(column, all_data[column].unique())
1
letter ['A' 'B' 'C' 'D' 'E']

Теперь давайте обновим тип нашего поля «письмо» в поезде и протестируем данные.

Тип: «категория»

1
2
3
4
5
all_data = pd.concat((train,test))
  
for column in all_data.select_dtypes(include=[np.object]).columns:
    train[column] = train[column].astype('category', categories = all_data[column].unique())
    test[column] = test[column].astype('category', categories = all_data[column].unique())

И теперь, если мы вызовем get_dummies для любого фрейма данных, мы получим одинаковый набор столбцов:

get_dummies: взять 2

1
2
3
X_train = train.drop(["value"], axis=1)
X_train = pd.get_dummies(X_train)
print(X_train)
1
2
3
4
5
letter_A  letter_B  letter_C  letter_D  letter_E
0         1         0         0         0         0
1         0         1         0         0         0
2         0         0         1         0         0
3         0         0         0         1         0
1
2
3
X_test = test.drop(["value"], axis=1)
X_test = pd.get_dummies(X_test)
print(X_train)
1
2
3
4
5
letter_A  letter_B  letter_C  letter_D  letter_E
0         0         0         0         1         0
1         0         0         0         1         0
2         0         1         0         0         0
3         0         0         0         0         1

Большой! Теперь мы должны быть в состоянии обучить нашу модель и использовать ее в тестовом наборе:

Тренируй модель: возьми 2

1
2
lr = linear_model.LinearRegression()
model = lr.fit(X_train, y_train)

Протестируйте модель: возьмите 2

1
model.score(X_test, y_test)
1
-1.0604490500863557

И мы сделали!