Руководство по кодированию и инженерным функциям даты и времени
Пояснение: на изображении показана дата, а также на человеке надеты наручные часы, которые показывают время, отсюда и изображение!
вступление
Давайте начнем с того, что проясним некоторые вещи. Прежде всего, дата, время и дата-время не совпадают. Pandas имеет только тип даты и времени, в котором каждая ячейка является объектом pandas Timestamp
. В пандах, если вы преобразуете столбец, содержащий только дату, в дату и время, то по умолчанию часть «время» будет 00:00
, но вам следует избегать использования части времени по очевидным причинам. При работе со столбцами, содержащими только время, есть еще одно «следите за», скажем, 11:00
Перед ним будет стоять текущая дата!
Как видите, дата, представленная в виде строки, была преобразована в Timestamp
с 00:00:00
временем, а текущая дата (дата выполнения кода) была добавлена к времени одиночества.
Учитывая текущую дату, которая автоматически добавляется как часть исходных данных, это приведет к огромным проблемам.
Имея это в виду, давайте перейдем к созданию функций из них.
Разработка функций для даты, времени и переменных даты и времени
В этом разделе мы создадим несколько функций из доступных столбцов, создав GenProcessor для каждого типа данных.
Технические даты
Для простоты мы будем генерировать следующие функции из даты: день, месяц, год, день недели, квартал и независимо от того, является ли это выходным.
Мы собираемся предположить, что только правильная дата будет передана.
Давайте начнем с определения нашего пользовательского преобразователя sklearn.
Мы создадим класс, который будет наследоваться от BaseEstimator
и TransformerMixin
, среди прочего, он дает нам сгенерированный метод fit_transform
, который, как следует из названия, вызывает метод fit
, а затем метод transform
. Также отметим, что сгенерированные функции будут масштабироваться до диапазона [0,1], когда это уместно.
Некоторые константы и довольно простой метод подгонки
Логика трансформации высокого уровня
Здесь следует отметить несколько вещей. Как и любой хороший разработчик, мы разбиваем отдельные задачи на методы экземпляра. Мы используем защищенные методы, а не частные методы, потому что позже мы собираемся создать подкласс этого класса. Кроме того, мы транспонируем каждый кадр данных перед конкатенацией, а затем снова транспонируем, чтобы ускорить процесс конкатенации. Давайте реализуем методы экземпляра.
Мы будем следовать примерно такому же формату. Метод apply
применяет переданную функцию к каждой серии нашего фрейма данных. Как упоминалось в начале, мы предполагаем, что только подмножество данных, имеющих столбцы даты (в виде строк), будет передано нашему преобразователю, в основном с использованием ColumnTransformer
. После извлечения требуемого атрибута мы добавим требуемый суффикс ко всем именам столбцов. И последнее, но не менее важное, поскольку в месяце от максимума до максимума 31 день, а в году 12 месяцев, мы делим день и месяц на 31 и 12 соответственно. Мы могли бы масштабировать год, но это работа масштабатора, учитывая, что нет определенных минимальных и максимальных границ, как для дня и месяца. Реализуем оставшиеся методы.
- Поскольку день недели находится в диапазоне от 0 до 6, для его масштабирования мы делим на 6
- Поскольку четвертей 4, то есть от 0 до 3, для масштабирования делим на 3.
- Так как день недели 0 представляет собой понедельник, дни недели 5 и 6 являются выходными.
Чтобы получить0
/1
вместоFalse
/True
, мы преобразуем логический результат в целое число.
Теперь давайте обратим наше внимание на создание функций вне времени.
Инженерные времена
Как видите, мы разделим время на утро, день, вечер и ночь. Мы также будем извлекать час.
Бонус: такое преобразование не сохраняет циклический характер значений, чтобы сохранить их, вы можете использовать
CyclicalTrasnformer
, использующий синус и косинус.
Снова некоторые константы и очень простой метод подгонки,
Метод преобразования
Придерживаясь стиля кода, который мы использовали для дат, мы делегируем ответственность за создание отдельных функций другим методам. Давайте посмотрим на наш частный метод __get_period
.
Чтобы преобразовать наш объект time
в целое число, представляющее время в двадцать четыре часа, мы используем быстрый прием умножения часа на 100, чтобы сдвинуть его на 2 десятичных знака влево и добавить к нему минуты (минуты). Как видите, вместо того, чтобы использовать and
в условном выражении, мы написали его так, как сделал бы любой математик. Потому что наука о данных — ничто без математики.
Дата разработки Время
Теперь обратим внимание на дату и время. Честно говоря, благодаря защищенным методам, определенным в DateGenProcessor
и TimeGenProcessor
, делать особо нечего. Давайте идти!
Мы просто наследуем наши DateGenProcessor
и TimeGenProcessor
. Давайте реализуем метод подгонки и преобразования.
Нет ничего такого, чего бы мы не видели до сих пор.
Самоанализ: мы могли бы использовать композицию вместо наследования, попробуйте сами!
Вот весь код, связанный с разработкой функций, для справки (не забывайте, что ниже сути есть кодирование).
Ненадолго оторвитесь от экрана!
Кодирование даты, времени и переменных даты и времени
В этом разделе мы закодируем переменные таким образом, чтобы их можно было передать в модели мл. Здесь мы также создадим пользовательский преобразователь sklearn для каждого типа данных.
Даты кодирования
Мы будем представлять даты как разницу между датой, которую нужно закодировать, и самой ранней датой, присутствующей в фазе fit
. При этом минимальное закодированное значение будет равно 0, следовательно, мы будем кодировать отсутствующие значения как -1.
Логика подгонки
Чтобы выполнить преобразование, а также обратное преобразование, нам понадобится минимальная дата в каждой функции.
Логика трансформации
Поскольку min_dates
— это фрейм данных, мы можем напрямую вычесть его из фрейма данных, который нужно преобразовать. Нам не нужно беспокоиться о нулях при вычитании, потому что объект pd.Timestamp
минус None
есть не что иное, как None
.
Вычитание даст нам фрейм данных, заполненный pandas.Timedelta
объектами. Затем мы извлечем атрибут days
, если значение не равно нулю, если да, то заполним его значением -1. Метод applymap
кадра данных pandas применяет переданную функцию к каждому элементу каждой серии. Это перестановка метода apply
, который применяет функцию к каждой серии фрейма данных, и метода map
, который применяет функцию к каждому элементу. серии.
Логика обратного преобразования
Обратное преобразование — это не что иное, как операция обращения/отмены преобразованных данных. Поскольку мы знаем, что целые числа имеют единицу «дни», мы сначала преобразуем их в объекты pandas Timedelta и просто добавляем количество дней к сохраненным минимальным датам. Наконец, поскольку после выполнения этой операции мы получим ряд даты и времени, мы берем только часть даты.
Бонус: тестирование нашего собственного трансформатора
Давайте быстро напишем модульные тесты для нашего пользовательского преобразователя.
Подготовка тестовых данных
Начнем с создания повторно используемого метода, который возвращает исходные данные. Чтобы убедиться, что мы правильно обрабатываем пустые значения, мы намеренно сохраняем один элемент None
.
Проверка логики преобразования
Мы инициализируем наш кодировщик, подгоняем его к тестовым данным, а также преобразуем тестовые данные. Вот что мы тестируем:
- Форма данных остается неизменной, поскольку мы выполняем преобразование на месте.
- Поскольку 2-й элемент (индекс 1) в данных тестирования является самой низкой датой, он был закодирован как 0.
- Поскольку 1-й элемент опережает минимальную дату на 2 дня, он был правильно закодирован как 2 (14 — 12)
- Нуль был закодирован как -1
Имейте в виду, что когда вы тестируете свой конвейер или делаете прогнозы на невидимых данных, вы должны преобразовывать невидимые данные только с помощью кодировщика, установленного на обучающих данных.
В качестве примечания: когда вы разрабатываете, следуя принципам TDD (разработка через тестирование), написание модульных тестов, чтобы убедиться, что вы получаете ожидаемый результат до написания фактического преобразователя, будет для вас чрезвычайно полезным. так как у вас будет ясность в отношении конкретной проблемы, которую вам нужно решить; ни больше, ни меньше, а также сокращение времени отладки.
Тестирование логики обратного преобразования
Здесь мы сначала преобразуем наши исходные данные, а затем выполняем обратное преобразование преобразованных данных. А затем мы проверяем, получаем ли мы исходную дату по индексу 1, которая была закодирована (как показано выше) как 2. Давайте теперь перейдем к кодированию времени и времени, функциям даты и времени.
Время кодирования
Мы преобразуем объекты datetime.time
в целое число, представляющее время в 24-часовом формате, а затем разделим его на 2359
, максимально возможное целое число, представляющее 23:59. для того, чтобы масштабировать, а также. Мы выполняем масштабирование внутри кодировщика и не сохраняем его для масштабатора, поскольку существует определенная максимальная граница (2359), о которой масштабатор не знает. Хотя мы можем отслеживать этот столбец в закодированном времени и использовать его, чтобы решить, как масштабирование должно быть выполнено позже, но это выходит за рамки этой статьи, давайте не будем усложнять.
Подходящая логика
Подгонки не к чему, так как преобразование, как и обратное преобразование, не зависит от обучающих данных.
Логика преобразования и обратного преобразования
Подобно логике, используемой при генерации признаков из столбцов времени, мы сдвигаем час на два десятичных знака влево и добавляем к нему минуты, чтобы получить военное время, и, наконец, делим на 2359.
Для обратного преобразования мы обратить вспять процесс трансформации. Так как мы разделили на 2359 в качестве последнего шага, мы сначала умножаем закодированное время на 2359. Затем, чтобы получить доступ к двум крайним левым цифрам, мы делим на 100 (и берем целую часть), чтобы получить доступ к двум крайним правым цифрам, мы берем по модулю ( и взять целую часть). Мы также заботимся о нулях. Если вы находите это запутанным, взгляните на приведенный ниже фрагмент кода, который я написал при написании модульных тестов.
Кодирование Дата Время
Давайте подведем итоги, закодировав дату и время. Мы будем использовать ту же стратегию, что и для кодирования дат. Единственное отличие состоит в том, что вместо кодирования разницы в днях мы будем хранить разницу в минутах.
Подходящая логика
Подобно тому, как мы кодировали даты, мы сохраняем минимальное значение даты и времени для каждой серии.
Логика преобразования и обратного преобразования
Во время преобразования мы вычитаем фрейм данных, который нужно преобразовать, на сохраненные минимальные значения даты и времени. Теперь, поскольку в объекте pandas.Timedelta
нет атрибута minute
, мы делим total_seconds
на 60.
Во время обратного преобразования мы просто конвертируем значение в минуты, указав unit = "m"
при преобразовании целочисленного значения в объект pandas.Timedelta
. Вот весь код, связанный с кодировкой для справки,
Поздравляю с тем, что дочитали до этого места, надеюсь, вам понравилось читать и учиться.
Знаете ли вы, что на кнопке со значком «Хлопки» разработчики также указали обратный вызов onLongPress
вместе с обратным вызовом onPress
? Попробуйте!
Вы можете связаться со мной на Linkedin susmit-vengurlekar или написать мне по электронной почте [email protected]. Вы можете увидеть, чем я занимаюсь, на Github susmit.py
Интересуетесь инженерией данных? Вы находитесь в правильном месте! Следите за открытыми вакансиями в Zeza Tech