Мой опыт создания, обработки и машинного обучения неструктурированных данных для принятия инвестиционных решений

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

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

Мы делаем это в масштабе с малой задержкой (почти в реальном времени). Мы создали более 90 миллионов уникальных поисковых точек данных и более 1 терабайта данных, извлекая наиболее важные документы из каждой компании в SEC на всех 3 основных биржах США, и делаем это каждый час каждого дня. Скорее, наша технология делает это за нас.

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

Шаг 1. Обработка данных

Я часто слышал, что при работе с данными 80–90% работы составляет их перебор или «обработка данных». Я полностью согласен с этим и убеждаюсь в этом снова и снова в своих проектах данных.

Почему это требует столько усилий? Вы должны обратить внимание на все эти вещи:

  • Сбор данных (поиск хороших источников данных, точная оценка качества и таксономии данных, получение и определение меток). Мы разработали собственные данные из SEC. Данные, которые мы получаем оттуда, требуют большого внимания, они довольно беспорядочны. Мы попробовали множество наборов данных и в итоге создали большую часть наших собственных данных, за исключением некоторых фундаментальных данных.
  • Предварительная обработка данных (вменение отсутствующих данных, проектирование признаков, увеличение данных, нормализация данных, разделение перекрестной проверки)
  • Постобработка данных (предоставление возможности использования выходных данных модели, очистка артефактов, обработка особых случаев и выбросов)
  • (H/T Эммануэлю Амайзену за его описание этих категорий, которые уместны)

Шаг 2. Настройка/конвейерная обработка

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

Например, мы передаем аргументы в Perform_async, которые могут состоять из простых типов данных JSON: строка, целое число, число с плавающей запятой, логическое значение, ноль, массив и хэш. У нас есть клиентский API Sidekiq, использующий JSON.dump для отправки данных в Redis. Сервер Sidekiq извлекает эти данные JSON из Redis и использует JSON.load для преобразования данных обратно в типы Ruby для передачи в метод execute.

if ft.complete_html.blank? && ft.plain_text.blank?
  PopulateFilingTextJob.perform_async ft.sec_filing_id

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

Шаг 3. Машинное обучение данных

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

Теперь, когда мы здесь (вытираем бровь), давайте изучим данные…

В этом случае я получил доступ к созданному нами набору данных через нашу собственную корзину S3 на AWS. Мы создали набор данных, который включает в себя только информацию из данных и идентификационные данные и оставляет первоначальные данные создания позади. Это хорошо работает.

Я делаю это с помощью Scikit-Learn, поэтому начну с настройки библиотек и модулей, включая то, что мне нужно для обнаружения выбросов:

# Setup for Outlier Detection
import numpy as np
import pandas as pd
from scipy import stats
import matplotlib.pyplot as plt
import matplotlib.font_manager

from sklearn import svm
from sklearn.covariance import EllipticEnvelope
from sklearn.ensemble import IsolationForest
from sklearn.neighbors import LocalOutlierFactor

print(__doc__)

rng = np.random.RandomState(42)

Затем я просто установлю указатель для просмотра моего набора данных в корзине AWS S3, о которой я упоминал:

# 2) Load the data from the remote url via an AWS S3 bucket

dataset_url = 'https://s3.amazonaws.com/your-url-goes-here.csv'
data = pd.read_csv(dataset_url)

Для начала давайте удостоверимся, что у нас есть доступ к этим данным. Попробуем получить первые 5 строк:

print data.head()

Затем давайте посмотрим на форму этих данных:

print data.shape

Это дает нам:

(107119, 6)

Итак, теперь мы знаем, что существует более 107 тысяч строк и 6 столбцов. Это приличный объем данных для начала.

Далее давайте получим сводную статистику по этим данным:

print data.describe()

id
count 107119.000000
mean 120881.355530
std 71456.683309
min 11.000000
25% 60048.500000
50% 116449.0000000
95% макс 251076.000000

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

Теперь, после всего этого, все становится более захватывающим (наконец-то)!

Я начал больше исследовать эти данные, просматривая графики выбросов.

Это выполняет четыре различных типа обнаружения новинок и выбросов:

* На основе надежной оценки ковариации, которая предполагает, что данные распределены по Гауссу, и в этом случае работает лучше, чем SVM одного класса.

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

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

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

Источник: документация Scikit-Learn.

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

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