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

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

  • Словари, в которых мы получаем доступ к данным через ключи (или имена)
  • Списки, в которых мы получаем доступ к данным, ища соответствующие индексы

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

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

Здесь на помощь приходят именованные кортежи. Они предлагают возможность доступа к элементам по имени или индексу. Они также неизменяемы, поэтому вы можете быть уверены, что по мере того, как вещи движутся по вашему конвейеру, они не игнорируются и не изменяются. Хорошо, если вы не назначили внутренний список (что означает, что кортеж хранит ссылку на список, поэтому вы можете изменить список), но не будем здесь идти.

Да и что насчет использования словаря и добавления ключей по ходу дела? Что ж, вам нужно будет определить здесь всю структуру для именованного кортежа. Но опять же, если вы добавляете структуру данных по мере ее прохождения по конвейеру, то вы, вероятно, не делаете свой код читаемым для других, и вам следует подумать о том, чтобы этого не делать. Кроме того, вы всегда можете использовать эти именованные кортежи для возврата данных из функций в удобном для понимания и удобном виде, а также для повышения читабельности. Это важно, поскольку вы обнаружите, что читаете код чаще, чем пишете его (некоторые цитируют в 10 раз больше), а в большой группе специалистов по анализу данных нет ничего хуже, чем наследовать чужой код и не понимать, почему это происходит. передаются функциям.

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

Давайте создадим именованный кортеж

# Import the modules
from collections import namedtuple
# Define our named-tuple structure
myfirsttuple = namedtuple('myfirsttuple','first second last')

Теперь мы создали наш кортеж с первым именем. В первой части мы назвали его «моя первая семья». Вы заметите, что это имя совпадает с именем переменной, которой мы назначаем результат «namedtuple». Это должно совпадать, и это частая ошибка, с которой люди сталкиваются, когда что-то меняют, а они не совпадают, что приводит к ошибкам позже.

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

# Alternate way to define
list_of_names = ['first', 'second', 'last']
myfirsttuple = namedtuple('myfirsttuple',list_of_names)

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

# Create an instance of myfirsttuple
instance = myfirsttuple(first=1,second=2,last='End')
instance

Имя «экземпляр» совершенно произвольно, но вы увидите, что для его создания мы присвоили значения каждому из трех имен, которые мы определили ранее. Мы можем назначить им все, что захотим, может быть с плавающей запятой, целым числом, списком, словарем, моделью машинного обучения и т. Д.

Теперь мы можем получить доступ к этим значениям, как и к обычному кортежу:

# Access the third element
instance[2]
>>> 'End'

Мы также можем получить к нему доступ через имя, используя «.»:

# Access the third element by name
instance.last
>>> 'End'

Точно такой же результат.

Почему нас это волнует?

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

  • Они «самоопределяются». Их структура именования помогает идентифицировать участников
  • Атрибуты в именованном кортеже неизменяемы, как и обычные кортежи.
  • Они используют меньше памяти, чем словарь
  • Они обратно совместимы с обычными кортежами (доступ с помощью индексов).
  • При необходимости вы можете преобразовать их в словари.

Некоторые люди утверждают, что они также более элегантны / красивы / читабельны, чем другие решения, но я оставляю это вам решать.

Зачем использовать их в машинном обучении?

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

Неизменяемая часть также может быть очень полезной, если вы передаете переменные, и вы хотите быть в безопасности, зная, что никто не возится с ними (хотя я бы хотел предупредить, что вы можете обойти это, как вы, возможно, обнаружили, если когда-либо изменяли элементы списка, содержащегося в кортеже).

Я полагаю, что это могло бы помочь, если бы действительно был его пример в действии.

Хороший пример

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

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

Я работал над этим, используя именованные кортежи для передачи этих переменных по мере необходимости. Я также использовал именованные кортежи с моими моделями, поскольку я мог получить доступ к модели под именем «модель», я мог посмотреть время создания, используемые столбцы, производительность, полученную при перекрестной проверке во время обучения, агрегирование времени и т. Д. У меня был компактный портативный способ для всех, кто загружает мою модель, чтобы увидеть, что я создал и как (и чтобы мой код вывода, работающий на оборудовании для развертывания, тоже знал об этом). Это если правильно сохранить.

Маринование может быть рассолом

Итак, вы можете выделить именованный кортеж. Лучший способ - определить ваш именованный кортеж одинаково как в коде, который содержит травление, так и в коде, который открепляет. Но если вы не знаете, как это будет выглядеть, вы можете использовать другую ключевую часть, о которой я упоминал ранее, и просто преобразовать названный вами кортеж в словарь и обработать его.

Пример кода травления:

# Modules to Import
import joblib
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification
from collections import namedtuple
# Define our named tuple for out model
model_details = namedtuple('model_details',['model','x','y'])
# Code for creating dummy data and training a model
x, y = make_classification(n_samples=100, n_features=2,
                            n_informative=2, n_redundant=0,
                            random_state=0, shuffle=False)
model = RandomForestClassifier(max_depth=2, random_state=0)
model.fit(x, y)
# Save our model to pickle
# Name to save the model to
model_name = 'pickled_model.joblib'
# Create out named tuple instance, storing the training data in it
out_model = model_details(model=model,x=x,y=y)
# Convert to dictionary and save to joblib
joblib.dump(dict(out_model._asdict()),model_name)

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

Другая часть, которую я сделал, - преобразовала его в словарь. Я обернул его в dict (), потому что если вы запустите тип в «out_model», он вернет «OrderedDict». Протолкнув его через dict (), мы получим настоящий словарь (по крайней мере, когда мы проверяем тип).

Чтобы вернуть нашу модель, мы можем запустить следующее:

Пример кода для отмены травления:

import joblib
# from collections import namedtuple
from types import SimpleNamespace
# Load the model
model_name = 'pickled_model.joblib'
model = SimpleNamespace(**joblib.load(model_name))
print(model)
>>> namespace(model=RandomForestClassifier(max_depth=2, random_state=0), x=array([[ 4.22341441e-01, -2.05321581e+00],...

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

import joblib
from collections import namedtuple
# Load the model
model_name = 'pickled_model.joblib'
model = joblib.load(model_name)
print(model)
>>> model_details(model=RandomForestClassifier(max_depth=2, random_state=0), x=array([[ 4.22341441e-01, -2.05321581e+00],...

Вуаля! Я сохранил и извлек модель, к которой прикрепил дополнительные детали. Я мог бы сделать это просто со словарем (или загрузить его вместе с файлом csv), но таким образом детали будут прикреплены и неизменны.

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

Резюме

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

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

На этом пока все, и я надеюсь скоро поговорить со всеми вами!