<jupyter_start><jupyter_text>IBOV Ações - Exploração inicial<jupyter_code>df.head()
df.shape<jupyter_output><empty_output><jupyter_text>Tratamento dos dados<jupyter_code># Convertendo string para datetime
df['datetime'] = pd.to_datetime(df['datetime'])
# Removendo coluna não utilizada
# df = df.drop(['volume'], axis=1)<jupyter_output><empty_output><jupyter_text>Criação de novas features<jupyter_code># Variação diária em porcentagem 
df['delta_open'] = df.apply(lambda x: (abs(x['open'] - x['close']) / x['open']), axis=1)
# Indica se a variação foi positiva, negativa ou zero
def calc_delta_side(row):
    delta = row['open'] - row['close']
    if delta > 0:
        return 1
    elif delta == 0:
        return 0
    else:
        return -1

df['delta_side'] = df.apply(lambda row: calc_delta_side(row), axis=1)<jupyter_output><empty_output><jupyter_text>**Coluna delta_high faz sentido??? (high - low)**  Removendo dados que não fazem sentidocom por exemplo, preço máximo menor do que o preço de abertura<jupyter_code># Muita low e high com muita variação mas close e open próximos
df.loc[df['delta_open'] > 10].head(10)<jupyter_output><empty_output><jupyter_text>Seriam esses dois dados ruido? (high = 1 / close = 33)<jupyter_code>df = df.loc[(df['high'] >= df['open']) & (df['high'] >= df['close'])]
df = df.loc[(df['open'] >= df['low']) & (df['close'] >= df['low'])]

df = df.loc[(df['high'] >= df['low'])]

df.shape<jupyter_output><empty_output><jupyter_text>Plotando distribuições<jupyter_code>df.describe().apply(lambda s: s.apply('{0:.2f}'.format))
sns.boxplot(x=df['delta_open'])
# Esses pontos são possíveis outliers???
# Cortando uma parte dos dados para ver o gráfico com "zoom"
sns.relplot(x="open", y="delta_open", data=df)<jupyter_output><empty_output><jupyter_text>Normalizando valores**Normalizar antes ou depois de criar as feature?**<jupyter_code># Normalizando os valores com MinMaxScaler
# df[['open', 'close', 'low', 'high', 'delta_open']] = MinMaxScaler().fit_transform(df[['open', 'close', 'low', 'high', 'delta_open']])
# Normalizando os valores usando normalização logaritmica
# df[['open', 'close', 'low', 'high', 'delta_open']] = np.log(df[['open', 'close', 'low', 'high', 'delta_open']])<jupyter_output><empty_output><jupyter_text>Cortando uma parte dos dados para ver o gráfico com "zoom"<jupyter_code>sns.relplot(x="open", y="delta_open", data=df.loc[(df['delta_open'] < 1000) & (df['open'] < 1000)])<jupyter_output><empty_output><jupyter_text>Usaremos dados depois de 95 por causa do plano realNão temos a informação de como foi realizada a conversão da moeda e o ano de 94 possui muitas observações destoantes<jupyter_code>df = df.loc[df['datetime'] > '1995-01-01']<jupyter_output><empty_output><jupyter_text>Vamos usar apenas dados desse seculoAo procurar muitas das ações listadas no dataset não encontramos informações<jupyter_code>df = df.loc[df['datetime'] > '2000-01-01']<jupyter_output><empty_output><jupyter_text>Entendendo ações da amazon caindo bruscamente<jupyter_code>sns.lineplot(x='datetime', y='close', data=df.loc[(df['ticker'] == 'AMZO34') & (df['datetime'] > '2020-11-01') & (df['datetime'] > '2020-11-01')])
# Analisando alguns dados para entender o motivo da variação brusca
df.loc[(df['ticker'] == 'AMZO34') & (df['datetime'] > '2020-11-01') & (df['datetime'] > '2020-11-01')]<jupyter_output><empty_output><jupyter_text>Provavelmente reindexação (1 ação virou 10 com 1/10 do preço)  LOF<jupyter_code>def get_LOF_scores(df, n_neighbors=10, contamination=0.05):
    np.random.seed(42)

    # fit the model for outlier detection (default)
    clf = LocalOutlierFactor(n_neighbors=n_neighbors, contamination=contamination)
    # use fit_predict to compute the predicted labels of the training samples
    # (when LOF is used for outlier detection, the estimator has no predict,
    # decision_function and score_samples methods).
    y_pred = clf.fit_predict(df)

    X_scores = clf.negative_outlier_factor_
    
    output_df = df.copy()
    output_df['LOF_score'] = X_scores
    output_df['LOF_predictions'] = y_pred
    
    return output_df
