Spec-Zone.ru › scikit-learn

Примечание

Перейти в конец, чтобы скачать полный код примера или запустить этот пример в браузере с помощью JupyterLite или Binder.

Визуализация структуры фондового рынка

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

Используемая нами величина — дневное изменение цены котировки: связанные котировки, как правило, меняются в течение дня согласованно друг с другом.

# Authors: The scikit-learn developers
# SPDX-License-Identifier: BSD-3-Clause

Получение данных из Интернета

Данные охватывают период с 2003 по 2008 год. Это достаточно спокойный период: он не настолько давний, чтобы в выборке не было высокотехнологичных компаний, и предшествует обвалу 2008 года. Такие исторические данные можно получить с помощью API, например data.nasdaq.com и alphavantage.co.

import sys

import numpy as np
import pandas as pd

symbol_dict = {
    "TOT": "Total",
    "XOM": "Exxon",
    "CVX": "Chevron",
    "COP": "ConocoPhillips",
    "VLO": "Valero Energy",
    "MSFT": "Microsoft",
    "IBM": "IBM",
    "TWX": "Time Warner",
    "CMCSA": "Comcast",
    "CVC": "Cablevision",
    "YHOO": "Yahoo",
    "DELL": "Dell",
    "HPQ": "HP",
    "AMZN": "Amazon",
    "TM": "Toyota",
    "CAJ": "Canon",
    "SNE": "Sony",
    "F": "Ford",
    "HMC": "Honda",
    "NAV": "Navistar",
    "NOC": "Northrop Grumman",
    "BA": "Boeing",
    "KO": "Coca Cola",
    "MMM": "3M",
    "MCD": "McDonald's",
    "PEP": "Pepsi",
    "K": "Kellogg",
    "UN": "Unilever",
    "MAR": "Marriott",
    "PG": "Procter Gamble",
    "CL": "Colgate-Palmolive",
    "GE": "General Electrics",
    "WFC": "Wells Fargo",
    "JPM": "JPMorgan Chase",
    "AIG": "AIG",
    "AXP": "American express",
    "BAC": "Bank of America",
    "GS": "Goldman Sachs",
    "AAPL": "Apple",
    "SAP": "SAP",
    "CSCO": "Cisco",
    "TXN": "Texas Instruments",
    "XRX": "Xerox",
    "WMT": "Wal-Mart",
    "HD": "Home Depot",
    "GSK": "GlaxoSmithKline",
    "PFE": "Pfizer",
    "SNY": "Sanofi-Aventis",
    "NVS": "Novartis",
    "KMB": "Kimberly-Clark",
    "R": "Ryder",
    "GD": "General Dynamics",
    "RTN": "Raytheon",
    "CVS": "CVS",
    "CAT": "Caterpillar",
    "DD": "DuPont de Nemours",
}


symbols, names = np.array(sorted(symbol_dict.items())).T

quotes = []

for symbol in symbols:
    print("Fetching quote history for %r" % symbol, file=sys.stderr)
    url = (
        "https://raw.githubusercontent.com/scikit-learn/examples-data/"
        "master/financial-data/{}.csv"
    )
    quotes.append(pd.read_csv(url.format(symbol)))

close_prices = np.vstack([q["close"] for q in quotes])
open_prices = np.vstack([q["open"] for q in quotes])

