Come si rende questo codice più pitonico?
-
06-07-2019 - |
Domanda
Potreste dirmi come posso rendere più pitone il seguente codice?
Il codice è corretto. Informativa completa - è il problema 1b nella Handout n. 4 del questo corso di apprendimento automatico. Dovrei usare l'algoritmo di Newton sui due set di dati per adattare un'ipotesi logistica. Ma usano matlab & amp; Sto usando Scipy
Ad esempio, una domanda che ho è che le matrici continuavano ad arrotondare agli interi finché non ho inizializzato un valore su 0,0. C'è un modo migliore?
Grazie
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
Soluzione
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
Altri suggerimenti
Un ovvio cambiamento è quello di sbarazzarsi di " per i nell'intervallo (1, 100): " e basta scorrere le righe del file. Per scorrere su entrambi i file (xfile e yfile), comprimili. cioè sostituisci quel blocco con qualcosa del tipo:
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)
...
(Questo presuppone che il file sia composto da 100 righe (ad es. si desidera l'intero file). Se si sta deliberatamente limitando le prime 100 righe, è possibile utilizzare qualcosa del tipo:
for i, xline, yline in itertools.izip(range(100), xfile, yfile):
Tuttavia, è anche inefficiente iterare sullo stesso file 6 volte - è meglio caricarlo in memoria in anticipo e passarci sopra, ad es. fuori dal tuo ciclo, avere:
xfile = open("q1x.dat", "r")
yfile = open("q1y.dat", "r")
data = zip([line.split(" ")[1:3] for line in xfile], map(float, yfile))
E dentro solo:
for (x1,x2), y in data:
x[0] = x1
x[1] = x2
...
le matrici hanno continuato ad arrotondare a numeri interi fino a quando non ho inizializzato un valore a 0,0. C'è un modo migliore?
Nella parte superiore del codice:
from __future__ import division
In Python 2.6 e precedenti, la divisione intera restituisce sempre un numero intero a meno che non ci sia almeno un numero in virgola mobile all'interno. In Python 3.0 (e nella divisione futura nella 2.6), la divisione funziona più di come noi umani potremmo aspettarci.
Se desideri la divisione di numeri interi per restituire un numero intero e hai importato da futuro , usa un doppio //. Questo è
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
Puoi utilizzare con statement.
il codice che legge i file negli elenchi potrebbe essere drasticamente più semplice
for line in open("q1x.dat", "r"):
x = map(float,line.split(" ")[1:])
y = map(float, open("q1y.dat", "r").readlines())