Обработка данных/Машинное обучение/Python

Множество способов изменить внешний вид перехвата

Методы добавления столбца перехвата в набор данных

Если вы чем-то похожи на меня, вы, несомненно, сталкивались с линейной регрессией в своем путешествии по науке о данных. Возможно, чтобы понять модель, вы решили написать код с нуля или, по крайней мере, с несколькими распространенными библиотеками, такими как Pandas или NumPy. Я почему-то все время забываю, как добавить постоянный столбец с единицами в мои наборы данных для моего перехвата, и в конечном итоге мне приходится искать процесс только для того, чтобы найти другой метод, чем раньше. Чтобы мы с вами никогда не заходили слишком далеко в поисках, вот несколько способов добавить столбец перехвата в существующий набор данных.

За методами следует раздел оценки бонусного времени и памяти в конце для тех, кому любопытно. pd.concat оказался наиболее эффективным с точки зрения памяти и создал Pandas DataFrame, в то время как np.concatenate был одним из лучших с точки зрения скорости и создал массив NumPy.

1. Создание данных

Я начал с Pandas DataFrame, так как он работает со всеми предоставленными методами. Также можно использовать массив NumPy, но он ограничен процессами NumPy.

2. «Рескин» Intercept

Ниже я перечислил 7 методов, с которыми я столкнулся, чтобы добавить столбец перехвата в существующий набор данных. Похоже, что они разделены на три категории: размещение в первую очередь, конкатенация и вставка. Результаты находятся в 2D-массиве Pandas DataFrame или NumPy с перехватом в крайнем левом столбце, готовым к некоторой линейной алгебре и машинному обучению.

3. Общее обсуждение

В этом разделе я рассмотрю каждый метод, проиллюстрирую высокоуровневое описание каждого процесса.

Первый метод выделяет матрицу единиц в форме исходного набора данных с одним дополнительным столбцом. Затем неперехватываемые позиции заменяются данными из X. Это может показаться медленным, поскольку перед перезаписью создается и не используется много единиц. Выход представляет собой np.array.

tempX = np.ones((X.shape[0], X.shape[1] + 1))
tempX[:,1:] = X

Второй метод использует конкатенацию. Он создает столбец перехвата, преобразует его в объект DataFrame, а затем объединяет столбец с исходным набором данных. Использование памяти этим методом было весьма неожиданным, поскольку он использовал чуть больше памяти, чем исходный набор данных. Результатом является pd.DataFrame.

pd.concat([pd.DataFrame(np.ones(X.shape[0])), X], axis=1)

Третий, четвертый и пятый методы представляют собой методы конкатенации с использованием NumPy. Помимо разницы в необходимых параметрах, это всего лишь три разных подхода к добавлению перехвата в набор данных. Каждый создает новый столбец перехвата перед объединением результата для нового вывода. Выходы - np.arrays. Различия есть, но в этой статье они не рассматриваются.

np.c_[np.ones(X.shape[0]), X]
np.hstack([np.ones((X.shape[0], 1)), X])
np.concatenate([np.ones((X.shape[0], 1)), X], axis=1)

Шестой способ – вставка. Он задает столбец, указывая индекс и ориентацию оси, выбирает значение для вставки и продолжает работу. Он использует np.array(X) для преобразования DataFrame в массив NumPy. Это похоже на встроенную функцию списка Python, но вносит некоторую путаницу, потому что вы можете добавить одно значение для распространения столбца в массиве. Точно так же вы можете передать [1] в качестве третьего аргумента для точно такого же вывода. Результатом является np.array.

np.insert(np.array(X), 0, 1, axis=1)

Седьмой способ — вставка и подкачка. Он делает копию, так что исходный DataFrame остается нетронутым. Перехват добавляется с помощью специального процесса Pandas, аналогичного шестому методу, когда мы устанавливаем столбец в скаляр, создавая столбец, заполненный предоставленным скаляром. Столбцы DataFrame извлекаются, переупорядочиваются, а затем передаются в метод переиндексации. Результатом является pd.DataFrame.

tempX = X.copy()
tempX['intercept'] = 1
columns = list(tempX.columns)
columns[0], columns[1:] = columns[-1], columns[0:-1]
tempX.reindex(columns=columns)

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

Но что, если миллисекунды и мегабайты имеют значение? Продолжай читать.

4. Подробности

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

Методология

Я использовал Pandas DataFrame и массив NumPy со случайно инициализированными переменными (100_000, 100).
Чтобы Python не кэшировал массивы и матрицы, я запустил и замерил время каждого метода отдельно и изолированно. Функция base() была создана для инициализации и расчета постоянного использования памяти набора данных и столбца перехвата. Кроме того, использование базовой памяти использовалось для проверки того, какие переменные кэшируются.
Все методы перехвата были помещены в функцию, которая была обернута в профилировщик памяти для измерения добавочного использования данных. Использование памяти ниже было рассчитано с помощью декоратора профилировщика.
Для определения времени каждой функции я создал декоратор времени, который перебирал каждый метод перехвата, вычислял прошедшее время и регистрировал результаты.

Результаты

Вот несколько вещей, которые я заметил:

  • Разница в использовании исходных данных между Pandas и NumPy была незначительной.
  • np.array имел меньшие начальные накладные расходы и работал быстрее на упомянутых методах, за исключением np.concatenate, с 10 итерациями.
  • Удивительно, но второй метод, использующий pd.concat, оказался наиболее эффективным с точки зрения использования памяти методом с использованием только 323,9 МБ оперативной памяти. Казалось, что указатели объединяются в возвращенный DataFrame вместо выделения нового места для копии. К сожалению, это заняло больше всего времени, в 2–5 раз больше времени по сравнению с np.concatenate.
  • Самый быстрый методзависил от итераций. С 10 итерациями np.concatenate, np.hstack и np.insert связаны с 0,097 секунды. При 100 итерациях методы конкатенации NumPy (3, 4, 5) раз имели трехстороннюю связь ± 1%.
  • Если вы хотите, чтобы на выходе был DataFrame, седьмой метод со вставкой и переиндексацией был на удивление быстрым: 0,801 секунды для 100 итераций и 0,130 секунды для 10 итераций. В противном случае np.concatenate был стабильно быстрым для обоих типов наборов данных.

Заключение

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

Я знаю, что буду использовать только тот, который я помню.

Спасибо за чтение! Не стесняйтесь проверить код здесь!