# The daily variations of the quotes are what carry the most information
variation = close_prices - open_prices
Fetching quote history for np.str_('AAPL')
Fetching quote history for np.str_('AIG')
Fetching quote history for np.str_('AMZN')
Fetching quote history for np.str_('AXP')
Fetching quote history for np.str_('BA')
Fetching quote history for np.str_('BAC')
Fetching quote history for np.str_('CAJ')
Fetching quote history for np.str_('CAT')
Fetching quote history for np.str_('CL')
Fetching quote history for np.str_('CMCSA')
Fetching quote history for np.str_('COP')
Fetching quote history for np.str_('CSCO')
Fetching quote history for np.str_('CVC')
Fetching quote history for np.str_('CVS')
Fetching quote history for np.str_('CVX')
Fetching quote history for np.str_('DD')
Fetching quote history for np.str_('DELL')
Fetching quote history for np.str_('F')
Fetching quote history for np.str_('GD')
Fetching quote history for np.str_('GE')
Fetching quote history for np.str_('GS')
Fetching quote history for np.str_('GSK')
Fetching quote history for np.str_('HD')
Fetching quote history for np.str_('HMC')
Fetching quote history for np.str_('HPQ')
Fetching quote history for np.str_('IBM')
Fetching quote history for np.str_('JPM')
Fetching quote history for np.str_('K')
Fetching quote history for np.str_('KMB')
Fetching quote history for np.str_('KO')
Fetching quote history for np.str_('MAR')
Fetching quote history for np.str_('MCD')
Fetching quote history for np.str_('MMM')
Fetching quote history for np.str_('MSFT')
Fetching quote history for np.str_('NAV')
Fetching quote history for np.str_('NOC')
Fetching quote history for np.str_('NVS')
Fetching quote history for np.str_('PEP')
Fetching quote history for np.str_('PFE')
Fetching quote history for np.str_('PG')
Fetching quote history for np.str_('R')
Fetching quote history for np.str_('RTN')
Fetching quote history for np.str_('SAP')
Fetching quote history for np.str_('SNE')
Fetching quote history for np.str_('SNY')
Fetching quote history for np.str_('TM')
Fetching quote history for np.str_('TOT')
Fetching quote history for np.str_('TWX')
Fetching quote history for np.str_('TXN')
Fetching quote history for np.str_('UN')
Fetching quote history for np.str_('VLO')
Fetching quote history for np.str_('WFC')
Fetching quote history for np.str_('WMT')
Fetching quote history for np.str_('XOM')
Fetching quote history for np.str_('XRX')
Fetching quote history for np.str_('YHOO')

Обучение структуре графа

Мы используем разреженную оценку обратной ковариационной матрицы, чтобы определить, какие котировки коррелируют при условии остальных. В частности, разреженная обратная ковариационная матрица задаёт граф — список связей. Для каждого символа связанные с ним символы помогают объяснить его колебания.

from sklearn import covariance

alphas = np.logspace(-1.5, 1, num=10)
edge_model = covariance.GraphicalLassoCV(alphas=alphas)

# standardize the time series: using correlations rather than covariance
# former is more efficient for structure recovery
X = variation.copy().T
X /= X.std(axis=0)
edge_model.fit(X)
GraphicalLassoCV(alphas=array([ 0.03162278,  0.05994843,  0.11364637,  0.21544347,  0.40842387,
        0.77426368,  1.46779927,  2.7825594 ,  5.27499706, 10.        ]))
В среде Jupyter повторно выполните эту ячейку, чтобы отобразить HTML-представление, или доверьте блокноту выполнение.
На GitHub HTML-представление отобразить не удаётся; попробуйте открыть эту страницу с помощью nbviewer.org.
Параметры
alphas alphas: целое число или объект, подобный массиву, формы (n_alphas,), dtype=float, по умолчанию 4

Если задано целое число, оно определяет количество точек
в сетке значений alpha. Если задан список, он задаёт
используемую сетку. Дополнительные сведения см. в примечаниях
к документации класса. Для целого числа диапазон — [1, inf).
Для массива чисел с плавающей точкой диапазон — (0, inf].
array([ 0.031... 10. ])
n_refinements n_refinements: целое число, по умолчанию 4

Количество уточнений сетки. Не используется, если заданы явные
значения alphas. Диапазон — [1, inf).
4
cv cv: целое число, генератор перекрёстной проверки или итерируемый объект, по умолчанию None

Определяет стратегию разбиения для перекрёстной проверки.
Возможные значения cv:

