Universidade Estadual Paulista Júlio de Mesquita Filho (Unesp)

Faculdade de Ciências e Tecnologia de Presidente Prudente (FCT/Unesp)

Departamento de Matemática e Computação (DMC)

Programa de Pós-Graduação em Ciência da Computação (PPGCC/Unesp)

Visualização de Informação -- Turma 2020

Prof. Dr. Danilo Medeiros Eler

Aula 02 - Fundamentos sobre dados: Processamento dos dados

In [3]:
import numpy as np
import pandas as pd

Dados Ausentes

In [4]:
pesos = pd.Series([87.6, np.nan, 70.5, 90.5, None])
print(pesos)
0    87.6
1     NaN
2    70.5
3    90.5
4     NaN
dtype: float64
In [5]:
pesos.isnull()
Out[5]:
0    False
1     True
2    False
3    False
4     True
dtype: bool

Filtrando dados Ausentes

In [6]:
#remove os valores ausentes
pesos_semNAN = pesos.dropna()
print(pesos_semNAN)
0    87.6
2    70.5
3    90.5
dtype: float64
In [7]:
#tem o mesmo resultado que o dropna
pesos_semNAN2 = pesos[pesos.notnull()]
print(pesos_semNAN2)
0    87.6
2    70.5
3    90.5
dtype: float64
In [8]:
data = pd.DataFrame([['P1',1500.89,30,87.6,1,0],
                     ['P2',789.52,48,np.nan,2,0],
                     ['P3',1000.00,28,70.5,2,1],
                     ['P4',589.36,39,90.5,3,1]])
data
Out[8]:
0 1 2 3 4 5
0 P1 1500.89 30 87.6 1 0
1 P2 789.52 48 NaN 2 0
2 P3 1000.00 28 70.5 2 1
3 P4 589.36 39 90.5 3 1
In [9]:
data_limpo = data.dropna()
data_limpo
Out[9]:
0 1 2 3 4 5
0 P1 1500.89 30 87.6 1 0
2 P3 1000.00 28 70.5 2 1
3 P4 589.36 39 90.5 3 1
In [10]:
data_limpo = data.dropna(axis=1) #limpa as colunas
data_limpo
Out[10]:
0 1 2 4 5
0 P1 1500.89 30 1 0
1 P2 789.52 48 2 0
2 P3 1000.00 28 2 1
3 P4 589.36 39 3 1
In [11]:
data2 = pd.DataFrame([['P1',1500.89,30,87.6,1,0],
                     ['P2',789.52,48,np.nan,2,0],
                     ['P3',1000.00,28,70.5,2,1],
                     ['P4',589.36,39,90.5,3,1],
                     [np.nan,np.nan,np.nan,np.nan,np.nan,np.nan],
                     ['P6',589.36,39,90.5,np.nan,np.nan]])
data2
Out[11]:
0 1 2 3 4 5
0 P1 1500.89 30.0 87.6 1.0 0.0
1 P2 789.52 48.0 NaN 2.0 0.0
2 P3 1000.00 28.0 70.5 2.0 1.0
3 P4 589.36 39.0 90.5 3.0 1.0
4 NaN NaN NaN NaN NaN NaN
5 P6 589.36 39.0 90.5 NaN NaN
In [12]:
#remove as linhas com dados ausentes
data_limpo2 = data2.dropna()
data_limpo2
Out[12]:
0 1 2 3 4 5
0 P1 1500.89 30.0 87.6 1.0 0.0
2 P3 1000.00 28.0 70.5 2.0 1.0
3 P4 589.36 39.0 90.5 3.0 1.0
In [13]:
#limpa somente as linhas que estão totalmente preenchidas totalmente com dados ausentes
data_limpo2 = data2.dropna(how='all')
data_limpo2
Out[13]:
0 1 2 3 4 5
0 P1 1500.89 30.0 87.6 1.0 0.0
1 P2 789.52 48.0 NaN 2.0 0.0
2 P3 1000.00 28.0 70.5 2.0 1.0
3 P4 589.36 39.0 90.5 3.0 1.0
5 P6 589.36 39.0 90.5 NaN NaN
In [14]:
data3 = pd.DataFrame([['P1',1500.89,30,87.6,1,np.nan],
                     ['P2',789.52,48,np.nan,2,np.nan],
                     ['P3',1000.00,28,70.5,2,np.nan],
                     ['P4',589.36,39,90.5,3,np.nan],
                     [np.nan,np.nan,np.nan,np.nan,np.nan,np.nan],
                     ['P6',589.36,39,90.5,np.nan,np.nan]])
