Integrantes do grupo

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.

In [1]:
import pandas

hl_data = pandas.read_csv('../../docs/hl_atividade_1.csv')
hl_df = pandas.DataFrame(hl_data)
hl_df[:3]
Out[1]:
Member Hentai Lab Corp Relevance Semester that joined Founder
0 Matheus Marques Polillo West 1.00 2 True
1 Thiago Aires West 1.00 2 True
2 Marcello Bertero West 0.97 3 False

Pré-processamento de dados

Character

Enquanto no R, o tipo de variável que representa dados em formato de texto é character, enquanto no Python é str (String). Usando type(), passando a variável que contém o dado como parâmetro do método podemos ver seu tipo.

In [2]:
type(hl_df.loc[0, 'Member'])
Out[2]:
str

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:

In [3]:
hl_df.loc[0, 'Member']
Out[3]:
'Matheus Marques Polillo'

Numeric

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.

In [4]:
type(hl_df.loc[2, 'Relevance'])
Out[4]:
numpy.float64

Para ficar melhor a visualização do valor float, observe o seguinte exemplo feito a mão:

In [5]:
peso = 76.2
type(peso)
Out[5]:
float

Ambos tem valores flutuantes, observe:

In [6]:
print('Valor no data frame:', hl_df.loc[2, 'Relevance'])
print('Valor da variável criada a mão:', peso)
Valor no data frame: 0.97
Valor da variável criada a mão: 76.2

Integer

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.

In [7]:
type(hl_df.loc[0, 'Semester that joined'])
Out[7]:
numpy.int64

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)!

In [8]:
qtdFilhos = 3
type(qtdFilhos)
Out[8]:
int
In [9]:
print('Valor no data frame:', hl_df.loc[0, 'Semester that joined'])
print('Valor da variável criada a mão:', qtdFilhos)
Valor no data frame: 2
Valor da variável criada a mão: 3

Logical

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.

In [10]:
type(hl_df.loc[0, 'Founder'])
Out[10]:
numpy.bool_

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:

In [11]:
temCarro = True
type(temCarro)
Out[11]:
bool
In [13]:
print('Valor no data frame:', hl_df.loc[0, 'Founder'])
print('Valor da variável criada a mão:', temCarro)
Valor no data frame: True
Valor da variável criada a mão: True

Vectors

"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."

-- Renata Florence dos Santos

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.

In [14]:
hl_relevance_vector = []
for i in range(0, 10):
    hl_relevance_vector.append(hl_df.loc[i, 'Relevance'])
hl_relevance_vector
Out[14]:
[1.0, 1.0, 0.97, 1.0, 1.0, 0.99, 0.22, 0.22, 0.58, 0.35]
In [15]:
hl_names_vector = []
for i in range(0, 10):
    hl_names_vector.append(hl_df.loc[i, 'Member'])
hl_names_vector
Out[15]:
['Matheus Marques Polillo',
 'Thiago Aires',
 'Marcello Bertero',
 'Felipe Leitão',
 'João Pedro Libonati',
 'Bruno Seiti',
 'Alexandre de Godoy',
 'Bruno Paes',
 'Miguel Kannan',
 'Guilherme Reis']

Lists

"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."

-- GeeksforGeeks

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().

In [16]:
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)
['Matheus Marques Polillo', 1.0, True, 'Thiago Aires', 1.0, True, 'Marcello Bertero', 0.97, False, 'Felipe Leitão', 1.0, True, 'João Pedro Libonati', 1.0, True, 'Bruno Seiti', 0.99, False, 'Alexandre de Godoy', 0.22, False, 'Bruno Paes', 0.22, False, 'Miguel Kannan', 0.58, False, 'Guilherme Reis', 0.35, False]

Matrizes

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.

In [17]:
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)
[['Matheus Marques Polillo' 'Thiago Aires']
 ['Marcello Bertero' 'Felipe Leitão']]

Data frame

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.