def show_2D_outliers(df, x, y, scores, title = ''):

    normalized = (df[scores].max() - df[scores]) / (df[scores].max() - df[scores].min())
    
    t = "Outlier Scores"
    if title: t=t+": "+title
    
    fig, ax = plt.subplots(figsize=(8, 6))

    plt.title(t)
    plt.scatter(x=x, y=y, color='k', s=3., label='Data points', data=df)
    # plot circles with radius proportional to the outlier scores

    plt.scatter(x=x, y=y, s=1000 * normalized, edgecolors='r',
                facecolors='none', label='Outlier scores', data=df)
    plt.axis('tight')
    # plt.xlim((-5, 5))
    # plt.ylim((-5, 5))
    # plt.xlabel("prediction errors: %d" % (n_errors))
    legend = plt.legend(loc='upper right')
    legend.legendHandles[0]._sizes = [10]
    legend.legendHandles[1]._sizes = [20]
    plt.show()<jupyter_output><empty_output><jupyter_text>Aplicando o algoritmo para uma faixa muito densa do dataset<jupyter_code>df_low = df[['open', 'delta_open']]
df_low = df_low.loc[(df_low['open'] < 10) & (df_low['delta_open'] < 0.5)]
scores_low = get_LOF_scores(df_low, n_neighbors=300, contamination=0.5)

show_2D_outliers(scores_low, x = 'open', y = 'delta_open', scores = 'LOF_score', title = 'Delta open low')<jupyter_output><empty_output><jupyter_text>Acreditamos que nesse caso a visualização seja ruim pois alguns circulos ficam grandes o suficiente para ficar fora do gráfico  Aplicando o algoritmo para uma faixa pouco densa do dataset<jupyter_code>df_high = df[['open', 'delta_open']]
df_high = df_high.loc[(df_high['open'] > 500) & (df_high['delta_open'] > 0.1)]
scores_high = get_LOF_scores(df_high, n_neighbors=100, contamination=0.3)

show_2D_outliers(scores_high, x = 'open', y = 'delta_open', scores = 'LOF_score', title = 'Delta open high')<jupyter_output><empty_output><jupyter_text>**Acreditamos que nesse caso a visualização seja mais efetiva, porém não sabemos como realizar transformações no dataset para chegar numa visualização coerente **  Resultados- Maior problema identificado: disparidade no preço das ações (algumas centavos outras milhares de reais). Como tratar? - Normalização utilizando escala logaritmica???- Sem resultados satisfatórios- Visualização não é boa nesse caso- Quais outras transformações podem ser feitas ou visualizações exploradas?- Como tratar a disparidade entre os preços das ações?  Em busca dos Circuit Breakers  Criando novas colunas Meta:- quantas acoes cairam- quantas acoes subiram- media da variacao- media da variacao das 10+- desvio padrao da variacao- media do volume- dia Getting the most important ibovespa stocks<jupyter_code>ibov_composition = pd.read_csv('datasets/IBOVDia_13-10-21.csv', sep=';', encoding='utf-8')
ibov_composition.reset_index(inplace=True)
ibov_composition['Theoretical Quantity'] = ibov_composition['Theoretical Quantity'].str.replace(',','.').astype(float)
ibov_composition.sort_values('Theoretical Quantity', ascending=False, inplace=True)
top_15 = ibov_composition[1:16]['index'].to_list()
# Quantos porcento as 15 maiores ações representam no indice IBOVESPA
ibov_composition[1:16]['Theoretical Quantity'].sum()<jupyter_output><empty_output><jupyter_text>Creating the daily aggregation<jupyter_code>def how_many_went_up(series):
    return series[series == 1].shape[0] / series.shape[0]

