Esses são os três membros do grupo. Utilizamos um .csv para deixar mais dinâmico a apresentação. Para isso, usamos a biblioteca Pandas.
import pandas
hl_data = pandas.read_csv('../../docs/hl_atividade_1.csv')
hl_df = pandas.DataFrame(hl_data)
hl_df[:3]
type(hl_df.loc[0, 'Member'])
Como parâmetro do método foi passado o dataframe.loc, responsável por localizar certo valor em determinada linha e/ou coluna de um data frame. Neste caso, foi pego o nome do Polillo pra servir como valor para identificação de tipo. Para saber como fica o output do valor usado para identificar o tipo str, ele fica desta forma:
hl_df.loc[0, 'Member']
Dentro do R há um tipo de variável que comporta valores numéricos com casas decimais, ou seja, valores após a vírgula, enquanto no Python este tipo (numeric) é representado por um valor flutuante: o float. Usando type(), passando a variável que contém o dado como parâmetro do método podemos ver seu tipo.
type(hl_df.loc[2, 'Relevance'])
Para ficar melhor a visualização do valor float, observe o seguinte exemplo feito a mão:
peso = 76.2
type(peso)
Ambos tem valores flutuantes, observe:
print('Valor no data frame:', hl_df.loc[2, 'Relevance'])
print('Valor da variável criada a mão:', peso)
Diferente dos tópicos anteriores, o tipo inteiro nas duas linguagens (R e Python) é o mesmo: o int. Usando type(), passando a variável que contém o dado como parâmetro do método podemos ver seu tipo.
type(hl_df.loc[0, 'Semester that joined'])
Assim como no exemplo anterior, se olharmos uma variável feita a mão vamos notar que têm valores parecidos, portanto o tipo continua sendo o mesmo, mudando apenas a forma de sua anotação (os valores do data frame tem o tipo representado pelo NumPy)!
qtdFilhos = 3
type(qtdFilhos)
print('Valor no data frame:', hl_df.loc[0, 'Semester that joined'])
print('Valor da variável criada a mão:', qtdFilhos)
O valor lógico do R (logical) é representado no Python por bool. Ambos tem valores lógicos, ou seja, apenas True e False. Usando type(), passando a variável que contém o dado como parâmetro do método podemos ver seu tipo.
type(hl_df.loc[0, 'Founder'])
Seguindo os exemplos dados anteriormente, é possível mostrar que o valor do data frame e o valor feito a mão dentro da linguagem são parecidos, apenas mudando a forma como é imprimido seu tipo. Veja:
temCarro = True
type(temCarro)
print('Valor no data frame:', hl_df.loc[0, 'Founder'])
print('Valor da variável criada a mão:', temCarro)
"O vetor pode ser considerado uma variável multidimensional indexada, ou seja, uma variável que tem a capacidade de guardar mais de um valor simultaneamente do mesmo tipo."
Para a criação desses vetores utilizamos um laço de repetição para preencher dois vetores vazios. O primeiro vetor é preenchido através do método vector.append(), passando como parâmetro os dados que serão inputados no vetor vazio. O laço de repetição se repetirá 9 vezes. O segundo vetor sofre o mesmo processo.
hl_relevance_vector = []
for i in range(0, 10):
hl_relevance_vector.append(hl_df.loc[i, 'Relevance'])
hl_relevance_vector
hl_names_vector = []
for i in range(0, 10):
hl_names_vector.append(hl_df.loc[i, 'Member'])
hl_names_vector
"Lists are just like the arrays, declared in other languages. Lists need not be homogeneous always which makes it a most powerful tool in Python. A single list may contain DataTypes like Integers, Strings, as well as Objects. Lists are also very useful for implementing stacks and queues. Lists are mutable, and hence, they can be altered even after their creation."
Para criarmos a lista, primeiro instanciamos uma vazia e, através de um laço de repetição que se repete 9 vezes, foi preenchendo a lista através do lista.append(). Por se tratar de uma lista, ela comporta vários tipos de dados, portanto há um total de 3 tipos de lista.append().
hl_list = []
for i in range(0, 10):
hl_list.append(hl_df.loc[i, 'Member'])
hl_list.append(hl_df.loc[i, 'Relevance'])
hl_list.append(hl_df.loc[i, 'Founder'])
print(hl_list)
As matrizes não são mais do que vetores, contudo elas tem múltiplas dimensões, diferentemente dos vetores que é unidimensional (uma dimensão). Para montarmos uma matriz simples bidimensional iremos utilizar a biblioteca Numpy.
import numpy
hl_vector_1 = [hl_df.loc[0, 'Member'], hl_df.loc[1, 'Member']]
hl_vector_2 = [hl_df.loc[2, 'Member'], hl_df.loc[3, 'Member']]
hl_matrix = numpy.matrix([hl_vector_1, hl_vector_2])
print(hl_matrix)
Estrutura de dados tabular bidimensional, mutável em tamanho e potencialmente heterogênea, com eixos rotulados (linhas e colunas). As operações aritméticas são alinhadas nos rótulos de linha e coluna. Pode ser pensado como um contêiner do tipo ditado para objetos Series. A estrutura de dados principal dos Pandas.
-- Pandas
É importante ressaltar que apenas listas de tamanhos iguais podem formar um data frame!
Para esta operação utilizamos a biblioteca Pandas no qual, através do método pandas.DataFrame() construímos um data frame a partir de um dicionário.
hl_members = pandas.DataFrame({'Member': hl_df["Member"], 'Founder': hl_df['Founder']})
hl_members
hl_corp = pandas.DataFrame({'Member': hl_df["Member"], 'Hentai Lab Corp': hl_df['Hentai Lab Corp']})
hl_corp
hl_relevance = []
for i in range(0, 10):
hl_relevance.append(hl_df.loc[i,'Relevance'])
hl_relevance_factor = pandas.Series(hl_relevance, dtype='category')
hl_relevance_factor
hl_founder = []
for i in range(0, 10):
hl_founder.append(hl_df.loc[i,'Founder'])
hl_founder_factor = pandas.Series(hl_founder, dtype='category')
hl_founder_factor
Enquanto no R os campos que não há valor informado são chamados de NaN, no Python são chamados de None. Montamos um vetor com alguns campos com valores "não-respostas", ou seja, None para mostrarmos como seria.
none_vector = [12.3, 19.0, 65.14, None, None, 1.3, None]
none_vector
Contudo, o Python não tem uma função nativa para saber se um valor é None ou não, portanto cabe a nós desenvolver esta função ou utilizar uma biblioteca que já tenha ela, que no caso é o NumPy.
print(numpy.isnan(none_vector))
Mas, como mostra o erro acima, é necessário ter consciência de que o método numpy.isnan() do NumPy é limitado ao seu próprio valor nulo. Portanto, faremos das duas formas: construíremos um método para verificar o valor None e usaremos também o método numpy.isnan().
Começando pelo método do NumPy, vamos ajustar o vetor que criamos.
none_vector = [12.3, 19.0, 65.14, numpy.nan, numpy.nan, 1.3, numpy.nan]
none_vector
print(numpy.isnan(none_vector))
Aí está, o NumPy consegue identificar os valores nulos quando utilizamos o método da própria biblioteca para gerar seus próprios valores nulos.
Agora, vamos criar nosso próprio método de verificação.
def is_none(v):
none_vector = []
for i in v:
if i != None:
none_vector.append(False)
else:
none_vector.append(True)
return none_vector
Este é o método is_none(). Ele recebe como parâmetro um vetor. Dentro deste método há um vetor que receberá valores booleanos baseado na verificação do método. Ele verificará, em cada posição do vetor, onde há valor None e onde não há. No fim, ele retorna o vetor com os valores booleanos.
none_vector = [12.3, 19.0, 65.14, None, None, 1.3, None]
is_none(none_vector)
Subsetting é a capacidade do Python de retornar um ou mais valores baseado no número correspondente a posição do vetor. Ou seja, valor(es) correspondente(s) a posição 0 (no R é 1) de um certo vetor serão retornadas caso o programa seja ordenado a tal. Um exemplo disso é o que foi feito na apresentação dos integrantes do grupo.
hl_df[:3]
Aqui é selecionado apenas os três primeiros valores do data frame. Vamos usar o vetor de members criado anteriormente no tópico de vetores para aplicar o subsetting nele.
print(hl_names_vector[0])
print("\n=======================\n")
print(hl_names_vector[1:3])
print("\n=======================\n")
print(hl_names_vector[:10])
Agora, vamos utilizar o data frame inteiro para podermos ver como o subsetting se comporta quando aplica a ele.
print(hl_df['Member'].to_string(index=False))
Funciona da mesma forma que o subsetting apresentado anteriormente, porém ele trabalha com valores booleanos que são resultados de verificações de existência feitas pelo Python. Para entender melhor, observe:
is_polillo = hl_df.Member == "Matheus Marques Polillo"
hl_df.loc[is_polillo]
Como pode ser observado acima, a variável is_polillo carrega um vetor de valores booleanos, resultantes da verificação feita pelo restante da linha de código, analisando se há ou não o valor Matheus Marques Polillo dentro da coluna Members do data frame. No meio do vetor desta variável deverá haver um True responsável por avisar em que índice o valor Matheus Marques Polillo se encontra para que assim o dataframe.loc[] funcione. Veja o valor da variável:
is_polillo
Vamos fazer de outra forma. Desta vez, coletaremos apenas os membros fundadores do grupo, ou seja, que tem o valor booleano True na coluna Founder.
is_founder = hl_df.Founder == True
hl_df.loc[is_founder]
is_founder
Utilizando o mesmo dataset anterior, vamos coletar um dos valores do semestre que juntou-se e trocar de int para float.
hl_stj = hl_df.loc[0, 'Semester that joined']
type(hl_stj)
hl_stj = float(hl_stj)
type(hl_stj)
É possível fazer isso com vários tipos de valores. Vamos tentar com outros 2! Começaremos pelo Relevance e terminaremos com o Founder.
hl_r = hl_df.loc[0, 'Relevance']
type(hl_r)
hl_r = int(hl_r)
type(hl_r)
hl_f = hl_df.loc[0, 'Founder']
type(hl_f)
hl_f = str(hl_f)
type(hl_f)
Este método pertence a biblioteca Pandas, responsável por mesclar dois data frames. Função bastante parecida com as funções de join que usamos em SQL.
Para fazermos um merge() que funcione com excelência vamos usar dois data frames que tenham uma coluna e seus valores parecidos para que o método identifique quais são os valores iguais e, através disso, faça o merge com os valores pertencentes as linhas corretas. Para isso, vamos usar um data frame que irá coletar o nome dos membros e se ele é ou não fundador, e outro data frame que irá coletar o nome dos membros (pra fazer a associação com o outro data frame) e de qual corporação do HL ele pertence. Observe:
hl_corp_df = pandas.DataFrame({'Member': hl_df["Member"], 'Hentai Lab Corp': hl_df['Hentai Lab Corp']})
hl_member_df = pandas.DataFrame({'Member': hl_df["Member"], 'Founder': hl_df['Founder']})
hl_merge_df = pandas.merge(hl_corp_df, hl_member_df)
hl_merge_df
Vamos aplicar agora este conceito em um dataset retirado da internet e que iremos utilizar junto deste outro dataset montado a mão (o HL) no início do notebook. O dataset se chama Video Game Sales.
"This dataset contains a list of video games with sales greater than 100,000 copies."
por GregorySmith, usuário do Kaggle
Este dataset é 16.598x11 (16.598 amostras com 11 colunas).
vgs_data = pandas.read_csv("../../docs/vgsales.csv")
vgs_df = pandas.DataFrame(vgs_data)
vgs_df.head()
No caso deste dataset nós iremos aplicar a função merge() em um data frame com os jogos e sua distribuidora e em um outro data frame com as vendas apenas da Europa, também carregando a coluna de jogos para que tenham valores padrões que o método consiga enxergar para assim termos um data frame que mostre os jogos, suas distribuidoras e o número de vendas na Europa.
vgs_games_df = pandas.DataFrame({'Name': vgs_df['Name'], 'Publisher': vgs_df['Publisher']})
vgs_eu_sales_df = pandas.DataFrame({'Name': vgs_df['Name'], 'EU_Sales': vgs_df['EU_Sales']})
vgs_merge_df = pandas.merge(vgs_games_df, vgs_eu_sales_df)
vgs_merge_df[:10]
Diferentemente do merge() que une dois data frames em um data frame só (formatado), o concat() se preocupa em montar um data frame utilizando outros mas que se completam, ou seja, continuam na mesma coluna.
vgs_games_part1_df = pandas.DataFrame({'Name': vgs_df.loc[:4, 'Name']})
vgs_games_part2_df = pandas.DataFrame({'Name': vgs_df.loc[5:9, 'Name']})
vgs_concat_df = pandas.concat([vgs_games_part1_df, vgs_games_part2_df], ignore_index=True)
vgs_concat_df
O método replace() é muito útil pois é encarregado de sobrescrever dados apenas indicando a coluna em que tal dado deverá ser sobescrito e qual o dado anterior. Ele é bastante simples e pode ser de grande ajuda quando se trabalha com data frames muito grandes como é o caso do nosso Video Games Sales.
vgs_clone_df = vgs_df
vgs_clone_games_df = pandas.DataFrame({'Name': vgs_clone_df['Name'], 'Publisher': vgs_clone_df['Publisher']})
vgs_clone_game_replaced_df = vgs_clone_games_df['Name'].replace('Pokemon Red/Pokemon Blue', 'Smokémon')
vgs_clone_games_df = pandas.DataFrame({'Name': vgs_clone_game_replaced_df, 'Publisher': vgs_clone_df['Publisher']})
vgs_clone_games_df.head()
Para facilitar a visualização:
is_smokemon = vgs_clone_games_df.Name == 'Smokémon'
vgs_clone_games_df[is_smokemon]
vgs_clone_games_df.loc[4, 'Name']
Não encontramos nenhuma função em alguma biblioteca que possa executar este tipo de comando como é feito no R, portanto utilizamos o método query() cujo o nome já indica o que ele faz. Por se tratar de um método cujo a função é montar uma query utilizando o data frame como banco, então podemos fazer este tipo de consulta usando ele.
vgs_df.query('Global_Sales > 30')
O método groupby() é encarregado de, através de algum critério de separação (ou de seleção), os dados de um determinado data frame serão reorganizados em grupos, retornando um valor no formato de um data frame.
vgs_publisher_sales_df = pandas.DataFrame({'Publisher': vgs_df['Publisher'], 'Global_Sales': vgs_df['Global_Sales']})
vgs_publisher_sales_df.groupby(['Publisher']).mean().head()
vgs_df.head()
Os passos já foram feitos duas vezes, um para importação do dataset feito a mão e outro para a importação do dataset Video Game Sales, contudo será explicado melhor as etapas aqui. Primeiramente importamos o arquivo .csv a partir da rota de onde o arquivo está, após isso inserimos ele como parâmetro para o método pandas.DataFrame() responsável pela criação de um data frame. Observe o processo novamente:
vgs_data = pandas.read_csv("../../docs/vgsales.csv")
vgs_df = pandas.DataFrame(vgs_data)
Com isso já geramos o data frame que pode ser visto um pouco mais acima! Antes de fazer qualquer análise ou possíveis alterações, é necessário sabermos com que tipo de dados estamos lidando. Portanto, utilizamos o método dataframe.dtypes para sabermos qual o tipo de dado de cada coluna.
vgs_df.dtypes
Uma coisa que pode-se notar ao olhar o data frame e os data types é os nomes. Eles estão bem formatados, mas e se por acaso nós quisessemos alterá-los caso houvesse algum nome não formatado? Vamos alterar o nome de todas as colunas duas vezes: para não formato e, depois, para formatado novamente. Tudo isso utilizando o método dataframe.columns.
vgs_columns_unformatted = ['rank', 'name', 'platform', 'year', 'genre', 'publisher', 'na sales', 'eu sales', 'jp sales',
'other sales', 'global sales']
vgs_df.columns = vgs_columns_unformatted
vgs_df.head()
vgs_df.columns
Agora, vamos deixá-lo mais bonito, apresentável, formatado utilizando o mesmo método.
vgs_columns_formatted = ['Rank', 'Name', 'Platform', 'Year', 'Genre', 'Publisher', 'NA_Sales', 'EU_Sales', 'JP_Sales',
'Other_Sales', 'Global_Sales']
vgs_df.columns = vgs_columns_formatted
vgs_df.head()
vgs_df.columns
É possível até contar a quantidade de valores que cada dado da coluna apresenta. Por exemplo, quantas vezes a EA, Activision ou qualquer outra distribuidora aparece neste data frame? Com isso podemos deduzir até qual distribuidora teve mais jogos vendidos neste data frame.
vgs_df['Publisher'].value_counts().head()
Baseado nisso é possível deduzir que a EA teve a maior quantidade de jogos vendidos dentre todas as distribuidoras presentes neste dataset.
Para podermos ir mais fundo, vamos fazer o cálculo do desvio-padrão mas baseado nas vendais globais (Global_Sales) para saber o quanto varia. Para ser feito, usaremos o método numpy.std() da biblioteca NumPy que receberá como parâmetro o data frame e a coluna que quer saber o desvio-padrão.
vgs_standard_deviation = numpy.std(vgs_df['Global_Sales'])
vgs_standard_deviation
Contudo, caso queira o desvio-padrão de todas as colunas de vendas, também é possível.
vgs_sd_na = numpy.std(vgs_df['NA_Sales'])
vgs_sd_eu = numpy.std(vgs_df['EU_Sales'])
vgs_sd_jp = numpy.std(vgs_df['JP_Sales'])
vgs_sd_ot = numpy.std(vgs_df['Other_Sales'])
print('NA Sales Standard Deviation: ', vgs_sd_na)
print('EU Sales Standard Deviation: ', vgs_sd_eu)
print('JP Sales Standard Deviation: ', vgs_sd_jp)
print('Other Sales Standard Deviation: ', vgs_sd_ot)
print('Global Sales Standard Deviation: ', vgs_standard_deviation)
arr = [vgs_sd_na, vgs_sd_eu, vgs_sd_jp, vgs_sd_ot, vgs_standard_deviation]
print("arr : ", arr)
print("median of arr : ", numpy.median(arr))
Analisando a mediana do dataframe, chegamos ao valor 0.5053360078008797 como valor que o divide entre dois iguais.
import seaborn as sns
corrmat = vgs_data.corr()
cg = sns.clustermap(corrmat, cmap ="YlGnBu", linewidths = 0.1);
cg
corrmat = vgs_data.corr()
corrmat
Analisando as correlações dos anos em relação as vendas, concluímos que há correlação positiva se o ano e as vendas aumentam e diminuem quase sempre juntos. Se as vendas caem quase sempre que os anos passam,ou vice-versa, há correlação negativa. Se os aumentos e quedas nas vendas não tem efeito sobre o anos, não há correlação.
meanmat = vgs_data.mean()
meanmat
Analisando a média de vendas, concluímos que a américa do norte teve a maior média geral de vendas durante todo o periodo, enquanto que as vendas japão somaram a menor quantidade de vendas.
Para melhorar a forma como analisamos o data frame vamos construir alguns gráficos que resumem bastante o que queremos encontrar. Começaremos pelo clássico histograma, utilizando o método dataframe.plot() para construir um. Ele é customizável, portanto ajuda bastante na hora da análise.
Para fazermos nosso histograma iremos utilizar a coluna de ano (Year) do data frame para sabermos qual foi o ano que mais teve vendas.
vgs_histogram = vgs_df['Year'].plot(kind='hist', color='#6B07E6')
vgs_histogram.set_title('Vendas de títulos diferentes por ano')
vgs_histogram.set_xlabel('Ano')
vgs_histogram.set_ylabel('Quantidade')
O histograma indica que o período entre 2010 e 2014 foi o período que mais teve títulos diferentes vendidos. Portanto podemos admitir que este período foi o mais vasto em questão de títulos diferentes vendidos. Não podemos admitir que este período foi o que mais teve vendas, pois a contagem está sendo feita por quantidade de vezes em que este ano apareceu no dataset e, portanto, quantos títulos diferentes foram vendidos nesse ano.
Falando agora do código. Através do método dataframe.plot() criamos um histograma. É bom destacar que usamos a coluna Year dentro do dataframe para sinalizar ao método qual a coluna que queríamos plotar. Após isso, como parâmetros, passamos hist no kind para dizer que queríamos plotar um histograma e, por fim, o hexadecimal da cor roxa passada pelo color. Nas linhas de baixo apenas determinamos o título do histograma, o título do eixo X e o título do eixo Y!
Agora faremos um boxplot utilizando a mesma coluna (Year) para ver quais os anos tiveram menos títulos diferentes vendidos. Usando o mesmo método de plotar gráfico, porém mudamos apenas o hexadecimal da cor e a tag do kind, trocamos de hist para box, sinalizando para o método que queremos plotar um boxplot, não mais um histograma.
vgs_boxplot = vgs_df['Year'].plot(kind='box', color='#B105F0')
vgs_boxplot.set_title('Vendas de títulos diferentes por ano')
É nítido a quantidade extravagante de outliers neste boxplot, o que mostra que os períodos que sucederam mais ou menos os anos 94 em diante tiveram uma grande quantidade de títulos diferentes vendidos, enquanto os anos que antecederam esses períodos venderam muito menos, não é atoa que se apresentam como outliers.
vgs_scatterplot = vgs_df.plot.scatter(x='Year', y='NA_Sales', c='DarkBlue')
Analisando o gráfico scatterplot concluímos que as vendas na américa do norte aumentam com o passar dos anos, isso se dá principalmente ao sucesso de jogos como Wii Sports e Super mario Bros.