In [18]:
hl_members = pandas.DataFrame({'Member': hl_df["Member"], 'Founder': hl_df['Founder']})
hl_members
Out[18]:
Member Founder
0 Matheus Marques Polillo True
1 Thiago Aires True
2 Marcello Bertero False
3 Felipe Leitão True
4 João Pedro Libonati True
5 Bruno Seiti False
6 Alexandre de Godoy False
7 Bruno Paes False
8 Miguel Kannan False
9 Guilherme Reis False
In [19]:
hl_corp = pandas.DataFrame({'Member': hl_df["Member"], 'Hentai Lab Corp': hl_df['Hentai Lab Corp']})
hl_corp
Out[19]:
Member Hentai Lab Corp
0 Matheus Marques Polillo West
1 Thiago Aires West
2 Marcello Bertero West
3 Felipe Leitão East
4 João Pedro Libonati East
5 Bruno Seiti East
6 Alexandre de Godoy NaN
7 Bruno Paes NaN
8 Miguel Kannan NaN
9 Guilherme Reis NaN

Factors

Os factors são variáveis qualitativas que podem ser incluídas nos modelos.

In [20]:
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
Out[20]:
0    1.00
1    1.00
2    0.97
3    1.00
4    1.00
5    0.99
6    0.22
7    0.22
8    0.58
9    0.35
dtype: category
Categories (6, float64): [0.22, 0.35, 0.58, 0.97, 0.99, 1.00]
In [21]:
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
Out[21]:
0     True
1     True
2    False
3     True
4     True
5    False
6    False
7    False
8    False
9    False
dtype: category
Categories (2, object): [False, True]

Missing values

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.

In [22]:
none_vector = [12.3, 19.0, 65.14, None, None, 1.3, None]
none_vector
Out[22]:
[12.3, 19.0, 65.14, None, None, 1.3, None]

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.

In [23]:
print(numpy.isnan(none_vector))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-23-db8b7ee02edd> in <module>
----> 1 print(numpy.isnan(none_vector))

TypeError: ufunc 'isnan' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''

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.

In [24]:
none_vector = [12.3, 19.0, 65.14, numpy.nan, numpy.nan, 1.3, numpy.nan]
none_vector
Out[24]:
[12.3, 19.0, 65.14, nan, nan, 1.3, nan]
In [25]:
print(numpy.isnan(none_vector))
[False False False  True  True False  True]

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.

In [26]:
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.

In [28]:
none_vector = [12.3, 19.0, 65.14, None, None, 1.3, None]
In [29]:
is_none(none_vector)
Out[29]:
[False, False, False, True, True, False, True]

Subsetting

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.

In [30]:
hl_df[:3]
Out[30]:
Member Hentai Lab Corp Relevance Semester that joined Founder
0 Matheus Marques Polillo West 1.00 2 True
1 Thiago Aires West 1.00 2 True
2 Marcello Bertero West 0.97 3 False

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.

In [31]:
print(hl_names_vector[0])
print("\n=======================\n")
print(hl_names_vector[1:3])
print("\n=======================\n")
print(hl_names_vector[:10])
Matheus Marques Polillo

=======================

['Thiago Aires', 'Marcello Bertero']

=======================

['Matheus Marques Polillo', 'Thiago Aires', 'Marcello Bertero', 'Felipe Leitão', 'João Pedro Libonati', 'Bruno Seiti', 'Alexandre de Godoy', 'Bruno Paes', 'Miguel Kannan', 'Guilherme Reis']

Agora, vamos utilizar o data frame inteiro para podermos ver como o subsetting se comporta quando aplica a ele.

In [32]:
print(hl_df['Member'].to_string(index=False))
 Matheus Marques Polillo
            Thiago Aires
        Marcello Bertero
           Felipe Leitão
     João Pedro Libonati
             Bruno Seiti
      Alexandre de Godoy
              Bruno Paes
           Miguel Kannan
          Guilherme Reis

Logical subsetting

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:

In [33]:
is_polillo = hl_df.Member == "Matheus Marques Polillo"
hl_df.loc[is_polillo]
Out[33]:
Member Hentai Lab Corp Relevance Semester that joined Founder
0 Matheus Marques Polillo West 1.0 2 True

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:

In [34]:
is_polillo
Out[34]:
0     True
1    False
2    False
3    False
4    False
5    False
6    False
7    False
8    False
9    False
Name: Member, dtype: bool

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.