data3
Out[14]:
0 1 2 3 4 5
0 P1 1500.89 30.0 87.6 1.0 NaN
1 P2 789.52 48.0 NaN 2.0 NaN
2 P3 1000.00 28.0 70.5 2.0 NaN
3 P4 589.36 39.0 90.5 3.0 NaN
4 NaN NaN NaN NaN NaN NaN
5 P6 589.36 39.0 90.5 NaN NaN
In [15]:
#limpa somente as linhas que estão totalmente preenchidas totalmente com dados ausentes
data_limpo3 = data3.dropna(how='all') 
data_limpo3
Out[15]:
0 1 2 3 4 5
0 P1 1500.89 30.0 87.6 1.0 NaN
1 P2 789.52 48.0 NaN 2.0 NaN
2 P3 1000.00 28.0 70.5 2.0 NaN
3 P4 589.36 39.0 90.5 3.0 NaN
5 P6 589.36 39.0 90.5 NaN NaN
In [16]:
#limpa somente as colunas que estão totalmente preenchidas totalmente com dados ausentes
data_limpo3 = data3.dropna(how='all', axis=1) 
data_limpo3
Out[16]:
0 1 2 3 4
0 P1 1500.89 30.0 87.6 1.0
1 P2 789.52 48.0 NaN 2.0
2 P3 1000.00 28.0 70.5 2.0
3 P4 589.36 39.0 90.5 3.0
4 NaN NaN NaN NaN NaN
5 P6 589.36 39.0 90.5 NaN

Substituindo dados ausentes

In [17]:
data4 = pd.DataFrame([['P1',1500.89,30,87.6,1,0],
                     ['P2',789.52,48,np.nan,2,0],
                     ['P3',1000.00,28,70.5,2,1],
                     ['P4',589.36,39,90.5,3,1],
                     ['P5',900.00,np.nan,55.6,np.nan,np.nan],
                     ['P6',589.36,39,90.5,np.nan,np.nan]])
