Files
Data_Science/lab5.ipynb
2025-07-17 16:37:16 +04:00

302 KiB
Raw Blame History

  1. Выбор бизнес-цели и постановка задачи

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

Задача: На основе ежедневных значений цен и объёмов кластеризовать дни на группы с похожими характеристиками. Выявить и визуализировать эти группы.

In [2]:
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.cluster import KMeans, AgglomerativeClustering
from sklearn.metrics import silhouette_score
import matplotlib.pyplot as plt
  1. Загрузка и подготовка данных
In [3]:
data = pd.read_csv("data/FINAL_USO.csv")

data.head()
Out[3]:
<style scoped=""> .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </style>
Date Open High Low Close Adj Close Volume SP_open SP_high SP_low ... GDX_Low GDX_Close GDX_Adj Close GDX_Volume USO_Open USO_High USO_Low USO_Close USO_Adj Close USO_Volume
0 2011-12-15 154.740005 154.949997 151.710007 152.330002 152.330002 21521900 123.029999 123.199997 121.989998 ... 51.570000 51.680000 48.973877 20605600 36.900002 36.939999 36.049999 36.130001 36.130001 12616700
1 2011-12-16 154.309998 155.369995 153.899994 155.229996 155.229996 18124300 122.230003 122.949997 121.300003 ... 52.040001 52.680000 49.921513 16285400 36.180000 36.500000 35.730000 36.270000 36.270000 12578800
2 2011-12-19 155.479996 155.860001 154.360001 154.869995 154.869995 12547200 122.059998 122.320000 120.029999 ... 51.029999 51.169998 48.490578 15120200 36.389999 36.450001 35.930000 36.200001 36.200001 7418200
3 2011-12-20 156.820007 157.429993 156.580002 156.979996 156.979996 9136300 122.180000 124.139999 120.370003 ... 52.369999 52.990002 50.215282 11644900 37.299999 37.610001 37.220001 37.560001 37.560001 10041600
4 2011-12-21 156.979996 157.529999 156.130005 157.160004 157.160004 11996100 123.930000 124.360001 122.750000 ... 52.419998 52.959999 50.186852 8724300 37.669998 38.240002 37.520000 38.110001 38.110001 10728000

5 rows × 81 columns

In [4]:
data_num = data.drop(columns=['Date'])


print('Пропуски по столбцам:')
print(data_num.isnull().sum())


data_num = data_num.fillna(data_num.mean())

scaler = StandardScaler()
data_scaled = scaler.fit_transform(data_num)

print(f'Размер данных после обработки: {data_scaled.shape}')
Пропуски по столбцам:
Open             0
High             0
Low              0
Close            0
Adj Close        0
                ..
USO_High         0
USO_Low          0
USO_Close        0
USO_Adj Close    0
USO_Volume       0
Length: 80, dtype: int64
Размер данных после обработки: (1718, 80)
  1. Понижение размерности и визуализация
In [5]:
pca = PCA(n_components=2, random_state=42)
data_pca = pca.fit_transform(data_scaled)

plt.figure(figsize=(8,6))
plt.scatter(data_pca[:,0], data_pca[:,1], s=15, alpha=0.6)
plt.title('PCA - визуализация данных')
plt.xlabel('Главная компонента 1')
plt.ylabel('Главная компонента 2')
plt.show()
No description has been provided for this image
  1. Выбор количества кластеров (K)
In [6]:
inertias = []
silhouettes = []
K_range = range(2, 11)

for k in K_range:
    kmeans = KMeans(n_clusters=k, random_state=42)
    labels = kmeans.fit_predict(data_scaled)
    inertias.append(kmeans.inertia_)
    silhouettes.append(silhouette_score(data_scaled, labels))

plt.figure(figsize=(14,5))

plt.subplot(1,2,1)
plt.plot(K_range, inertias, marker='o')
plt.title('Метод локтя')
plt.xlabel('Количество кластеров K')
plt.ylabel('Инерция')

plt.subplot(1,2,2)
plt.plot(K_range, silhouettes, marker='o', color='orange')
plt.title('Коэффициент силуэта')
plt.xlabel('Количество кластеров K')
plt.ylabel('Силуэт')

plt.show()

optimal_k = K_range[np.argmax(silhouettes)]
print(f'Оптимальное количество кластеров по коэффициенту силуэта: {optimal_k}')
No description has been provided for this image
Оптимальное количество кластеров по коэффициенту силуэта: 2
  1. Кластеризация и оценка качества
In [7]:
kmeans_final = KMeans(n_clusters=optimal_k, random_state=42)
labels_kmeans = kmeans_final.fit_predict(data_scaled)


agglo = AgglomerativeClustering(n_clusters=optimal_k)
labels_agglo = agglo.fit_predict(data_scaled)


sil_kmeans = silhouette_score(data_scaled, labels_kmeans)
sil_agglo = silhouette_score(data_scaled, labels_agglo)

print(f'Силуэт KMeans: {sil_kmeans:.3f}')
print(f'Силуэт AgglomerativeClustering: {sil_agglo:.3f}')
Силуэт KMeans: 0.430
Силуэт AgglomerativeClustering: 0.425
  1. Визуализация кластеров
In [9]:
import matplotlib.pyplot as plt


colors = ['red', 'blue', 'green', 'purple', 'orange', 'cyan', 'magenta', 'brown', 'olive', 'pink']


plt.figure(figsize=(12,5))

plt.subplot(1,2,1)
for i in range(optimal_k):
    cluster = data_pca[labels_kmeans == i]
    plt.scatter(cluster[:, 0], cluster[:, 1], color=colors[i % len(colors)], label=f'Кластер {i}', s=40, alpha=0.7)
plt.title('KMeans кластеризация')
plt.xlabel('PC1')
plt.ylabel('PC2')
plt.legend()


plt.subplot(1,2,2)
for i in range(optimal_k):
    cluster = data_pca[labels_agglo == i]
    plt.scatter(cluster[:, 0], cluster[:, 1], color=colors[i % len(colors)], label=f'Кластер {i}', s=40, alpha=0.7)
plt.title('Иерархическая кластеризация')
plt.xlabel('PC1')
plt.ylabel('PC2')
plt.legend()

plt.tight_layout()
plt.show()
No description has been provided for this image