2009-06-17 5 views
3

Не могли бы вы, ребята, рассказать мне, как я могу сделать следующий код более питоническим?Как вы делаете этот код более pythonic?

Код верный. Полное раскрытие информации - это проблема 1b в раздаточном материале № 4 this курс машинного обучения. Я должен использовать алгоритм Ньютона на двух наборах данных для подгонки логистической гипотезы. Но они используют matlab & Я использую scipy

Например, один вопрос: у меня есть матрицы, округленные до целых чисел, до тех пор, пока я не инициализировал одно значение до 0.0. Есть ли способ лучше?

Благодаря

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

Что делает линия y = 11 do? – SilentGhost

+0

, который устанавливает холодный бит. – Geo

+0

+1 для использования слова pythonic в предложении. – samoz

ответ

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

Не знаю, код отлично работает.Когда они являются матрицами, они, кажется, делают внутренний продукт. Я получил код отсюда (http://www.scipy.org/SciPy_Tutorial) – MercerKernel

+0

@MercerKernel: cool - я узнал что-то новое! Вместо этого я использую массивы из матриц, заставил меня использовать точку с матрицами, которые вы можете использовать «*»! Я исправил код, а также позволил себе сделать theta = -old_theta, чтобы упростить – yairchu

+1

hmm, ваша линия карты жалуется на dimensi дополнения. Мне пришлось переписать его как x [: 2] = array ([xline.split ("") [1: 3]], dtype = float) .transpose() То же самое на линии math.exp, я думаю, вам нужна Theta .transpose() – MercerKernel

0

Вы можете использовать заявление with.

+1

за исключением того, что никто * не получает * с утверждением еще ... –

+1

-1: каким образом? Просто случайно? или с чем-то как цель? –

+0

для обработки файлов. – Geo

9

Одно из очевидных изменений состоит в том, чтобы избавиться от «for i in range (1, 100):» и просто перебрать строки файлов. Чтобы перебрать оба файла (xfile и yfile), запишите их. т.е. заменить этот блок с чем-то вроде:

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

(Предполагается, что файл находится в 100 строк (то есть вы хотите весь файл) Если вы намеренно ограничивая к первых 100 строк, вы.. могли бы использовать что-то вроде:.

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

Однако, его также неэффективна перебрать тот же файл в 6 раз - лучше, чтобы загрузить его в память заранее, и петля над ней, то есть за пределами цикла, имеют:

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

А внутри просто:

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

, что должно быть line.split ("") [1: 3], как это сделал yairchu. Разделите два пробела, этот сайт редактирует мой код. – MercerKernel

+0

К сожалению, вы правы - я пропустил это. Обновлено. – Brian

0

код, который считывает файлы в списки могут быть значительно проще

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

вы все время переопределяете x. Возможно, вы указали x = [map (float, line.split ("") [1:] для строки в открытом ("q1x.dat", "r")? – yairchu

+0

ждать, не делает ли его код тоже? – Nathan

+0

@Nathan: чтобы устранить некоторую путаницу - позволяет называть ваш «y» «ys», поскольку в нем есть список всех «y» в коде OP. Однако ваш «x» не может быть переименован в «xs», поскольку он имеет одинаковые значения его «x», тогда было бы странно, что вы вычисляете «x» и «ys», а не «xs» и «ys». Надеюсь, я понятен. – yairchu

3

матрицах хранится округление до целых чисел, пока не инициализируется одно значение до 0,0. Есть ли способ лучше?

В верхней части кода:

from __future__ import division 

В Python 2.6 и выше, целочисленное деление всегда возвращает целое число, если не будет по крайней мере, один число с плавающей точкой внутри. В Python 3.0 (и в будущем раздел в 2.6), подразделение работает больше, как мы, люди, можем ожидать.

Если вы хотите целочисленного деления возвращать целое число, и вы импортировали из будущих используйте двойной, //. То есть

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