Этот проект по науке о данных направлен на построение модели AI / ML для прогнозирования динамики цен акций за 52 недели на основе финансовых данных, экстраполированных из списка компаний S&P 500. Данные исследуются, визуализируются и обрабатываются. Затем реализуется и уточняется регрессия опорных векторов (SVR). Наконец, результаты приводятся вместе с заключением.

Трудно точно предсказать динамику цены акции за 52 недели. Финансовые эксперты используют определенные критерии для прогнозирования результатов деятельности, но этот навык является неявным и трудным для освоения. Этот проект будет направлен на то, чтобы научить машину делать прогнозы с точностью 70% +. Набор данных собран с сайта Fidelity.com. Если у вас есть учетная запись в Fidelity, вы можете извлечь данные из их опции экрана, используя их опцию «скачать в Excel».

Постановка задачи

  • Машины не знают, как точно предсказать динамику цены акции. Этот проект демонстрирует стратегию решения проблемы с помощью машины опорных векторов (SVM). После того, как модель будет обучена и протестирована, она сможет предоставить решение, которое может прогнозировать динамику цены акций за 52 недели с точностью 73%.

Метрики

  • Мы использовали регрессионную форму SVM, известную как SVR (регрессия опорных векторов). Метрика, используемая для измерения эффективности модели SVR, - это оценка R2. Чем ближе оценка к 1, тем точнее модель. Оценка около 0,7 или выше считается приемлемой, чтобы считать модель надежной. Мы выбрали эту модель и метрику, потому что нам нужна высокая точность для прогнозирования фондового рынка, и мы не можем позволить себе 50/50% шанс для такой важной темы, которая связана с финансовыми разветвлениями.

В этом проекте используются библиотеки Python: numpy, pandas, math, matplotlib, collections и sklearn.

Исследование данных

Переменные / характеристики набора данных отображались с помощью функции info (). Исходный набор данных содержал 22 столбца (функции) и 500 строк данных. Переменные / функции были следующими:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 500 entries, 0 to 499
Data columns (total 22 columns):
Symbol                                             500 non-null object
Company_Name                                       500 non-null object
Security_Price                                     500 non-null float64
Volume__90_Day_Avg_                                500 non-null float64
Market_Capitalization                              500 non-null object
Dividend_Yield                                     418 non-null float64
Company_Headquarters_Location                      500 non-null object
Sector                                             500 non-null object
Industry                                           500 non-null object
Price_Performance__52_Weeks_                       500 non-null float64
Total_Return__1_Yr_Annualized_                     500 non-null float64
Beta__1_Year_Annualized_                           499 non-null float64
Standard_Deviation__1_Yr_Annualized_               500 non-null float64
S&P_Global_Market_Intelligence_Valuation           498 non-null float64
S&P_Global_Market_Intelligence_Quality             498 non-null float64
S&P_Global_Market_Intelligence_Growth_Stability    498 non-null float64
S&P_Global_Market_Intelligence_Financial_Health    497 non-null float64
P/E__Price/TTM_Earnings_                           500 non-null object
PEG_Ratio                                          406 non-null float64
EPS_Growth__Proj_This_Yr_vs._Last_Yr_              486 non-null float64
Institutional_Ownership                            487 non-null float64
Institutional_Ownership__Last_vs._Prior_Qtr_       498 non-null float64
dtypes: float64(15), object(7)

Мы очистили набор данных, удалив все значения NAN. На этапе исследования данных мы использовали функцию describe () для отображения описательной статистики набора данных. После этого мы искали корреляции между различными функциями, используя функцию corr (). Затем мы визуализировали данные, разбив акции по секторам, создав функцию graphS (), которая выглядит следующим образом:

# Использование функции графика для лучшего понимания данных путем разбивки запасов индекса S&P 500 по промышленным секторам
def graphS ():
ps = df.Sector.value_counts ()
(ps / df.shape [0]). plot (kind = «bar»);
plt.title («Sector»)
«» »Эта функция 'graphS ()' построит график акции в S% P 500 по секторам ”” ”
graphS ()

Предварительная обработка данных

Проанализировав 22 функции, мы определили, что многие из них не являются числовыми и их необходимо удалить. Мы использовали функцию drop (), чтобы удалить все нечисловые функции. Мы также использовали функцию fillna () для заполнения всех значений NAN. Мы заметили, что функция Dividend Yield имеет наибольшее количество значений NAN на основе исследования данных, поэтому мы отбросили все значения NAN для этой функции, которая одновременно отбросила все значения NAN в наборе данных. Мы разделили набор данных на два набора. Данные, которые содержат все независимые переменные и наблюдения, и Target, содержащие зависимую переменную (Ценовые характеристики) и ее варианты. Информация об очищенном фрейме данных отображается ниже:

