#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Oct 23 16:14:37 2024

@author: ojacques
"""
import pandas as pd
import numpy as np
from scipy.stats import norm
from scipy import stats

import matplotlib.pyplot as plt
#-----------repositório de dados http://archive.ics.uci.edu/----------------------

def valFdp(x,med,dp):
    #verifica se x é um tipo array ou um único valor (int,float)
    if type(x) is np.ndarray:
        md=np.array([med,dp]).T #transforma em 3x2
        y=[stats.norm.pdf(x,loc=m,scale=d) for m,d in md]
    else:
        y=stats.norm.pdf(x,loc=med,scale=dp)    
    return y

campos=['Classe','Peso Esquerdo','Distância Esquerda', 'Peso Direito','Distância Direita']
caminhoDados='./balance+scale'
#caso o arquivo não tenha nome das colunas ou queira trocar os nomes das colunas utilizar names
df=pd.read_csv(f'{caminhoDados}/balance-scale.data',names=campos) 
qtdeClasse=df['Classe'].value_counts()
prbClasse=qtdeClasse/qtdeClasse.sum()
print(prbClasse)
classes=list(qtdeClasse.index)
numClasses=len(classes)
campos.pop(0) #retira 'Classe' de campos
X=[3,2,1,3]
numAtrib=len(X)


med=np.array([[df.query(f"Classe=='{c}'")[campo].mean() for campo in campos] for c in classes])
dp=np.array([[df.query(f"Classe=='{c}'")[campo].std() for campo in campos] for c in classes])
#supoe que o problema segue um distribuição normal (também chamada de gaussiana)
#cria o objeto gaussiana
gaussiana=stats.norm(loc=med,scale=dp)
#plt.close()
#plt.figure(pltsize=(10,10))
plt.close('all')
x=np.linspace(-2,8) #cria um array com 50 valores (default)
#---------------------------limpa a plt atual------------------------------------------
#plt.clf()
#-----------plt.cla() limpa o eixo corrente (gráfico)-------------------------------------

plt.subplot(1,2,1)
plt.title('Peso Esquerdo')
Y=valFdp(x,med[:,0],dp[:,0])

plt.plot(x,Y[0],label="P(x|R)")
plt.plot(x,Y[1],label="P(x|L)")
plt.plot(x,Y[2],label="P(x|B)")
plt.legend() #exibe os labels da legenda
ptMax=max([valFdp(X[0],m,d) for m,d in np.array([med[:,0],dp[:,0]]).T])
plt.scatter(X[0],ptMax,color='red')
plt.axvline(X[0],color='red',linestyle='--')
plt.text(X[0]+0.2,ptMax,f'({X[0]}, {ptMax:.2f})',color='red',weight='heavy')
plt.grid(True)

plt.subplot(1,2,2)
plt.title('Peso Direito')
Y=valFdp(x,med[:,2],dp[:,2])
plt.plot(x,Y[0],label="P(x|R)")
plt.plot(x,Y[1],label="P(x|L)")
plt.plot(x,Y[2],label="P(x|B)")
plt.legend() 
ptMax=max([valFdp(X[2],m,d) for m,d in np.array([med[:,2],dp[:,2]]).T])
plt.scatter(X[2],ptMax,color='red')
plt.axvline(X[2],color='red',linestyle='--')
plt.text(X[2]+0.2,ptMax,f'({X[2]}, {ptMax:.2f})',color='red',weight='heavy')
plt.grid(True)
#plt.tight_layout()
plt.show()

#calcula a probabilidade de cada X na curva normal
prbXC=gaussiana.pdf(X) #ou no modo direto prbXC=norm.pdf(X,loc=med,scale=dp)

#--------Qual a chance de ser a classe c uma vez observado X------------
prbCX=prbClasse*np.prod(prbXC,axis=1)

#----normaliza----------
prbCX=prbCX/np.sum(prbCX)
#Hipotese da Máxima Verossimilhança (HMV)
hMv=np.argmax(prbCX)
#índice do maior argumento para o menor
id=np.argsort(np.array(prbCX))[::-1]
#probabilidade ordenada das classes
prbOrdC=[[classes[cl],prbCX[cl]] for cl in id]
print('--------------PROBABILIDADE DAS CLASSES DADO X-------------------------------')
for l in prbOrdC:
    print(f'Classe {l[0]} = {l[1]:.2f}')

print(f'\n Classe vencedora: {classes[hMv]} probabilidade: {prbCX[hMv]:.2f}')


#--------------------USO DE FILTROS EM COLCHETES OU COM query-------------------------------
# Seja dados de empresas fabricantes de cereais:Kellogs, Nestlé, etc, com os campos:
#  name, mfr, type, calories, protein, fat, sodium, fiber, carbo, sugars, potass, 
#  vitamins, shelf,cups, rating
# Veja aula em https://www.hashtagtreinamentos.com/metodo-query-do-pandas-ciencia-de-dados

#df[df["rating"] > 70]
#df.query("rating > 70")
#df.query("rating > 70")[ ["name", "rating"] ]
#df[(df["mfr"] == "N") & (df["type"] == "H")]
#df.query("mfr == 'N' and type == 'H'")
# df[(df["mfr"] == "N") & ~(df["type"] == "H")]
# df.query("mfr == 'N' and not type == 'H'")
# df[(df["mfr"] == "N") | (df["type"] == "H")]
# df.query("mfr == 'N' or type == 'H'")
# df[df["mfr"].isin(["R", "N", "A"])]]
# df.query("mfr in ['R', 'N', 'A']")
# empresas_de_interesse = ["R", "N", "A"]
# df[df["mfr"].isin(empresas_de_interesse)]
# empresas_de_interesse = ["R", "N", "A"]
# df.query("mfr in @empresas_de_interesse")qui
# df[~df["mfr"].isin(empresas_de_interesse)]
# df.query("mfr not in @empresas_de_interesse")

# train['Sex'].value_counts() #conta a frequência de um único valor
# Out[6]:
# male      577
# female    314
# Name: Sex, dtype: int64
#value_counts()agrega os dados e conta cada valor único. Você pode conseguir o mesmo usando groupbywhich é uma função mais ampla para agregar dados no pandas.
#count()simplesmente retorna o número de valores não NaN/Nulos na coluna (série) em que você o aplica.
#------------------------------Soma----------------------------------------
#data = [[10, 18], [13, 15], [9, 20]]
#df = pd.DataFrame(data)
#somaLinhas=df.sum(axis=0)       #cada linha tem 2 campos, 2 resultados: 32 e 53
#somaLinhas=df.sum(axis='index') #cada index tem 2 campos, 2 resultados: 32 e 53
#somaColunas=df.sum(axis=1)         #cada coluna tem 3 linhas, 3 resultados: 28, 28, 29
#somaColunas=df.sum(axis='columns') #cada coluna tem 3 linhas, 3 resultados: 28, 28, 29