- None — использовать перекрёстную проверку по умолчанию с 5 блоками;
- целое число — задать количество блоков;
- :term:`разделитель CV`,
- итерируемый объект, возвращающий разбиения (train, test) в виде массивов индексов.

Для целочисленного значения или None используется :class:`~sklearn.model_selection.KFold`.

Различные стратегии перекрёстной проверки, которые можно использовать здесь,
описаны в :ref:`руководстве пользователя <cross_validation>`.

.. versionchanged:: 0.20
Значение ``cv`` по умолчанию, равное None, изменено с 3 блоков на 5.
None
tol tol: число с плавающей точкой, по умолчанию 1e-4

Допуск для определения сходимости: итерации останавливаются,
если двойственный разрыв становится меньше этого значения. Диапазон — (0, inf].
0.0001
enet_tol enet_tol: число с плавающей точкой, по умолчанию 1e-4

Допуск для решателя эластичной сети, используемого для вычисления направления
спуска. Этот параметр управляет точностью направления поиска
для обновления отдельного столбца, а не общей оценки параметров. Используется только
при mode='cd'. Диапазон — (0, inf].
0.0001
max_iter max_iter: целое число, по умолчанию 100

Максимальное количество итераций.
100
mode mode: {'cd', 'lars'}, по умолчанию 'cd'

Используемый решатель Lasso: покоординатный спуск или LARS. Используйте LARS для
очень разреженных графов, где число признаков превышает
число образцов. В остальных случаях предпочтителен cd: он более
устойчив с численной точки зрения.
'cd'
n_jobs n_jobs: целое число, по умолчанию None

Количество задач, выполняемых параллельно.
``None`` означает 1, если не используется контекст :obj:`joblib.parallel_backend`.
``-1`` означает использование всех процессоров. Дополнительные сведения см. в :term:`глоссарии <n_jobs>`.

.. versionchanged:: v0.20
Значение `n_jobs` по умолчанию изменено с 1 на None
None
verbose verbose: логическое значение, по умолчанию False

Если verbose имеет значение True, на каждой итерации выводятся
целевая функция и двойственный разрыв.
False
eps eps: число с плавающей точкой, по умолчанию eps

Регуляризация с точностью до машинного эпсилон при вычислении
диагональных множителей разложения Холецкого. Увеличьте это значение для систем
с очень плохой обусловленностью. По умолчанию используется `np.finfo(np.float64).eps`.

.. versionadded:: 1.3
np.float64(2....049250313e-16)
assume_centered assume_centered: логическое значение, по умолчанию False

Если значение True, данные перед вычислениями не центрируются.
Это полезно при работе с данными, среднее значение которых почти, но не точно
равно нулю.
Если значение False, данные центрируются перед вычислениями.
False
Обученные атрибуты
Имя Тип Значение
alpha_ alpha_: число с плавающей точкой

Выбранный параметр регуляризации.
float64 0.05995
costs_ costs_: список пар (objective, dual_gap)

Список значений целевой функции и двойственного разрыва
на каждой итерации. Возвращается только при значении return_costs, равном True.

.. versionadded:: 1.3
list [(np.float64(inf), np.float64(-2...5374945193858)), (np.float64(242.72241991721066), np.float64(0....7211362260404)), (np.float64(242.72169173955422), np.float64(0....5270814104613)), (np.float64(242.72171542675326), np.float64(0....4492626584087)), ...]
covariance_ covariance_: ndarray формы (n_features, n_features)

Оценённая ковариационная матрица.
ndarray[float64](56, 56) [[1. ,0.22,0.29,...,0.25,0.17,0.22], [0.22,1. ,0.23,...,0.27,0.24,0.24], [0.29,0.23,1. ,...,0.21,0.21,0.43], ..., [0.25,0.27,0.21,...,1. ,0.2 ,0.21], [0.17,0.24,0.21,...,0.2 ,1. ,0.23], [0.22,0.24,0.43,...,0.21,0.23,1. ]]
cv_results_ cv_results_: словарь массивов ndarray