<class 'pandas.core.frame.DataFrame'>
Int64Index: 389 entries, 0 to 499
Data columns (total 13 columns):
Security_Price                                     389 non-null float64
Volume__90_Day_Avg_                                389 non-null float64
Dividend_Yield                                     389 non-null float64
Beta__1_Year_Annualized_                           389 non-null float64
Standard_Deviation__1_Yr_Annualized_               389 non-null float64
S&P_Global_Market_Intelligence_Valuation           389 non-null float64
S&P_Global_Market_Intelligence_Quality             389 non-null float64
S&P_Global_Market_Intelligence_Growth_Stability    389 non-null float64
S&P_Global_Market_Intelligence_Financial_Health    389 non-null float64
PEG_Ratio                                          389 non-null float64
EPS_Growth__Proj_This_Yr_vs._Last_Yr_              389 non-null float64
Institutional_Ownership                            389 non-null float64
Institutional_Ownership__Last_vs._Prior_Qtr_       389 non-null float64
dtypes: float64(13)

После разработки функций мы использовали matplotlib для отображения распределения каждой функции, чтобы увидеть, нормально ли распределяются данные. Код, который использовался, был следующим (мы изменили номер столбца для каждой функции), и все распределения показаны ниже:

cols = final_df.columns [: 1]
densityplot = final_df [cols] .plot (kind = ’density’)

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

normalized_df = (final_df-final_df.min ()) / (final_df.max () - final_df.min ()).

Реализация

Прежде чем выбрать алгоритм / модель ML, мы просмотрели следующую шпаргалку, чтобы выбрать правильную модель для этой проблемы (получена с веб-сайта Scikit Learn):

Поскольку мы не пытаемся классифицировать или кластеризовать, все модели в левой части диаграммы исключаются. Мы стремимся определить количество (ценовые характеристики) акций на основе различных характеристик (переменных). Следовательно, наша проблема требует регрессионной модели. Поскольку у нас меньше 100 тыс. Выборок, также исключается SDG Regressor - поскольку наличие небольшого количества функций не важно, также исключаются алгоритмы Lasso и ElasticNet. Таким образом, остается SVR и RidgeRegression. В этом случае мы решили использовать SVR (регрессия вектора поддержки).

Используя функцию train, test, split в библиотеке scikit learn, данные были разделены на обучающий набор и набор для тестирования, был использован приведенный ниже код:

# Разделение данных на обучение и тестирование
X_train, X_test, y_train, y_test = train_test_split (data, target,
test_size = 0.3,
random_state = 0)
масштабирование = MinMaxScaler (feature_range = (- 1, 1)). Fit (X_train)
X_tr = scaling.transform (X_train)
X_t = scaling.transform (X_test)

Затем модель SVR была реализована с использованием следующего кода:

# Реализация модели
svr = SVR ()
search_space = [{'kernel': ['linear'],
'C': np.logspace (-3, 2 , 6),
'epsilon': [0, 0,01, 0,1, 0,5, 1, 2, 4]},
{'ядро': ['rbf'],
'градус ': [2,3],
' C ': np.logspace (-3, 3, 7),
' gamma ': np.logspace (-3, 2, 6),
'epsilon': [0, 0,01, 0,1, 0,5, 1, 2, 4]}]
gridsearch = GridSearchCV (svr,
param_grid = search_space,
refit = True, < br /> scoring = 'r2',
cv = 10, n_jobs = -1)
gridsearch.fit (X_tr, y_train)
cv = gridsearch.best_score_
test_score = gridsearch .score (X_tr, y_train)
print ('Оценка CV R2:% 0,3f'% cv)
print ('Оценка теста R2:% 0,3f'% test_score)
print (' Лучшие параметры:% s '% gridsearch.best_params_)

Затем мы создали модель прогнозирования машинного обучения, используя SVM со следующим кодом:

# Создание прогнозной модели
model = SVR ()
print (model)
X = data
y = target
# Подбор модели
model.fit (X, y)
# Создание модели прогноза
pred_y = model.predict (X)
# Показать прогноз
pred_y

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

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

Полученные результаты

Результат был следующим:

CV R2 score: 0.628
Test R2 score: 0.735
Best parameters: {'C': 1.0, 'degree': 2, 'epsilon': 0.1, 'gamma': 0.1, 'kernel': 'rbf'}

Результаты показали, что R2 составляет 0,735, что свидетельствует о высокой точности, которой мы довольны.

Заключение

Отражение

Мы начали с попытки найти способы решить проблему. Я многое узнал о выборе правильного алгоритма и узнал о многих существующих вариантах. Самые сложные части этого проекта были двоякими. 1. Обнаружив данные, мы сначала попытались построить конвейер ETL, используя API для удаления веб-страниц yahoo, но безуспешно. Я узнал, что извлечение данных и построение конвейеров ETL - самая сложная часть науки о данных, что заставляет меня еще больше узнать об инженерии данных. Я также узнал, что существует множество API-интерфейсов из многих источников, и некоторым из них требуется партнерство с провайдером, чтобы предоставить доступ к своим данным. Я обнаружил, что только у Google есть сотни и сотни API, которые пройдут полный семестровый курс только для того, чтобы изучить некоторые из них. Вторая часть заключалась в разработке функций, чтобы найти наиболее подходящие функции, которые сделают точный прогноз.

Улучшение

Этот проект можно улучшить / расширить с помощью конвейера ETL, который может автоматически извлекать данные с помощью кнопки обновления с финансового веб-сайта. Его также можно улучшить, создав приложение, которое позволяет пользователям вводить тикер акций и получать результат прогноза динамики цен на 52 недели той конкретной акции, которую они искали.