data4
Out[17]:
0 1 2 3 4 5
0 P1 1500.89 30.0 87.6 1.0 0.0
1 P2 789.52 48.0 NaN 2.0 0.0
2 P3 1000.00 28.0 70.5 2.0 1.0
3 P4 589.36 39.0 90.5 3.0 1.0
4 P5 900.00 NaN 55.6 NaN NaN
5 P6 589.36 39.0 90.5 NaN NaN
In [18]:
#substitui NAN por um valor
data_zero = data4.fillna(0) 
data_zero
Out[18]:
0 1 2 3 4 5
0 P1 1500.89 30.0 87.6 1.0 0.0
1 P2 789.52 48.0 0.0 2.0 0.0
2 P3 1000.00 28.0 70.5 2.0 1.0
3 P4 589.36 39.0 90.5 3.0 1.0
4 P5 900.00 0.0 55.6 0.0 0.0
5 P6 589.36 39.0 90.5 0.0 0.0
In [19]:
#medidas estatísticas do dataframe -- desconsidera o NAN
data4.describe() 
Out[19]:
1 2 3 4 5
count 6.000000 5.000000 5.000000 4.000000 4.00000
mean 894.855000 36.800000 78.940000 2.000000 0.50000
std 339.443726 8.043631 15.477823 0.816497 0.57735
min 589.360000 28.000000 55.600000 1.000000 0.00000
25% 639.400000 30.000000 70.500000 1.750000 0.00000
50% 844.760000 39.000000 87.600000 2.000000 0.50000
75% 975.000000 39.000000 90.500000 2.250000 1.00000
max 1500.890000 48.000000 90.500000 3.000000 1.00000
In [20]:
#usar dicionario para indicar valores distintos para cada atributo
#substitui NAN pelo valor da media -- conforme apresentado na célula anterior
data_media = data4.fillna({1:894.85, 2:36.80, 3:78.94, 4: 2, 5: 1}) #tomar cuidado com atributo booleano
data_media
Out[20]:
0 1 2 3 4 5
0 P1 1500.89 30.0 87.60 1.0 0.0
1 P2 789.52 48.0 78.94 2.0 0.0
2 P3 1000.00 28.0 70.50 2.0 1.0
3 P4 589.36 39.0 90.50 3.0 1.0
4 P5 900.00 36.8 55.60 2.0 1.0
5 P6 589.36 39.0 90.50 2.0 1.0
In [21]:
#medidas estatísticas após substituição
data_media.describe() 
Out[21]:
1 2 3 4 5
count 6.000000 6.000000 6.000000 6.000000 6.000000
mean 894.855000 36.800000 78.940000 2.000000 0.666667
std 339.443726 7.194442 13.843786 0.632456 0.516398
min 589.360000 28.000000 55.600000 1.000000 0.000000
25% 639.400000 31.700000 72.610000 2.000000 0.250000
50% 844.760000 37.900000 83.270000 2.000000 1.000000
75% 975.000000 39.000000 89.775000 2.000000 1.000000
max 1500.890000 48.000000 90.500000 3.000000 1.000000
In [22]:
data4
Out[22]:
0 1 2 3 4 5
0 P1 1500.89 30.0 87.6 1.0 0.0
1 P2 789.52 48.0 NaN 2.0 0.0
2 P3 1000.00 28.0 70.5 2.0 1.0
3 P4 589.36 39.0 90.5 3.0 1.0
4 P5 900.00 NaN 55.6 NaN NaN
5 P6 589.36 39.0 90.5 NaN NaN
In [23]:
# modo automatico -- entretanto, deve-se tomar cuidado com o booleano -- note que ele não foi alterado nesse momento
# e deve ser alterado manualmente -- ou por algum metodo automatico de contagem ou outra estratégia
# data4.mean calcula as médias por atributo e fillna preenche os dados ausentes
data4.fillna(data4.mean()[0:4]) 
Out[23]:
0 1 2 3 4 5
0 P1 1500.89 30.0 87.60 1.0 0.0
1 P2 789.52 48.0 78.94 2.0 0.0
2 P3 1000.00 28.0 70.50 2.0 1.0
3 P4 589.36 39.0 90.50 3.0 1.0
4 P5 900.00 36.8 55.60 2.0 NaN
5 P6 589.36 39.0 90.50 2.0 NaN
In [24]:
#note que o data4 ainda não foi modificado, pois fillna retorna um novo dataframe
data4 
Out[24]:
0 1 2 3 4 5
0 P1 1500.89 30.0 87.6 1.0 0.0
1 P2 789.52 48.0 NaN 2.0 0.0
2 P3 1000.00 28.0 70.5 2.0 1.0
3 P4 589.36 39.0 90.5 3.0 1.0
4 P5 900.00 NaN 55.6 NaN NaN
5 P6 589.36 39.0 90.5 NaN NaN
In [25]:
#altera o data4 (inplace)
data4.fillna({1:894.85, 2:36.80, 3:78.94, 4: 2, 5: 1}, inplace=True) 
data4
Out[25]:
0 1 2 3 4 5
0 P1 1500.89 30.0 87.60 1.0 0.0
1 P2 789.52 48.0 78.94 2.0 0.0
2 P3 1000.00 28.0 70.50 2.0 1.0
3 P4 589.36 39.0 90.50 3.0 1.0
4 P5 900.00 36.8 55.60 2.0 1.0
5 P6 589.36 39.0 90.50 2.0 1.0
In [26]:
data5 = pd.DataFrame([['P1',1500.89,30,87.6,1,0],
                     ['P2',789.52,48,np.nan,2,0],
                     ['P3',1000.00,28,70.5,2,1],
                     ['P4',589.36,39,90.5,3,1],
                     ['P5',900.00,np.nan,55.6,np.nan,np.nan],
                     ['P6',589.36,39,90.5,np.nan,np.nan]])
