• Nenhum resultado encontrado

Construir a matriz disjunta: laid_a.py

A.2   Implementação do algoritmo LAID

A.2.1   Construir a matriz disjunta: laid_a.py

1 #!/usr/bin/python3 2 # coding: utf-8 3

4 ##################################################### 5 # # 6 # Script para construir a matriz disjunta # 7 # # 8 ##################################################### 9 10 import h5py 11 import numpy as np 12 import sys

13 import datetime, time 14 import math

15

16 # Função que determina e formata o tempo decorrido entre dois instantes

17 # Parâmetros: xti - tempo inicial 18 # xtf - tempo final

19 # Retorno: xitf - intervalo de tempo formatado

20 def fintervalotempo(xti, xtf):

21 xit = abs(xtf - xti) # Intervalo de tempo decorrido 22 # Determinar as horas, minutos e segundos

23 xhoras = int(xit/3600)

24 xminutos = int(xit/60)-xhoras*60

25 xsegundos = xit-xminutos*60-xhoras*3600

26 # Formatar o intervalo de tempo em horas:minutos:segundos

27 if xit < 60:

28 xitf = '{0:.1f} segundos'.format(xsegundos)

29 elif xit < 3600:

30 xitf = '{0} minutos e {1:.1f} segundos'.format(xminutos, xsegundos)

31 else:

32 xitf = '{0} horas, {1} minutos e {2:.1f} segundos'.format(xhoras, xminutos, xsegundos) 33 # Retornar o intervalo de tempo formatado 34 return xitf;

35

36 # ********** Início de execução do script ********** 37

38 # Testar o número de argumentos de chamada do script

39 if len(sys.argv) != 2:

40 raise SystemExit('O script "'+sys.argv[0]+'" tem um

argumento:\n\tnome_da_bd\n') 41

42 # Indicar a hora de início da execução

43 print('Hora inicial: '+datetime.datetime.now().strftime('%H:%M:%S')) 44 xti = time.time() # guardar a hora de início da execução do script 45

47 xnomef = 'bd'+sys.argv[1]+'.h5' # construir o nome do ficheiro da BD 48 xfich = h5py.File(xnomef, 'r+')

49

50 # Inicializar variáveis

51 xll = '\033[K' # sequência de escape ANSI para limpar a linha do cursor no terminal

52 xdt = np.dtype(np.int8) # definir a precisão dos inteiros a usar 53 xds_d = xfich['dados'] # dataset com os dados

54 xds_ma = xfich['ma'] # dataset com a matriz A 55 xna = xds_d.attrs['xna'] # número de atributos

56 xnj = xds_d.attrs['xnj'] # número máximo de atributos jnsq 57 xnac = xds_d.attrs['xnac'] # número de atributos classe 58 xno = xds_d.attrs['xno'] # número de observações

59 xnc = xds_d.attrs['xnc'] # número de valores diferentes para cada atributo classe

60 xntc = xna+xnj+xnac # número total de colunas

61 xsalto = int(10000000/xno) # número de colunas a tratar de cada vez,

formando um bloco de colunas

62 xini = 0 # coluna inicial do bloco de colunas

63 xordem = np.zeros((xno), dtype=int) # guarda a ordem de ordenação das observações, observações com atributos iguais têm a mesma ordem

64 xpos = np.arange((xno), dtype=int) # guarda a posição das observações no dataset

65 xfim = int(xntc/xsalto)+1 # número de blocos de colunas a tratar

66 xf = 1000 # frequência de impressão da progressão das iterações

67

68 # Obter a sequência das observações ordenadas pelos atributos

69 print('{0:10d}/{1} ... A ordenar observações ... '.format(0, xfim),

end='\r')

70 for i in range(xfim):

71 # Redefinir xsalto caso o último bloco ultrapasse o nº total de colunas

72 if xini+xsalto > xntc: 73 xsalto = xntc - xini 74 # Ler os dado do bloco

75 xleitura = xds_d[:,xini:xini+xsalto]

76 xleitura = xleitura[xpos] # ordenar as observações pela ordem definida na iteração anterior, ou seja, do bloco anterior

77 # Juntar os arrays xordem, xleitura, xpos numa única matriz

78 xmatriz = np.zeros((xno,xsalto+2), dtype=int)

79 xmatriz[:,0] = xordem[:]

80 xmatriz[:,1:xsalto+1] = xleitura[:,:]

81 xmatriz[:,xsalto+1] = xpos[:]

82 xi = np.lexsort(np.fliplr(xmatriz).T) # determina os índices de ordem das observações (começa por inverter a ordem das colunas, faz a transposta e determina o índice de ordem das colunas)

83 xmatriz = xmatriz[xi] # ordena as linhas da matriz segundo os índices de ordem

84 xordem[0] = 0 # a primeira observação tem número de ordem zero

85 # Testar se cada linha da matriz è igual à anterior

86 for j in range(1,xno):

87 if xini < xntc - xnj - xnac: # se xini é uma coluna correspondente a um atributo

88 if np.array_equal(xmatriz[j,0:xsalto+1],

xmatriz[j-1,0:xsalto+1]): # se uma linha é igual à anterior fica com o mesmo valor

de ordem

90 elif xini+xsalto == xntc and

np.array_equal(xmatriz[j,0:xsalto-xnac-xnj+1], xmatriz[j-1,0

:xsalto-xnac-xnj+1]): # semelhante ao anterior, no caso de ser o último bloco

91 xordem[j]=xordem[j-1]

92 else: # no caso de não serem iguais a ordem da linha fica com o valor seguinte ao da anterior

93 xordem[j]=xordem[j-1]+1

94 xpos = xmatriz[:,xsalto+1] # depois da matriz ordenada, é guardada

a posição que cada linha/observação tem no dataset

95 xini += xsalto # é atualizada a coluna inicial do próximo bloco

96 print('{0:10d}'.format(i+1), end='\r')

97 print(xll+'»»» As observações estão ordenadas.') 98

99 # Determinar as observações redundantes e as inconsistentes

100 print('{0:10d}/{1} ... A determinar redundâncias e inconsistências

...'.format(0, xno), end='\r')

101 xor = np.zeros((xno), dtype=int) # lista de redundâncias - guarda a posição das observações redundantes

102 xpr = 0 # posição das observações redundantes na lista de

redundâncias (nº de observações redundantes sem contar com a última de cada grupo)

103 xoi = np.zeros((xno,2), dtype=int) # lista de inconsistências -

guarda a posição das observações inconsistentes e respetivo número da inconsistência

104 xpi = 0 # posição das observações inconsistentes na lista de

inconsistências (nº de observações inconsistentes)

105 xnoi = -1 # número de inconsistências diferentes - 1, para

corresponder ao índice de xoi (que começa em zero)

106 xleitura_c = xmatriz[:,xsalto] # leitura da coluna do atributo classe

107 if xordem[0] == xordem[1]: # testa se a primeira observações da

matriz ordenada é igual à seguinte, ou seja, se os atributos são iguais

108 if (xleitura_c[0] != xleitura_c[1]): # se o valor da classe é

diferente a primeira linha da matriz faz parte duma inconsistência

109 xnoi += 1 # foi encontrada a primeira inconsistência

110 xoi[xnoi,:] = [xpos[0],xnoi] # é guardada a posição da primeira

linha e respetivo nº de inconsistência

111 xpi += 1

112 for i in range(1,xno): # para as restantes linhas

113 if xordem[i] == xordem[i-1]: # se os atributos de uma linha são

iguais aos da linha anterior é redundância ou inconsistência

114 if xleitura_c[i] == xleitura_c[i-1]: # se os valores da classe

são iguais a linha é redundante com a anterior

115 if (xpos[i-1] not in xoi[:xpi,0]) and (xpos[i-1] not in

xor[:xpr]): # se a linha anterior não era inconsistente nem redundante

116 xor[xpr] = xpos[i-1] # acrescentar a posição da linha

anterior à lista de redundâncias (num par redundante, é a primeira linha que é marcada)

117 # marca-se a anterior porque R Rx I a segunda era retirada e não era marcada como inconsistente, assim fica Rx RI I 118 else:

119 xor[xpr] = xpos[i] # se a anterior já estava marcada como inconsistente ou redundante, acrescentar a posição da linha à lista de redundâncias

120 xpr += 1

121 else: # se os valores da classe são diferentes as linhas são inconsistentes

122 if (xpos[i-1] not in xoi[:xpi,0]) and (xpos[i-1] not in

xor[:xpr]): # se a linha anterior não era inconsistente nem redundante

124 xoi[xpi,:] = [xpos[i-1],xnoi] # acrescentar a posição da linha anterior à lista de inconsistências

125 xpi += 1

126 xoi[xpi,:] = [xpos[i],xnoi] # acrescentar a posição da linha à lista de inconsistências

127 xpi += 1

128 print('{0:10d}'.format(i+1), end='\r')

129 # Redimensionar as listas ao número de redundâncias e inconsistências, respetivamente

130 xor = xor[:xpr] 131 xoi = xoi[:xpi]

132 print(xll+'»»» As redundâncias ({0}) e inconsistências ({1}) estão

determinadas.'.format(xpr,int(xpi/2)))

133

134 # Preencher as colunas jnsq

135 xnje = 0 # número de atributos jnsq efetivos

136 xleitura_j = np.zeros((xno,xnj), dtype=xdt) # inicializar atributos jnsq

137 if xnoi > -1: # se foram encontradas inconsistências

138 xnii = np.bincount(xoi[:,1]) # contabiliza a quantidade de

observações para cada nº de inconsistência (segunda coluna de xoi dá o nº da inconsistência)

139 xniimax = np.amax(xnii) # determina o máximo de xnii 140 print('{0:10d}/{1} ... A prencher a(s) coluna(s) jnsq

...'.format(0, np.size(xnii)), end='\r')

141 xp = 0 # posição na lista xoi

142 for i in range(np.size(xnii)): # para cada nº de inconsistência de xnii

143 for j in range(xnii[i]): # para cada valor inferior à quantidade de observações para cada nº de inconsistência

144 # Determinar o código binário para preencher as colunas jnsq das observações inconsistentes

145 xbin = j # posição de uma observação na quantidade de observações do seu nº de inconsistência

146 for k in range(xnj): # para cada coluna jnsq

147 xleitura_j[xoi[xp,0],k] = xbin%2 # resto da divisão –

valor binário para a coluna jnsq

148 xbin = xbin//2 # quociente da divisão - valor que passa

para a coluna jnsq seguinte

149 if xleitura_j[xoi[xp,0],k] > 0 and k+1 > xnje: # se uma

coluna jnsq tiver um valor não nulo e ainda não tiver sido contabilizada como efetiva

150 xnje += 1 # a coluna jnsq passa a efetiva

151 xp += 1

152 print('{0:10d}'.format(i), end='\r') 153 # popular os atributos jnsq

154 xds_d[:,xna:xna+xnj] = xleitura_j[...]

155 if xnje == 1:

156 print(xll+'»»» A coluna jnsq está preenchida.')

157 elif xnje == 0:

158 print(xll+'»»» Não existem atributos jnsq.') 159 else:

160 print(xll+'»»» As colunas jnsq ({0}) estão preenchidas.'.format(xnje))

161 # Atualizar o metadado xnje - número de atributos jnsq efetivos 162 xds_d.attrs['xnje'] = xnje

163

165 print('{0:10d}/{1} ... A construir a matriz disjunta ...'.format(0, int((xno-1)*xno/2/xf)), end='\r')

166 xleitura_m = np.zeros((xna+xnj), dtype=xdt) 167 xleitura_c = xds_d[...,xna+xnj:xna+xnj+xnac]

168 xnlma = 0 # inicializar o nº de linhas da matriz disjunta A

169 xitr = 0 # contabiliza o nº de iterações

170 for i in range(xno-1):

171 if (i not in xor): # não são consideradas as observações redundantes

172 xleitura_mi = xds_d[i,:xna+xnj] # ler os valores dos atributos e das colunas jnsq da observação a comparar

173 for j in range(i+1, xno): # compara a observação atual com as

observações das linhas seguintes

174 if (j not in xor) and (xleitura_c[i]!=xleitura_c[j]): # caso a observação a comparar não seja redundante e tenha valor de classe

diferente

175 xleitura_mj = xds_d[j,:xna+xnj] # ler os valores dos atributos e das colunas jnsq da observação com a qual se compara 176 xleitura_m = np.absolute(np.subtract(xleitura_mi, xleitura_mj)) # verifica se os elementos da observação atual e da observação com a qual se compara são iguais (=0) ou diferentes (=1) 177 xds_ma[xnlma,:] = xleitura_m # atualiza o dataset da matriz disjunta

178 xnlma += 1

179 xitr += 1

180 if xitr%xf == 0:

181 print('{0:10d}'.format(xitr//xf), end='\r')

182 # Atualizar o metadado xnlma - número de linhas da matriz disjunta 183 xds_d.attrs['xnlma'] = xnlma

184 print(xll+'»»» A matriz disjunta está construída.') 185

186 # Fechar o ficheiro da BD 187 xfich.close()

188

189 # Imprimir mensagem final com o tempo decorrido

190 print('\n»»» O script "'+sys.argv[0]+'" foi executado com sucesso em

'+fintervalotempo(xti, time.time())+'.\n')

Documentos relacionados