2012-05-15 12 views
7

Sto leggendo Python Programming di John Zelle e sono bloccato su uno degli esercizi mostrati nella foto qui sotto.Python Beginner - Come equiparare una linea di regressione da clic e visualizzare graficamente?

È possibile visualizzare il mio codice qui sotto. So che il codice è molto brutto. (Eventuali suggerimenti sono apprezzati)

Picture of Regression Exercise

Ecco il mio codice finora:

from graphics import * 

def regression(): 

# creating the window for the regression line 
     win = GraphWin("Regression Line - Start Clicking!", 500, 500) 
     win.setCoords(0.0, 0.0, 10.0, 10.0) 

     rect = Rectangle(Point(0.5, 0.1), Point(2.5, 2.1)) 
     rect.setFill("red") 
     rect.draw(win) 
     Text(rect.getCenter(), "Done").draw(win) 

     message = Text(Point(5, 0.5), "Click in this screen") 
     message.draw(win) 

     points = [] # list of points 
     n = 0 # count variable 
     sumX = 0 
     sumY = 0 

     while True: 
       p = win.getMouse() 
       p.draw(win) 

# if user clicks in a red square it exits the loop and calculates the regression line 
       if (p.getX() >= 0.5 and p.getX() <= 2.5) and (p.getY() >= 0.1 and p.getY() <= 2.1): 
         break 

       n += 1 # count of the points 

# get the sum of the X and Y points 
       sumX = sumX + p.getX() 
       sumY = sumY + p.getY() 

# tuple of the X and Y points 
       dot = (p.getX(), p.getY()) 
       points.append(dot) 

     avgX = sumX/n 
     avgY = sumY/n 

     top = 0 
     bottom = 0 

# my ugly attempt at the regression equation shown in the book 

     for i in points: 
       gp = 0 
       numer = points[gp][0] * points[gp][1] 
       top = top + numer 

       denom = points[gp][0] ** 2 
       bottom = bottom + denom 
       gp += 1 

     m = (top - sumX * sumY)/(bottom - sumX ** 2) 

     y1 = avgY + m * (0.0 - avgX) 
     y2 = avgY + m * (10.0 - avgX) 

     regressionline = Line(Point(0, y1), Point(10.0, y2)) 
     regressionline.draw(win) 

     raw_input("Press <Enter> to quit.") 
     win.close() 

regression() 

Quando eseguo il programma della retta di regressione non sembra essere la vera linea di best fit. Credo di interpretare l'equazione di regressione in modo errato nel mio codice. Cosa deve essere cambiato per ottenere la corretta linea di regressione?

+0

Questa è la mia prima domanda SO. Fammi sapere se dovrei chiedere questo in modo diverso o includere più/meno informazioni.Il codice è troppo lungo per essere citato direttamente nella domanda? – TyShi

+1

Se riesci a stabilire quale sezione di codice di cui sei sicuro sia responsabile, potrebbe avere senso includere solo quella sezione; ma questo non è _ribribile_. Ho ruotato l'immagine e l'ho inclusa in linea per renderla più facile da leggere, il che sarebbe stato bello, ma probabilmente impossibile per qualcuno così nuovo. (Benvenuti in SO. :) – sarnold

+0

Sarebbe bello se l'immagine fosse convertita in testo, ma Stack Overflow supporta la matematica nel modo in cui math.se lo fa? –

risposta

4

Issues:

  • from my_library import * dovrebbero essere evitati; meglio specificare esattamente quello che vuoi da esso. Ciò aiuta a mantenere il tuo spazio dei nomi ordinato.

  • hai un enorme blocco di codice; meglio dividerlo in funzioni separate. Questo rende molto più facile pensare e fare il debug e può aiutarti a riutilizzare il codice in un secondo momento. Certo, è un problema di giocattoli, non lo si riutilizza, ma l'intero punto di fare esercizi è sviluppare buone abitudini e il factoring del codice in questo modo è decisamente una buona abitudine! Una regola generale: se una funzione contiene più di una dozzina di righe di codice, dovresti considerare di suddividerla ulteriormente.

  • l'esercizio richiede di tenere traccia di x, y, xx e xy eseguendo somme durante l'acquisizione dei punti di input. Penso che sia una specie di cattiva idea - o almeno più C-ish di Python-ish - in quanto ti costringe a fare due compiti diversi in una volta (ottenere punti e fare matematica su di loro). Il mio consiglio sarebbe: se ottieni punti, ottieni punti; se stai facendo matematica, fai matematica; non provare a farlo entrambi contemporaneamente.

  • allo stesso modo, non mi piace il modo in cui i calcoli di regressione si preoccupano di dove sono i lati della finestra. Perché dovrebbe sapere o preoccuparsi di Windows? Spero che vi piaccia la mia soluzione a questo ;-)

Ecco la mia versione refactoring del codice:

from graphics import GraphWin, Point, Line, Rectangle, Text 

def draw_window() 
    # create canvas 
    win = GraphWin("Regression Line - Start Clicking!", 500, 500) 
    win.setCoords(0., 0., 10., 10.) 
    # exit button 
    rect = Rectangle(Point(0.5, 0.1), Point(2.5, 2.1)) 
    rect.setFill("red") 
    rect.draw(win) 
    Text(rect.getCenter(), "Done").draw(win) 
    # instructions 
    Text(Point(5., 0.5), "Click in this screen").draw(win) 
    return win 

def get_points(win): 
    points = [] 
    while True: 
     p = win.getMouse() 
     p.draw(win) 
     # clicked the exit button? 
     px, py = p.getX(), p.getY() 
     if 0.5 <= px <= 2.5 and 0.1 <= py <= 2.1: 
      break 
     else: 
      points.append((px,py)) 
    return points 

def do_regression(points): 
    num = len(points) 
    x_sum, y_sum, xx_sum, xy_sum = 0., 0., 0., 0. 
    for x,y in points: 
     x_sum += x 
     y_sum += y 
     xx_sum += x*x 
     xy_sum += x*y 
    x_mean, y_mean = x_sum/num, y_sum/num 
    m = (xy_sum - num*x_mean*y_mean)/(xx_sum - num*x_mean*x_mean) 
    def lineFn(xval): 
     return y_mean + m*(xval - x_mean) 
    return lineFn 

def main(): 
    # set up 
    win = draw_window() 
    points = get_points(win) 
    # show regression line 
    lineFn = do_regression(points) 
    Line(
     Point(0., lineFn(0.)), 
     Point(10., lineFn(10.)) 
    ).draw(win) 
    # wait to close 
    Text(Point(5., 5.), "Click to exit").draw(win) 
    win.getMouse() 
    win.close() 

if __name__=="__main__": 
    main() 
+0

Sono stato bloccato su questo problema e la tua soluzione ha aiutato me lo capisco immensamente. Non ho mai visto una sub-def prima però. Come funziona? Definisce la funzione ma non viene mai realmente chiamata, apparentemente in fase di test è però. –

3

il ciclo for è tutto incasinato! si dispone di un i che cambia nel ciclo, ma poi usare gp che è sempre 0.

si desidera qualcosa di più simile a:

for (X, Y) in points: 
    numer += X * Y 
    denom += X * X 

... o spostare gp = 0 a prima del ciclo for.

... oppure rilasciare completamente questa parte e aggiungere sumXY e sumXX a sumX e sumY.

in entrambi i casi, una volta risolto il problema dovrebbe essere ok (beh, o forse qualche altro bug ....).

Problemi correlati