data5
Out[26]:
0 1 2 3 4 5
0 P1 1500.89 30.0 87.6 1.0 0.0
1 P2 789.52 48.0 NaN 2.0 0.0
2 P3 1000.00 28.0 70.5 2.0 1.0
3 P4 589.36 39.0 90.5 3.0 1.0
4 P5 900.00 NaN 55.6 NaN NaN
5 P6 589.36 39.0 90.5 NaN NaN
In [27]:
#ffill replica o valor anterior para os ausentes subsequentes -- tomar cuidado
data5.fillna(method='ffill') 
Out[27]:
0 1 2 3 4 5
0 P1 1500.89 30.0 87.6 1.0 0.0
1 P2 789.52 48.0 87.6 2.0 0.0
2 P3 1000.00 28.0 70.5 2.0 1.0
3 P4 589.36 39.0 90.5 3.0 1.0
4 P5 900.00 39.0 55.6 3.0 1.0
5 P6 589.36 39.0 90.5 3.0 1.0

Normalização

In [28]:
from sklearn import preprocessing
In [29]:
data6 = pd.DataFrame([[1500.89,30,87.6,1,0],
                      [789.52,48,67.5,2,0],
                      [1000.00,28,70.5,2,1],
                      [589.36,39,90.5,3,1]])
In [30]:
#normalização pelo máximo (valor / max) -- considera que o menor valor é sempre zero, mesmo não aparecendo nos dados
data7 = data6 / data6.max()
data7
Out[30]:
0 1 2 3 4
0 1.000000 0.625000 0.967956 0.333333 0.0
1 0.526035 1.000000 0.745856 0.666667 0.0
2 0.666271 0.583333 0.779006 0.666667 1.0
3 0.392674 0.812500 1.000000 1.000000 1.0
In [31]:
valores = data6.values
valores
Out[31]:
array([[1.50089e+03, 3.00000e+01, 8.76000e+01, 1.00000e+00, 0.00000e+00],
       [7.89520e+02, 4.80000e+01, 6.75000e+01, 2.00000e+00, 0.00000e+00],
       [1.00000e+03, 2.80000e+01, 7.05000e+01, 2.00000e+00, 1.00000e+00],
       [5.89360e+02, 3.90000e+01, 9.05000e+01, 3.00000e+00, 1.00000e+00]])
In [32]:
min_max = preprocessing.MinMaxScaler() #normalização entre o valor mínimo e o valor máximo == mínimo é zero e o máximo é um
valores_normalizados = min_max.fit_transform(valores)
data8 = pd.DataFrame(valores_normalizados)
data8
Out[32]:
0 1 2 3 4
0 1.000000 0.10 0.873913 0.0 0.0
1 0.219587 1.00 0.000000 0.5 0.0
2 0.450495 0.00 0.130435 0.5 1.0
3 0.000000 0.55 1.000000 1.0 1.0

Calcular Distância

In [33]:
from sklearn.neighbors import DistanceMetric
dist = DistanceMetric.get_metric('euclidean')
In [34]:
data9 = pd.DataFrame([[1500.89,30,87.6,1,0],
                      [789.52,48,67.5,2,0],
                      [1000.00,28,70.5,2,1],
                      [589.36,39,90.5,3,1]])