In [35]:
is_founder = hl_df.Founder == True
hl_df.loc[is_founder]
Out[35]:
Member Hentai Lab Corp Relevance Semester that joined Founder
0 Matheus Marques Polillo West 1.0 2 True
1 Thiago Aires West 1.0 2 True
3 Felipe Leitão East 1.0 2 True
4 João Pedro Libonati East 1.0 2 True
In [36]:
is_founder
Out[36]:
0     True
1     True
2    False
3     True
4     True
5    False
6    False
7    False
8    False
9    False
Name: Founder, dtype: bool

Conversão de tipos

Utilizando o mesmo dataset anterior, vamos coletar um dos valores do semestre que juntou-se e trocar de int para float.

In [37]:
hl_stj = hl_df.loc[0, 'Semester that joined']
type(hl_stj)
Out[37]:
numpy.int64
In [38]:
hl_stj = float(hl_stj)
type(hl_stj)
Out[38]:
float

É possível fazer isso com vários tipos de valores. Vamos tentar com outros 2! Começaremos pelo Relevance e terminaremos com o Founder.

In [39]:
hl_r = hl_df.loc[0, 'Relevance']
type(hl_r)
Out[39]:
numpy.float64
In [40]:
hl_r = int(hl_r)
type(hl_r)
Out[40]:
int
In [41]:
hl_f = hl_df.loc[0, 'Founder']
type(hl_f)
Out[41]:
numpy.bool_
In [42]:
hl_f = str(hl_f)
type(hl_f)
Out[42]:
str

Merge( )

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:

In [43]:
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
Out[43]:
Member Hentai Lab Corp Founder
0 Matheus Marques Polillo West True
1 Thiago Aires West True
2 Marcello Bertero West False
3 Felipe Leitão East True
4 João Pedro Libonati East True
5 Bruno Seiti East False
6 Alexandre de Godoy NaN False
7 Bruno Paes NaN False
8 Miguel Kannan NaN False
9 Guilherme Reis NaN False

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).

In [44]:
vgs_data = pandas.read_csv("../../docs/vgsales.csv")
vgs_df = pandas.DataFrame(vgs_data)

vgs_df.head()
Out[44]:
Rank Name Platform Year Genre Publisher NA_Sales EU_Sales JP_Sales Other_Sales Global_Sales
0 1 Wii Sports Wii 2006.0 Sports Nintendo 41.49 29.02 3.77 8.46 82.74
1 2 Super Mario Bros. NES 1985.0 Platform Nintendo 29.08 3.58 6.81 0.77 40.24
2 3 Mario Kart Wii Wii 2008.0 Racing Nintendo 15.85 12.88 3.79 3.31 35.82
3 4 Wii Sports Resort Wii 2009.0 Sports Nintendo 15.75 11.01 3.28 2.96 33.00
4 5 Pokemon Red/Pokemon Blue GB 1996.0 Role-Playing Nintendo 11.27 8.89 10.22 1.00 31.37

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.

In [45]:
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]
Out[45]:
Name Publisher EU_Sales
0 Wii Sports Nintendo 29.02
1 Super Mario Bros. Nintendo 3.58
2 Super Mario Bros. Nintendo 1.30
3 Super Mario Bros. Nintendo 3.58
4 Super Mario Bros. Nintendo 1.30
5 Mario Kart Wii Nintendo 12.88
6 Wii Sports Resort Nintendo 11.01
7 Pokemon Red/Pokemon Blue Nintendo 8.89
8 Tetris Nintendo 2.26
9 Tetris Nintendo 0.69

Concat( )

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.

In [46]:
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
Out[46]:
Name
0 Wii Sports
1 Super Mario Bros.
2 Mario Kart Wii
3 Wii Sports Resort
4 Pokemon Red/Pokemon Blue
5 Tetris
6 New Super Mario Bros.
7 Wii Play
8 New Super Mario Bros. Wii
9 Duck Hunt

Replace( )

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.

In [50]:
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()
Out[50]:
Name Publisher
0 Wii Sports Nintendo
1 Super Mario Bros. Nintendo
2 Mario Kart Wii Nintendo
3 Wii Sports Resort Nintendo
4 Smokémon Nintendo

Para facilitar a visualização:

In [53]:
is_smokemon = vgs_clone_games_df.Name == 'Smokémon'
vgs_clone_games_df[is_smokemon]
Out[53]:
Name Publisher
4 Smokémon Nintendo
In [54]:
vgs_clone_games_df.loc[4, 'Name']
Out[54]:
'Smokémon'

Subset( )

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.

In [55]:
vgs_df.query('Global_Sales > 30')
Out[55]:
Rank Name Platform Year Genre Publisher NA_Sales EU_Sales JP_Sales Other_Sales Global_Sales
0 1 Wii Sports Wii 2006.0 Sports Nintendo 41.49 29.02 3.77 8.46 82.74
1 2 Super Mario Bros. NES 1985.0 Platform Nintendo 29.08 3.58 6.81 0.77 40.24
2 3 Mario Kart Wii Wii 2008.0 Racing Nintendo 15.85 12.88 3.79 3.31 35.82
3 4 Wii Sports Resort Wii 2009.0 Sports Nintendo 15.75 11.01 3.28 2.96 33.00
4 5 Pokemon Red/Pokemon Blue GB 1996.0 Role-Playing Nintendo 11.27 8.89 10.22 1.00 31.37
5 6 Tetris GB 1989.0 Puzzle Nintendo 23.20 2.26 4.22 0.58 30.26
6 7 New Super Mario Bros. DS 2006.0 Platform Nintendo 11.38 9.23 6.50 2.90 30.01

GroupBy( )

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.

In [57]:
vgs_publisher_sales_df = pandas.DataFrame({'Publisher': vgs_df['Publisher'], 'Global_Sales': vgs_df['Global_Sales']})
vgs_publisher_sales_df.groupby(['Publisher']).mean().head()
Out[57]:
Global_Sales
Publisher
10TACLE Studios 0.036667
1C Company 0.033333
20th Century Fox Video Games 0.388000
2D Boy 0.040000
3DO 0.281111

Análise Descritiva

Análise sem gráfico

O dataset que iremos utilizar já foi importado e explicado anteriormente, é o Video Game Sales.

In [58]:
vgs_df.head()
Out[58]:
Rank Name Platform Year Genre Publisher NA_Sales EU_Sales JP_Sales Other_Sales Global_Sales
0 1 Wii Sports Wii 2006.0 Sports Nintendo 41.49 29.02 3.77 8.46 82.74
1 2 Super Mario Bros. NES 1985.0 Platform Nintendo 29.08 3.58 6.81 0.77 40.24
2 3 Mario Kart Wii Wii 2008.0 Racing Nintendo 15.85 12.88 3.79 3.31 35.82
3 4 Wii Sports Resort Wii 2009.0 Sports Nintendo 15.75 11.01 3.28 2.96 33.00
4 5 Pokemon Red/Pokemon Blue GB 1996.0 Role-Playing Nintendo 11.27 8.89 10.22 1.00 31.37

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:

In [59]:
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.

In [60]:
vgs_df.dtypes
Out[60]:
Rank              int64
Name             object
Platform         object
Year            float64
Genre            object
Publisher        object
NA_Sales        float64
EU_Sales        float64
JP_Sales        float64
Other_Sales     float64
Global_Sales    float64
dtype: object

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.

In [61]:
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()
Out[61]:
rank name platform year genre publisher na sales eu sales jp sales other sales global sales
0 1 Wii Sports Wii 2006.0 Sports Nintendo 41.49 29.02 3.77 8.46 82.74
1 2 Super Mario Bros. NES 1985.0 Platform Nintendo 29.08 3.58 6.81 0.77 40.24
2 3 Mario Kart Wii Wii 2008.0 Racing Nintendo 15.85 12.88 3.79 3.31 35.82
3 4 Wii Sports Resort Wii 2009.0 Sports Nintendo 15.75 11.01 3.28 2.96 33.00
4 5 Pokemon Red/Pokemon Blue GB 1996.0 Role-Playing Nintendo 11.27 8.89 10.22 1.00 31.37
In [62]:
vgs_df.columns
Out[62]:
Index(['rank', 'name', 'platform', 'year', 'genre', 'publisher', 'na sales',
       'eu sales', 'jp sales', 'other sales', 'global sales'],
      dtype='object')

Agora, vamos deixá-lo mais bonito, apresentável, formatado utilizando o mesmo método.