def how_many_went_down(series):
    return series[series == -1].shape[0] / series.shape[0]
df_daily = df.groupby('datetime').agg(
    {
        'delta_open':['mean','std'],
        'volume': 'mean',
        'delta_side': [how_many_went_up, how_many_went_down]}
)<jupyter_output><empty_output><jupyter_text>Renaming the columns<jupyter_code>df_daily.columns = df_daily.columns.to_flat_index()
df_daily.rename(
    columns={
        ('delta_open', 'mean'): 'variation_mean',
        ('delta_open', 'std'): 'variation_std',
        ('volume', 'mean'): 'volume_mean',
        ('delta_side', 'how_many_went_up'): 'up_count',
        ('delta_side', 'how_many_went_down'): 'down_count',
    }, inplace = True
)<jupyter_output><empty_output><jupyter_text>Getting the mean and std variation of the 15 most important stocks<jupyter_code>df_top_15 = df.loc[df['ticker'].isin(top_15)]
daily_df_top_15 = df_top_15.groupby('datetime').agg({'delta_open': ['mean', 'std']})
daily_df_top_15.columns = daily_df_top_15.columns.to_flat_index()
daily_df_top_15.rename(
    columns= {
        ('delta_open', 'mean'): 'top_15_variation_mean',
        ('delta_open', 'std'): 'top_15_variation_std',
    }, inplace = True)<jupyter_output><empty_output><jupyter_text>joining if the df_daily dataset<jupyter_code>df_daily = pd.merge(df_daily, daily_df_top_15, on='datetime')
df_daily.reset_index(inplace=True)
df_daily
# Normalizing volume mean
df_daily['volume_mean'] = MinMaxScaler().fit_transform(df_daily[['volume_mean']])
sns.relplot(x="datetime", y="volume_mean", data=df_daily.loc[df_daily['datetime'] > '2020'])
sns.relplot(x="datetime", y="variation_mean", data=df_daily.loc[df_daily['datetime'] > '2020'])
sns.lineplot(x="datetime", y="variation_mean", data=df_daily.loc[(df_daily['datetime'] > '2008') & (df_daily['datetime'] < '2009')])<jupyter_output><empty_output><jupyter_text>Outlier Detection<jupyter_code>df_2020 = df_daily.loc[df_daily['datetime'] > '2020'].set_index('datetime')
df_2020_lof = get_LOF_scores(df_2020, n_neighbors=40, contamination=0.5)

# Para plotar o grafico, o datetime não pode ser a index do dataset
df_2020_lof.reset_index(inplace=True)
show_2D_outliers(df_2020_lof, x = 'datetime', y = 'variation_mean', scores = 'LOF_score', title = 'Delta open low')<jupyter_output><empty_output><jupyter_text>**Removendo o dado de volume**<jupyter_code>df_2020_lof = get_LOF_scores(df_2020.drop(columns=['volume_mean']), n_neighbors=40, contamination=0.5)

df_2020_lof.reset_index(inplace=True)
show_2D_outliers(df_2020_lof, x = 'datetime', y = 'variation_mean', scores = 'LOF_score', title = 'Variation Mean')<jupyter_output><empty_output><jupyter_text>**Plotando para 2008**<jupyter_code># df_2020 = df_daily.loc[(df_daily['datetime'] > '2008') & (df_daily['datetime'] < '2009')].set_index('datetime')
# scores_low = get_LOF_scores(df_2020, n_neighbors=100, contamination=0.5)

# # Para plotar o grafico, o datetime não pode ser a index do dataset
# scores_low.reset_index(inplace=True)
# show_2D_outliers(scores_low, x = 'datetime', y = 'variation_mean', scores = 'LOF_score', title = 'Delta open low')<jupyter_output><empty_output><jupyter_text>O dataset utilizado será o de 2020 sem os dados de volume<jupyter_code>df_2020_lof.mean()<jupyter_output>/var/folders/fq/0s3sdjd50r79swwqd52gm5xh0000gn/T/ipykernel_14033/2459732842.py:1: FutureWarning: DataFrame.mean and DataFrame.median with numeric_only=None will include datetime64 and datetime64tz columns in a future version.
  df_2020_lof.mean()<jupyter_text>**Linha com maior LOF_score que não foi considerada Outlier**<jupyter_code>df_2020_lof.sort_values(by=['LOF_score']).head(1)
