Пэтси: новые уровни в категориальных полях в тестовых данных

Я пытаюсь использовать Patsy (со sklearn, pandas) для создания простой модели регрессии. Создание формулы в стиле R является главной ничьей.

Мои данные содержат поле под названием «ship_city», в котором может быть любой город из Индии. Поскольку я разбиваю данные на обучающие и тестовые наборы, есть несколько городов, которые появляются только в одном из наборов. Фрагмент кода приведен ниже:

df_train_Y, df_train_X = dmatrices(formula, data=df_train, return_type='dataframe')
df_train_Y_design_info, df_train_X_design_info = df_train_Y.design_info, df_train_X.design_info
df_test_Y, df_test_X = build_design_matrices([df_train_Y_design_info.builder, df_train_X_design_info.builder], df_test, return_type='dataframe')

Последняя строка выдает следующую ошибку:

patsy.PatsyError: ошибка преобразования данных в категориальные: наблюдение со значением «Kolkata» не соответствует ни одному из ожидаемых уровней.

Я считаю, что это очень распространенный вариант использования, когда обучающие данные не будут иметь всех уровней всех категориальных полей. Sklearn DictVectorizer справляется с этим очень хорошо.

Могу ли я как-то заставить это работать с Пэтси?


person DaSarfyCode    schedule 02.12.2015    source источник


Ответы (2)


Проблема, конечно, в том, что если вы просто дадите patsy необработанный список значений, у него не будет возможности узнать, есть ли другие значения, которые потенциально могут иметь место. Вы должны каким-то образом сообщить ему, каков полный набор возможных значений.

Один из способов — использовать аргумент levels= для C(...), например:

# If you have a data frame with all the data before splitting:
all_cities = sorted(df_all["Cities"].unique())
# Alternative approach:
all_cities = sorted(set(df_train["Cities"]).union(set(df_test["Cities"])))

dmatrices("y ~ C(Cities, levels=all_cities)", data=df_train)

Другой вариант, если вы используете категориальную поддержку по умолчанию для pandas, — это запишите набор возможных значений при настройке фрейма данных; если patsy обнаружит, что объект, который вы передали, является категориальным pandas, тогда он автоматически использует атрибут категорий pandas вместо того, чтобы пытаться угадать возможные категории, просматривая данные.

person Nathaniel J. Smith    schedule 14.07.2017
comment
Я ценю ответ, но он сталкивается с той же проблемой, с которой столкнулся ответ timctrans. Перед запуском в производство мы не знали бы всех возможных уровней, с которыми нам предстоит столкнуться. Количество городов и поселков в Индии просто слишком велико, чтобы включить их в модель. Во-первых, исчерпывающего списка этих мест не существует. И хотите верьте, хотите нет, но новые продолжают появляться. В любом случае города — лишь один из таких примеров. - person DaSarfyCode; 14.07.2017
comment
Ну, что вы вообще хотите, чтобы произошло в этом случае? Пэтси вывел матрицу, в которой появились новые столбцы по сравнению с исходной матрицей? Что вы будете делать с ними? - person Nathaniel J. Smith; 14.07.2017
comment
Как я уже упоминал в вопросе, я чувствую, что Dictvectoriser sklearn прекрасно справляется с этим. Он не выдает ошибку. Это просто говорит модели, что вот запись, которая не соответствует ни одному значению города, которое я видел раньше. Он просто помечает все существующие столбцы как 0. Я просто подумал, что Patsy, будучи зрелой библиотекой, также обрабатывает этот очень распространенный вариант использования. Но, видимо, это не так. - person DaSarfyCode; 15.07.2017

Я столкнулся с похожей проблемой и построил матрицы дизайна перед разделением данных.

df_Y, df_X = dmatrices(formula, data=df, return_type='dataframe')
df_train_X, df_test_X, df_train_Y, df_test_Y = \
    train_test_split(df_X, df_Y, test_size=test_size)

Тогда как пример применения подгонки:

model = smf.OLS(df_train_Y, df_train_X)
model2 = model.fit()
predicted = model2.predict(df_test_X)

Технически я не создал тестовый пример, но я больше не сталкивался с ошибкой Error converting data to categorical после реализации вышеизложенного.

person timctran    schedule 25.06.2017
comment
Да, это возможный обходной путь. Но проблема с этим подходом в том, что теперь происходит утечка из тестового набора в тренировочный. В идеале во время обучения мы не должны использовать какую-либо информацию из тестовых данных, которая еще не является частью обучающих данных. Таким образом, в наших тестах мы моделируем то, что на самом деле произойдет в продакшене. Если взять пример из моего вопроса выше, если есть города, о которых я буду знать только в продакшене, будет неправильно (на самом деле даже невозможно) включать такие города в качестве столбцов в мои данные, используемые для обучения модели. Я надеюсь, что это ясно. - person DaSarfyCode; 27.06.2017
comment
Я вижу твою заботу. С учетом сказанного, насколько я понимаю, мой ответ не приведет к утечке информации в смысле предоставления какой-либо дополнительной информации при обучении. Это просто делает модель совместимой с другими элементами в вашем наборе данных. В R это было бы эквивалентно настройке уровней без изменения данных. Если вероятность отсутствия доступных городов высока в вашей модели, то, возможно, будет правильным объединить города вместе, чтобы сформировать более инклюзивную модель; но это склоняется к дизайну модели, отдельному от вашего вопроса о совместимости тестового и тренировочного набора. - person timctran; 05.07.2017
comment
В качестве примера предположим, что у нас есть данные по трем городам A, B, C. И в производстве будет четвертый город D и пятый город E. Так что в этом случае, возможно, подход будет фиктивным кодированием на A, B, C , так что не быть A, B или C любым другим городом. Однако мы не могли ожидать, что модель будет работать оптимально, поскольку она объединит все невидимые города вместе. Вместо этого мы могли бы разработать переменные, такие как city_population (числовые или категориальные: sm, med, lg), city_density и т. д., и сопоставить каждый город с его характеристиками. Затем модель можно применить к городам, которых нет в исходном наборе данных. - person timctran; 05.07.2017