Spaces:
Runtime error
Runtime error
File size: 7,312 Bytes
bceb8c4 06fc9c7 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | # -*- coding: utf-8 -*-
# File: app.py
# Project: 'Homework #3 OTUS.ML.Advanced'
# Created by Gennady Matveev (gm@og.ly) on 02-01-2022.
# %%
# Import libraries
import re
import pandas as pd
import numpy as np
import streamlit as st
import requests
import pickle
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
import tsfel
from kneed import KneeLocator
import cryptocompare as cc
import matplotlib.pyplot as plt
import plotly.express as px
from umap import UMAP
import warnings
plt.style.use("ggplot")
plt.rcParams["figure.figsize"] = (10, 5)
warnings.filterwarnings("ignore")
# pd.options.display.precision = 4
random_state = 17
scaler = StandardScaler()
n_jobs = -1
# %%
st.set_page_config(page_title="Cryptocurrencies clustering",
page_icon='./head.ico', layout='centered', initial_sidebar_state='expanded') # wide
padding = 0
st.markdown(f""" <style>
.reportview-container .main .block-container{{
padding-top: {padding}rem;
padding-right: {padding}rem;
padding-left: {padding}rem;
padding-bottom: {padding}rem;
}} </style> """, unsafe_allow_html=True)
st.image('./mundus.png')
st.subheader('Clustering analysis of cryptocurrencies')
st.markdown(
'*Explore similarities in statisticial, temporal and spectral domains*')
st.markdown('''Top 100 cryptocurrencies' daily closing prices are downloaded.
Their dynamics can be analized in search of similarities between coins.
Up to 8 currencies from each cluster are shown below.''')
st.markdown("""---""")
# %%
# Set cryptocompare API key:
api_key = st.secrets["api_key"]
# %%
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36"
}
req = f"https://min-api.cryptocompare.com/data/top/mktcapfull?limit=100&tsym=USD&api_key={api_key}"
# Utility functions for data download
@st.cache(ttl=600)
def get_price(ticker: str, limit: int):
return cc.get_historical_price_day(ticker, currency="USD",
limit=limit)
@st.cache(ttl=600)
def get_all_cc(limit: int):
df = pd.DataFrame(index=range(limit))
for tick in tickers:
# print(tick, end="\t")
try:
d = get_price(tick, limit)
one_cc = pd.DataFrame.from_dict(d)["close"]
one_cc.rename(index=tick, inplace=True)
df = pd.concat([df, one_cc], axis=1)
except:
pass
return df
# Utility functions for clustering analysis
def elbow_study(data, k_max: int = 10, model=KMeans):
X = scaler.fit_transform(data)
inertia = []
for k in range(2, k_max):
clusterer = model(n_clusters=k, random_state=random_state)
X_km = clusterer.fit(X)
inertia.append(np.sqrt(X_km.inertia_))
# Find a knee
kneedle = KneeLocator(range(2, k_max), inertia, S=2,
curve="convex", direction="decreasing")
# Use 3 clusters in case kneed doesn't find a knee
n_clusters = kneedle.knee or 3
return n_clusters
def plot_clusters_2(data, Xt, n_clusters, random_state):
clusterer = KMeans(n_clusters=n_clusters, max_iter=100,
random_state=random_state)
X = scaler.fit_transform(Xt)
dd = data.copy()
dd.loc["cluster"] = clusterer.fit_predict(X.T)
color = ["red", "green", "blue", "purple",
"orange", "magenta", "goldenrod"]
clusters_no = dd.loc["cluster"].value_counts(sort=False)
for c in range(n_clusters):
cc = color[c]
fig, ax = plt.subplots(2, 4, sharex='col', figsize=(15, 5))
cluster_ticks = dd.T[dd.T.loc[:, "cluster"] == c].index
for i, tick in enumerate(cluster_ticks[:8]):
ax[i % 2, i//2].plot(dd.iloc[:-1][tick],
color=cc) # , label=tick)
ax[i % 2, i//2].set_title(tick)
fig.suptitle(f"Cluster {c}, {clusters_no[c]} items\n", y=1.02)
st.pyplot(fig)
return dd
def visualize(Xt, n_clusters):
clusterer = KMeans(n_clusters=n_clusters, max_iter=100,
random_state=random_state)
X = scaler.fit_transform(Xt.T)
X_clust = clusterer.fit_predict(X)
X_color = X_clust.astype(str)
features = Xt.values
# UMAP
umap_3d = UMAP(n_components=3, init='random',
random_state=random_state)
proj_3d = umap_3d.fit_transform(features)
fig_3d = px.scatter_3d(
proj_3d, x=0, y=1, z=2,
color=X_color, labels={'color': 'clusters'},
color_discrete_sequence=["red", "green", "blue",
"purple", "orange", "magenta", "goldenrod"],
title=f"UMAP projection from feature space",
width=800, height=600,
)
fig_3d.update_traces(marker_size=5)
# fig_3d.show()
st.write(fig_3d)
# %%
# START Sidebar ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
st.sidebar.image('./blau.png')
demo = st.sidebar.checkbox(label="Use demo data?", value=True, help="Use demo data or fetch actual?")
days=st.sidebar.number_input('Number of days for analysis',
min_value=30, max_value=100, value=60)
domain=st.sidebar.selectbox('Domain', ('statistical', 'temporal', 'spectral', 'all'),
index=1, help='Domain to use feature extraction')
st.sidebar.markdown("""---""")
analyze=st.sidebar.button('Start analysis')
# END Sidebar ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Analysis
if analyze:
with st.spinner('Downloading data...'):
if demo==True:
with open("./demo_data.pkl", "rb") as f:
demo_data = pickle.load(f)
dl = demo_data.shape[0]
data_day = demo_data.iloc[dl-days:]
tickers = demo_data.columns
else:
top100=requests.get(req, headers=headers)
rs=re.compile(r"\"Name\":\"(?P<ticker>[A-Z0-9]+)\"")
tickers=rs.findall(top100.text)
data_day=get_all_cc(limit=days).copy()
with st.spinner(f'Extracting {domain} features...'):
dom=domain if domain != 'all' else None
cfg_file=tsfel.get_features_by_domain(dom)
# tsfel analysis
x_temp=tsfel.time_series_features_extractor(
cfg_file, data_day["BTC"], window_size=days)
tf_columns=x_temp.columns
xtf=pd.DataFrame(columns=data_day.columns, index=tf_columns)
# Fill df with features
for col in xtf.columns:
xtf[col]=tsfel.time_series_features_extractor(
cfg_file, data_day[col], window_size=days
).T
xtf.dropna(inplace=True)
# Features dataframe
Xt=pd.DataFrame(scaler.fit_transform(
xtf), columns=data_day.columns, index=xtf.index)
with st.spinner('Calculating optimal number of clusters...'):
# Get optimal no of clusters
n_clusters=elbow_study(Xt.T, model=KMeans) # metric="euclidean",
# Plot clusters
plot_clusters_2(data_day, Xt=Xt, n_clusters=n_clusters,
random_state=random_state
)
# Plot umap
# visualize(Xt, n_clusters) |