In [63]:
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()
Out[63]:
Rank Name Platform Year Genre Publisher NA_Sales EU_Sales JP_Sales Other_Sales Global_Sales
0 1 Wii Sports Wii 2006.0 Sports Nintendo 41.49 29.02 3.77 8.46 82.74
1 2 Super Mario Bros. NES 1985.0 Platform Nintendo 29.08 3.58 6.81 0.77 40.24
2 3 Mario Kart Wii Wii 2008.0 Racing Nintendo 15.85 12.88 3.79 3.31 35.82
3 4 Wii Sports Resort Wii 2009.0 Sports Nintendo 15.75 11.01 3.28 2.96 33.00
4 5 Pokemon Red/Pokemon Blue GB 1996.0 Role-Playing Nintendo 11.27 8.89 10.22 1.00 31.37
In [64]:
vgs_df.columns
Out[64]:
Index(['Rank', 'Name', 'Platform', 'Year', 'Genre', 'Publisher', 'NA_Sales',
       'EU_Sales', 'JP_Sales', 'Other_Sales', 'Global_Sales'],
      dtype='object')

É 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.

In [65]:
vgs_df['Publisher'].value_counts().head()
Out[65]:
Electronic Arts                 1351
Activision                       975
Namco Bandai Games               932
Ubisoft                          921
Konami Digital Entertainment     832
Name: Publisher, dtype: int64

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.

In [66]:
vgs_standard_deviation = numpy.std(vgs_df['Global_Sales'])
vgs_standard_deviation
Out[66]:
1.5549810910296504

Contudo, caso queira o desvio-padrão de todas as colunas de vendas, também é possível.

In [67]:
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)
NA Sales Standard Deviation:  0.8166584270779742
EU Sales Standard Deviation:  0.5053360078008797
JP Sales Standard Deviation:  0.3092813308358745
Other Sales Standard Deviation:  0.1885827217691664
Global Sales Standard Deviation:  1.5549810910296504
In [69]:
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)) 
arr :  [0.8166584270779742, 0.5053360078008797, 0.3092813308358745, 0.1885827217691664, 1.5549810910296504]
median of arr :  0.5053360078008797

Analisando a mediana do dataframe, chegamos ao valor 0.5053360078008797 como valor que o divide entre dois iguais.

In [73]:
import seaborn as sns 
corrmat = vgs_data.corr()
cg = sns.clustermap(corrmat, cmap ="YlGnBu", linewidths = 0.1);
  
cg
Out[73]:
<seaborn.matrix.ClusterGrid at 0x25bd898e550>
In [74]:
corrmat = vgs_data.corr()
corrmat
Out[74]:
Rank Year NA_Sales EU_Sales JP_Sales Other_Sales Global_Sales
Rank 1.000000 0.178814 -0.401362 -0.379123 -0.267785 -0.332986 -0.427407
Year 0.178814 1.000000 -0.091402 0.006014 -0.169316 0.041058 -0.074735
NA_Sales -0.401362 -0.091402 1.000000 0.767727 0.449787 0.634737 0.941047
EU_Sales -0.379123 0.006014 0.767727 1.000000 0.435584 0.726385 0.902836
JP_Sales -0.267785 -0.169316 0.449787 0.435584 1.000000 0.290186 0.611816
Other_Sales -0.332986 0.041058 0.634737 0.726385 0.290186 1.000000 0.748331
Global_Sales -0.427407 -0.074735 0.941047 0.902836 0.611816 0.748331 1.000000

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.

In [75]:
meanmat = vgs_data.mean()
meanmat
Out[75]:
Rank            8300.605254
Year            2006.406443
NA_Sales           0.264667
EU_Sales           0.146652
JP_Sales           0.077782
Other_Sales        0.048063
Global_Sales       0.537441
dtype: float64

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.


Análise com gráfico

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.

In [77]:
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')
Out[77]:
Text(0, 0.5, '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.

In [78]:
vgs_boxplot = vgs_df['Year'].plot(kind='box', color='#B105F0')
vgs_boxplot.set_title('Vendas de títulos diferentes por ano')
Out[78]:
Text(0.5, 1.0, '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.

In [81]:
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.