data9
Out[34]:
0 1 2 3 4
0 1500.89 30 87.6 1 0
1 789.52 48 67.5 2 0
2 1000.00 28 70.5 2 1
3 589.36 39 90.5 3 1
In [35]:
dist.pairwise(data9.to_numpy()) #calculo de distância com todos os atributos
Out[35]:
array([[  0.        , 711.8822142 , 501.18779125, 911.58178509],
       [711.8822142 ,   0.        , 211.4517212 , 201.68298292],
       [501.18779125, 211.4517212 ,   0.        , 411.27510209],
       [911.58178509, 201.68298292, 411.27510209,   0.        ]])
  • Exemplo da Aula - dados faltantes
In [36]:
data10 = pd.DataFrame([[1500.89,30,87.6,1,0],
                      [789.52,48,np.nan,2,0],
                      [1000.00,28,70.5,2,1],
                      [589.36,39,90.5,3,1]])
data10
Out[36]:
0 1 2 3 4
0 1500.89 30 87.6 1 0
1 789.52 48 NaN 2 0
2 1000.00 28 70.5 2 1
3 589.36 39 90.5 3 1
In [37]:
data10.dropna(axis=1) #remove a coluna que possui dado faltante
Out[37]:
0 1 3 4
0 1500.89 30 1 0
1 789.52 48 2 0
2 1000.00 28 2 1
3 589.36 39 3 1
In [38]:
valores = data10.dropna(axis=1).to_numpy()
print(valores)
[[1.50089e+03 3.00000e+01 1.00000e+00 0.00000e+00]
 [7.89520e+02 4.80000e+01 2.00000e+00 0.00000e+00]
 [1.00000e+03 2.80000e+01 2.00000e+00 1.00000e+00]
 [5.89360e+02 3.90000e+01 3.00000e+00 1.00000e+00]]
In [39]:
#caula a distancia -- menor distância para P2 é 200 (P4) --- menor distância para linha 1 é a linha 3 ==> 200.36
dist.pairwise(valores)
Out[39]:
array([[  0.        , 711.5983958 , 500.8959893 , 911.57717221],
       [711.5983958 ,   0.        , 211.43043868, 200.36722686],
       [500.8959893 , 211.43043868,   0.        , 410.78852175],
       [911.57717221, 200.36722686, 410.78852175,   0.        ]])
In [40]:
#desconsiderando salario
valores2 = np.delete(valores, 0, 1)#remove salario
print(valores2)
[[30.  1.  0.]
 [48.  2.  0.]
 [28.  2.  1.]
 [39.  3.  1.]]
In [41]:
#note que a linha 3 ainda é a mais próxima, mas a linha 0 seria a segunda mais próxima, nesse caso
dist.pairwise(valores2)
Out[41]:
array([[ 0.        , 18.02775638,  2.44948974,  9.2736185 ],
       [18.02775638,  0.        , 20.02498439,  9.11043358],
       [ 2.44948974, 20.02498439,  0.        , 11.04536102],
       [ 9.2736185 ,  9.11043358, 11.04536102,  0.        ]])
In [42]:
#normalizados pelo máximo
valores = data7.dropna(axis=1).to_numpy()
print(valores)
valores3 = np.delete(valores, 2, 1)#remove atributo peso
print(valores3)
print('\nDistancias:')
dist.pairwise(valores3) #calcula distancia -- linha 0 é mais próxima de linha 1 ==> 0.69
[[1.         0.625      0.9679558  0.33333333 0.        ]
 [0.52603455 1.         0.74585635 0.66666667 0.        ]
 [0.66627135 0.58333333 0.77900552 0.66666667 1.        ]
 [0.39267368 0.8125     1.         1.         1.        ]]
[[1.         0.625      0.33333333 0.        ]
 [0.52603455 1.         0.66666667 0.        ]
 [0.66627135 0.58333333 0.66666667 1.        ]
 [0.39267368 0.8125     1.         1.        ]]

Distancias:
Out[42]:
array([[0.        , 0.6902024 , 1.10644568, 1.35957565],
       [0.6902024 , 0.        , 1.0923724 , 1.07891264],
       [1.10644568, 1.0923724 , 0.        , 0.48834839],
       [1.35957565, 1.07891264, 0.48834839, 0.        ]])