Словарь со следующими ключами:

alphas : ndarray формы (n_alphas,)
Все проверенные параметры регуляризации.

split(k)_test_score : ndarray формы (n_alphas,)
Значение логарифмического правдоподобия на отложенных данных для (k)-го блока.

.. versionadded:: 1.0

mean_test_score : ndarray формы (n_alphas,)
Среднее значение оценок по блокам.

.. versionadded:: 1.0

std_test_score : ndarray формы (n_alphas,)
Стандартное отклонение оценок по блокам.

.. versionadded:: 1.0
dict {'alphas': array([10. ... 0. ]), 'me...re': array([-81.87...-72.17963604]), 'sp...re': array([-85.25...-73.71542769]), 'sp...re': array([-76.71...-67.03463241]), ...}
location_ location_: ndarray формы (n_features,)

Оценённое положение, то есть оценённое среднее значение.
ndarray[float64](56,) [-0.02,-0.02, 0.07,..., 0.04, 0.09,-0. ]
n_features_in_ n_features_in_: целое число

Количество признаков, обнаруженных во время :term:`fit`.

.. versionadded:: 0.24
int 56
n_iter_ n_iter_: целое число

Количество итераций, выполненных для оптимального alpha.
int 12
precision_ precision_: ndarray формы (n_features, n_features)

Оценённая матрица точности (обратная ковариационная матрица).
ndarray[float64](56, 56) [[ 1.28,-0. ,-0.17,...,-0.09,-0. ,-0. ], [-0. , 1.58,-0. ,...,-0. ,-0.02,-0. ], [-0.17,-0. , 1.38,...,-0. ,-0.04,-0.38], ..., [-0.09,-0. ,-0. ,..., 2.44,-0. , 0. ], [-0. ,-0.02,-0.04,...,-0. , 1.22,-0.06], [-0. ,-0. ,-0.38,..., 0. ,-0.06, 1.42]]


Кластеризация методом распространения сходства

Мы используем кластеризацию, чтобы сгруппировать котировки, которые ведут себя сходным образом. Среди различных методов кластеризации, доступных в scikit-learn, мы используем распространение сходства, поскольку этот метод не требует кластеров одинакового размера и автоматически определяет их количество по данным.

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

from sklearn import cluster

_, labels = cluster.affinity_propagation(edge_model.covariance_, random_state=0)
n_labels = labels.max()

for i in range(n_labels + 1):
    print(f"Cluster {i + 1}: {', '.join(names[labels == i])}")
Cluster 1: Apple, Amazon, Yahoo
Cluster 2: Comcast, Cablevision, Time Warner
Cluster 3: ConocoPhillips, Chevron, Total, Valero Energy, Exxon
Cluster 4: Cisco, Dell, HP, IBM, Microsoft, SAP, Texas Instruments
Cluster 5: Boeing, General Dynamics, Northrop Grumman, Raytheon
Cluster 6: AIG, American express, Bank of America, Caterpillar, CVS, DuPont de Nemours, Ford, General Electrics, Goldman Sachs, Home Depot, JPMorgan Chase, Marriott, McDonald's, 3M, Ryder, Wells Fargo, Wal-Mart
Cluster 7: GlaxoSmithKline, Novartis, Pfizer, Sanofi-Aventis, Unilever
Cluster 8: Kellogg, Coca Cola, Pepsi
Cluster 9: Colgate-Palmolive, Kimberly-Clark, Procter Gamble
Cluster 10: Canon, Honda, Navistar, Sony, Toyota, Xerox

Проекция в двумерное пространство

Для визуализации необходимо расположить различные символы на двумерной плоскости. Для этого мы используем методы обучения многообразий, чтобы получить двумерное вложение. Для воспроизводимости мы используем плотный eigen_solver (алгоритм arpack инициализируется случайными векторами, которыми мы не можем управлять). Кроме того, мы используем большое количество соседей, чтобы выявить структуру крупного масштаба.

