2009-06-17 5 views
3

Könnt ihr mir bitte sagen wie ich den folgenden Code mehr pythonisch machen kann?Wie machst du diesen Code pythonischer?

Der Code ist korrekt. Vollständige Offenlegung - es ist das Problem 1b in Handout # 4 von this maschinellen Lernkurs. Ich sollte Newton-Algorithmus auf die beiden Datensätze für die Anpassung einer logistischen Hypothese verwenden. Aber sie verwenden Matlab & Ich benutze scipy

ZB eine Frage, die ich habe, ist die Matrizen gerundet auf ganze Zahlen, bis ich einen Wert auf 0.0 initialisiert. Gibt es einen besseren Weg?

Dank

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 
+1

was macht die Zeile y = 11? – SilentGhost

+0

das setzt das coole Bit. – Geo

+0

+1 für die Verwendung des Wortes Pythonic in einem Satz. – samoz

Antwort

4
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 
+1

Ich weiß nicht, der Code funktioniert gut.Wenn sie Matrizen sind, scheint es zu inneren Produkt zu tun.Ich habe den Code von hier (http://www.scipy.org/SciPy_Tutorial) – MercerKernel

+0

@MercerKernel: cool - ich lernte etwas neues! meine Verwendung von Arrays statt Matrizen zwangen mich, Punkt zu verwenden, mit Matrizen kann man "*" verwenden! Ich korrigierte den Code und erlaubte mir auch, Theta = -old_theta zu vereinfachen – yairchu

+1

hmm, deine Mapline beschwert sich über dimensi ons. Ich musste es als x umschreiben [: 2] = array ([xline.split ("") [1: 3]], dtype = float) .transpose() Das gleiche auf der math.exp Zeile Ich denke, Sie brauchen Theta .transpose() – MercerKernel

0

Sie könnten die Verwendung der with Aussage machen.

+1

außer dass niemand * bekommt * die mit aussage noch ... –

+1

-1: in welcher weise? Nur zufällig? oder mit etwas als Zweck? –

+0

für die Dateiverarbeitung. – Geo

9

Eine offensichtliche Änderung ist, das "for i in range (1, 100):" loszuwerden und nur über die Dateizeilen zu iterieren. Um über beide Dateien (xfile und yfile) zu iterieren, zippen Sie sie. dh ersetzen diesen Block mit so etwas wie:

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

(Dies wird die Datei angenommen wird 100 Zeilen (dh Sie die gesamte Datei wollen) Wenn Sie bewusst auf die ersten 100 Zeilen zu beschränken sind, werden Sie.. verwenden könnte so etwas wie:.

for i, xline, yline in itertools.izip(range(100), xfile, yfile): 

jedoch sein auch ineffizient über die gleiche Datei iterieren 6 mal - besser ist es im Voraus in dem Speicher zu laden, und eine Schleife über es dort, also außerhalb der Schleife hat:

xfile = open("q1x.dat", "r") 
yfile = open("q1y.dat", "r") 
data = zip([line.split(" ")[1:3] for line in xfile], map(float, yfile)) 
nur

Und innen:

for (x1,x2), y in data: 
    x[0] = x1 
    x[1] = x2 
    ... 
+1

das sollte line.split sein ("") [1: 3] wie yairchu es getan hat. Teilen Sie zwei Leerzeichen, diese Seite bearbeitet meinen Code. – MercerKernel

+0

Ups, du hast Recht - das habe ich vermisst. Aktualisiert. – Brian

0

der Code, der die Dateien in Listen liest drastisch einfacher sein könnte

for line in open("q1x.dat", "r"): 
    x = map(float,line.split(" ")[1:]) 
y = map(float, open("q1y.dat", "r").readlines()) 
+0

Sie überschreiben x die ganze Zeit. vielleicht beabsichtigten Sie x = [map (float, line.split ("") [1:] für Zeile in geöffnet ("q1x.dat", "r") ?? – yairchu

+0

warten nicht tut sein Code das auch? – Nathan

+0

@Nathan: Um etwas Verwirrung zu beseitigen - rufen Sie Ihr "y" "ys" auf, da es eine Liste aller "y" s im OP-Code enthält. Ihr "x" konnte jedoch nicht in "xs" umbenannt werden gleiche Werte seines "x". dann würde es seltsam erscheinen, dass Sie "x" und "ys" berechnen und nicht "xs" und "ys". Ich hoffe, ich bin klar .. – yairchu

3

den Matrizen gehalten auf ganze Zahlen gerundet, bis ich einen Wert initialisiert bis 0,0. Gibt es einen besseren Weg?

An der Spitze des Codes:

from __future__ import division 

In Python 2.6 und früher Integer-Division gibt immer eine ganze Zahl, wenn mindestens eine ist Gleitkommazahl innerhalb. In Python 3.0 (und in zukünftige Division in 2.6), Abteilung funktioniert mehr, wie wir Menschen es erwarten könnten.

Wenn Sie Integer-Division wollen eine ganze Zahl zurück, und Sie haben von Zukunft importiert, ein Doppel // verwenden. Das ist

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 
Verwandte Themen