¿Cómo haces que este código sea más pitónico?
-
06-07-2019 - |
Pregunta
¿Podrían decirme cómo puedo hacer que el siguiente código sea más pitónico?
El código es correcto. Revelación completa: es el problema 1b en el Folleto n. ° 4 de este curso de aprendizaje automático. Se supone que debo usar el algoritmo de newton en los dos conjuntos de datos para ajustar una hipótesis logística. Pero usan matlab & amp; Estoy usando scipy
Por ejemplo, una pregunta que tengo es que las matrices se redondearon a enteros hasta que inicialicé un valor a 0.0. ¿Hay una mejor manera?
Gracias
import os.path
import math
from numpy import matrix
from scipy.linalg import inv #, det, eig
x = matrix( '0.0;0;1' )
y = 11
grad = matrix( '0.0;0;0' )
hess = matrix('0.0,0,0;0,0,0;0,0,0')
theta = matrix( '0.0;0;0' )
# run until convergence=6or7
for i in range(1, 6):
#reset
grad = matrix( '0.0;0;0' )
hess = matrix('0.0,0,0;0,0,0;0,0,0')
xfile = open("q1x.dat", "r")
yfile = open("q1y.dat", "r")
#over whole set=99 items
for i in range(1, 100):
xline = xfile.readline()
s= xline.split(" ")
x[0] = float(s[1])
x[1] = float(s[2])
y = float(yfile.readline())
hypoth = 1/ (1+ math.exp(-(theta.transpose() * x)))
for j in range(0,3):
grad[j] = grad[j] + (y-hypoth)* x[j]
for k in range(0,3):
hess[j,k] = hess[j,k] - (hypoth *(1-hypoth)*x[j]*x[k])
theta = theta - inv(hess)*grad #update theta after construction
xfile.close()
yfile.close()
print "done"
print theta
Solución
x = matrix([[0.],[0],[1]])
theta = matrix(zeros([3,1]))
for i in range(5):
grad = matrix(zeros([3,1]))
hess = matrix(zeros([3,3]))
[xfile, yfile] = [open('q1'+a+'.dat', 'r') for a in 'xy']
for xline, yline in zip(xfile, yfile):
x.transpose()[0,:2] = [map(float, xline.split(" ")[1:3])]
y = float(yline)
hypoth = 1 / (1 + math.exp(theta.transpose() * x))
grad += (y - hypoth) * x
hess -= hypoth * (1 - hypoth) * x * x.transpose()
theta += inv(hess) * grad
print "done"
print theta
Otros consejos
Un cambio obvio es deshacerse de " para i en el rango (1, 100): " y solo iterar sobre las líneas del archivo. Para iterar sobre ambos archivos (xfile e yfile), comprímalos. es decir, reemplazar ese bloque con algo como:
import itertools
for xline, yline in itertools.izip(xfile, yfile):
s= xline.split(" ")
x[0] = float(s[1])
x[1] = float(s[2])
y = float(yline)
...
(Esto supone que el archivo tiene 100 líneas (es decir, desea el archivo completo). Si está restringiendo deliberadamente a las primeras 100 líneas, puede usar algo como:
for i, xline, yline in itertools.izip(range(100), xfile, yfile):
Sin embargo, también es ineficiente iterar sobre el mismo archivo 6 veces; es mejor cargarlo en la memoria de antemano y recorrerlo allí, es decir. fuera de su ciclo, tenga:
xfile = open("q1x.dat", "r")
yfile = open("q1y.dat", "r")
data = zip([line.split(" ")[1:3] for line in xfile], map(float, yfile))
Y adentro solo:
for (x1,x2), y in data:
x[0] = x1
x[1] = x2
...
las matrices siguieron redondeando a enteros hasta que inicialicé un valor a 0.0. ¿Hay una mejor manera?
En la parte superior de su código:
from __future__ import division
En Python 2.6 y versiones anteriores, la división de enteros siempre devuelve un entero a menos que haya al menos un número de coma flotante. En Python 3.0 (y en la división futuro en 2.6), la división funciona más de lo que los humanos podríamos esperar.
Si desea que la división de enteros devuelva un entero, y ha importado de futuro , use un doble //. Eso es
from __future__ import division
print 1//2 # prints 0
print 5//2 # prints 2
print 1/2 # prints 0.5
print 5/2 # prints 2.5
Puede utilizar con declaración.
el código que lee los archivos en listas podría ser drásticamente más simple
for line in open("q1x.dat", "r"):
x = map(float,line.split(" ")[1:])
y = map(float, open("q1y.dat", "r").readlines())