# Finding a low-dimension embedding for visualization: find the best position of
# the nodes (the stocks) on a 2D plane

from sklearn import manifold

node_position_model = manifold.LocallyLinearEmbedding(
    n_components=2, eigen_solver="dense", n_neighbors=6
)

embedding = node_position_model.fit_transform(X.T).T

Визуализация

Результаты трёх моделей объединены в двумерный граф, в котором узлы обозначают акции, а рёбра — связи (частичные корреляции):

  • метки кластеров используются для определения цвета узлов
  • разреженная ковариационная модель используется для отображения силы связей
  • двумерное вложение используется для расположения узлов на плоскости

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

import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection

plt.figure(1, facecolor="w", figsize=(10, 8))
plt.clf()
ax = plt.axes([0.0, 0.0, 1.0, 1.0])
plt.axis("off")

# Plot the graph of partial correlations
partial_correlations = edge_model.precision_.copy()
d = 1 / np.sqrt(np.diag(partial_correlations))
partial_correlations *= d
partial_correlations *= d[:, np.newaxis]
non_zero = np.abs(np.triu(partial_correlations, k=1)) > 0.02

# Plot the nodes using the coordinates of our embedding
plt.scatter(
    embedding[0], embedding[1], s=100 * d**2, c=labels, cmap=plt.cm.nipy_spectral
)

# Plot the edges
start_idx, end_idx = non_zero.nonzero()
# a sequence of (*line0*, *line1*, *line2*), where::
#            linen = (x0, y0), (x1, y1), ... (xm, ym)
segments = [
    [embedding[:, start], embedding[:, stop]] for start, stop in zip(start_idx, end_idx)
]
values = np.abs(partial_correlations[non_zero])
lc = LineCollection(
    segments, zorder=0, cmap=plt.cm.hot_r, norm=plt.Normalize(0, 0.7 * values.max())
)
lc.set_array(values)
lc.set_linewidths(15 * values)
ax.add_collection(lc)

# Add a label to each node. The challenge here is that we want to
# position the labels to avoid overlap with other labels
for index, (name, label, (x, y)) in enumerate(zip(names, labels, embedding.T)):
    dx = x - embedding[0]
    dx[index] = 1
    dy = y - embedding[1]
    dy[index] = 1
    this_dx = dx[np.argmin(np.abs(dy))]
    this_dy = dy[np.argmin(np.abs(dx))]
    if this_dx > 0:
        horizontalalignment = "left"
        x = x + 0.002
    else:
        horizontalalignment = "right"
        x = x - 0.002
    if this_dy > 0:
        verticalalignment = "bottom"
        y = y + 0.002
    else:
        verticalalignment = "top"
        y = y - 0.002
    plt.text(
        x,
        y,
        name,
        size=10,
        horizontalalignment=horizontalalignment,
        verticalalignment=verticalalignment,
        bbox=dict(
            facecolor="w",
            edgecolor=plt.cm.nipy_spectral(label / float(n_labels)),
            alpha=0.6,
        ),
    )

plt.xlim(
    embedding[0].min() - 0.15 * np.ptp(embedding[0]),
    embedding[0].max() + 0.10 * np.ptp(embedding[0]),
)
plt.ylim(
    embedding[1].min() - 0.03 * np.ptp(embedding[1]),
    embedding[1].max() + 0.03 * np.ptp(embedding[1]),
)

plt.show()
plot stock market

Общее время выполнения скрипта: (0 минут 2.861 секунды)

Launch binder
Launch JupyterLite

Download Jupyter notebook: plot_stock_market.ipynb

Download Python source code: plot_stock_market.py

Download zipped: plot_stock_market.zip

Связанные примеры

Обучение многообразий на рукописных цифрах: локальное линейное вложение, Isomap…

Сравнение методов обучения многообразий

Различные варианты агломеративной кластеризации двумерного вложения цифр

Разделение изображения греческих монет на области

© 2007–2026 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.9/auto_examples/applications/plot_stock_market.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API