df_2020_lof.sort_values(by=['LOF_score']).head(5)<jupyter_output><empty_output><jupyter_text>**z-score for all columns and cut the 10+**<jupyter_code>df_top_10_zscore = df_2020_lof.sort_values(by=['LOF_score'])
df_top_10_zscore = df_top_10_zscore.drop(columns=['LOF_score', 'LOF_predictions'])
df_top_10_zscore = df_top_10_zscore.set_index('datetime').apply(zscore).head(5)

df_top_10_zscore = df_top_10_zscore.abs()
df_top_10_zscore
sns.heatmap(df_top_10_zscore, annot=True)<jupyter_output><empty_output><jupyter_text>Iniciamos a análise dos dados em busca das razões que resultaram na determinação de dias específicos como anomlaos ordernando-os em relação ao coeficiente de outlier retornado pelo LOF. Com o dataset organizado, transformamos os valores absolutos de cada uma das colunas no standard score (z-score) correspondente. A ideia é entender o quanto cada um dos registros está destoante da média encontrada no conjunto de dados. Com estas informações em mãos foram escolhidos os cinco dias que apresentaram os maiores coeficientes de outlier para uma análise mais apronfudada. É importante notar que este tipo de comparação pode trazer alguma explicabilidade na identificação de anomalias, mas é ingenua, princiaplemnte por dois aspectos que possivelmente derivam o alto coeficiente das observações apontadas como não explicáveis. São eles: estaremos analisando apenas dimensões isoladas, então subespaços maiores não serão considerados, e o algoritmo LOF utilizado leva em consideração os valores temporalmente próximos no calculo do coeficiente de cada obersvação, está informação também não foi considerada nas análises.O dia 22 de junho de 2020 foi o identificado como mais destoante dentre as mais de cinco mil amostras do dataset. Neste dia foi observado um desvio enorme em relação à média do conjunto na dimensão variation_std. Esta coluna apresenta qual o desvio padrão encontrado entre todas as ações negociadas no dia. A coluna variation_mean, a média da variação do dia, apresenta um leve desvio. As outras colunas se mantiveram estáveis. Assim, a anomalia encontrada neste dia parece ser um pequeno grupo de ações pequenas, que não estão entre as 15 mais importantes para o indice IBOV, variou muitas vezes em relação ao normal.No dia 22 de junho um grupo de acoes que nao estao no top 15 desviou muito em relação a media do desvio diario.Provavelmente nenhuma dessas acoes esta no top 15 porque a media de variacao entre elasdia 25 de março grande parte das açoes variou bastante, mas especialmente as 15 acoes mais importantesdia 17 de novembro ou um grupo muito pequeno variou muito ou existiram variacoes complementares, que se anularam em relação a media---demais dias variaram sao altamente inconclusivos (40% do top 5 e 50% do top 10) -> justificativa para utilização do algoritmo df_top_10_zscore.sum(axis=1).sort_values()<jupyter_code>pd.set_option('display.float_format', lambda x: '%.3f' % x)
df_top_10_zscore.sum().sort_values()
df_2020_lof.set_index('datetime')
df_2020_lof.to_csv('datasets/df_outliers.csv')
df_2020_lof.shape
df_2020.to_csv('datasets/df_outliers_since2000.csv', index=False)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12448864437861476, 'fraction_numerical': 0.028565382987727466, 'mean_word_length': 6.365714285714286, 'pattern_counts': {'":': 1, '<': 110, '<?xml version=': 0, '>': 125, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '26', 'dir': 'jupyter-structured-clean-dedup', 'id': '511375', 'license': 'MIT', 'n_tokens_mistral': 5499, 'n_tokens_neox': 5074, 'n_words': 1230, 'path': 'data_exploration.ipynb', 'repo_name': 'tiagoColli/tcc', 'size': '14178'}