In [43]:
#como o atributo booleano 'aprovado' pode assumir 0 ou 1, ele está nos dois extremos
#Se removermos esse atributo o resultado pode ser diferente, como ilustrado abaixo
#normalizados pelo máximo
valores = data7.dropna(axis=1).to_numpy()
print(valores)
valores3 = np.delete(valores, 2, 1)#remove atributo 'peso'
print(valores3)
valores3 = np.delete(valores3, 3, 1)#remove atributo 'aprovado'
print(valores3)
print('\nDistancias:')
dist.pairwise(valores3) #calcula distancia -- linha 3 é mais próxima de linha 1 ==> 0.40
[[1.         0.625      0.9679558  0.33333333 0.        ]
 [0.52603455 1.         0.74585635 0.66666667 0.        ]
 [0.66627135 0.58333333 0.77900552 0.66666667 1.        ]
 [0.39267368 0.8125     1.         1.         1.        ]]
[[1.         0.625      0.33333333 0.        ]
 [0.52603455 1.         0.66666667 0.        ]
 [0.66627135 0.58333333 0.66666667 1.        ]
 [0.39267368 0.8125     1.         1.        ]]
[[1.         0.625      0.33333333]
 [0.52603455 1.         0.66666667]
 [0.66627135 0.58333333 0.66666667]
 [0.39267368 0.8125     1.        ]]

Distancias:
Out[43]:
array([[0.        , 0.6902024 , 0.47352089, 0.92111126],
       [0.6902024 , 0.        , 0.43963333, 0.40503393],
       [0.47352089, 0.43963333, 0.        , 0.48834839],
       [0.92111126, 0.40503393, 0.48834839, 0.        ]])
In [44]:
#normalizados pelo min-max - considerando também o atributo 'aprovado'
valores = data8.dropna(axis=1).to_numpy()
print(valores)
valores4 = np.delete(valores, 2, 1)#remove atributo peso
print(valores4)
print('\nDistancias:')
dist.pairwise(valores4) #calcula distancia -- linha 3 é mais próxima de linha 1 ==> 1.22
[[1.         0.1        0.87391304 0.         0.        ]
 [0.21958685 1.         0.         0.5        0.        ]
 [0.45049532 0.         0.13043478 0.5        1.        ]
 [0.         0.55       1.         1.         1.        ]]
[[1.         0.1        0.         0.        ]
 [0.21958685 1.         0.5        0.        ]
 [0.45049532 0.         0.5        1.        ]
 [0.         0.55       1.         1.        ]]

Distancias:
Out[44]:
array([[0.        , 1.29191512, 1.24978214, 1.78955302],
       [1.29191512, 0.        , 1.43294059, 1.22503812],
       [1.24978214, 1.43294059, 0.        , 0.86916399],
       [1.78955302, 1.22503812, 0.86916399, 0.        ]])
  • Substituição por distância
In [59]:
from sklearn.impute import KNNImputer
# atualiza valores faltantes com base em vizinho mais próximo, no caso, foi definido 1 vizinho
imputer = KNNImputer(n_neighbors=1, weights="uniform")

data11 = pd.DataFrame([[1500.89,30,87.6,1,0],
                      [789.52,48,np.nan,2,0],
                      [1000.00,28,70.5,2,1],
                      [589.36,39,90.5,3,1]])
data11
Out[59]:
0 1 2 3 4
0 1500.89 30 87.6 1 0
1 789.52 48 NaN 2 0
2 1000.00 28 70.5 2 1
3 589.36 39 90.5 3 1
In [60]:
#atualização do peso que estava como NA -- criação de um dataframe com o resultado
pd.DataFrame(imputer.fit_transform(data11))
Out[60]:
0 1 2 3 4
0 1500.89 30.0 87.6 1.0 0.0
1 789.52 48.0 90.5 2.0 0.0
2 1000.00 28.0 70.5 2.0 1.0
3 589.36 39.0 90.5 3.0 1.0