2012-05-15 16 views
7

Estoy leyendo Python Programming por John Zelle y estoy atascado en uno de los ejercicios que se muestran en la imagen a continuación.Python Beginner - ¿Cómo equiparar una línea de regresión de clics y mostrar gráficamente?

Puede ver mi código a continuación. Sé que el código es muy feo. (Algún consejo son apreciados)

Picture of Regression Exercise

Aquí está mi código hasta ahora:

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

Cuando ejecuto el programa de la línea de regresión no parece ser la verdadera línea de mejor ajuste. Creo que estoy interpretando la ecuación de regresión incorrectamente en mi código. ¿Qué debe cambiarse para obtener la línea de regresión correcta?

+0

Esta es la primera cuestión de forma. Avíseme si debería preguntar esto de otra manera o incluir más/menos información.¿El código es demasiado largo para citar directamente en la pregunta? – TyShi

+1

Si puede determinar qué sección de código tiene la confianza de que es responsable, puede tener sentido incluir solo esa sección; pero esto no es _horrible_. He rotado la imagen y la he incluido en línea para que sea más fácil de leer, lo que hubiera sido agradable, pero probablemente imposible para alguien tan nuevo. (Bienvenido a SO. :) – sarnold

+0

Sería bueno si la imagen se convirtiera en texto, pero ¿Stack Overflow admite las matemáticas de la forma en que lo hace math.se? –

Respuesta

4

Problemas:

  • from my_library import * deberían ser evitados; mejor especificar exactamente lo que quieres de él. Esto ayuda a mantener despejado su espacio de nombres.

  • tienes un bloque enorme de código; mejor dividirlo en funciones separadas. Esto hace que sea mucho más fácil pensar y depurar, y puede ayudarlo a reutilizar el código más adelante. Claro, es un problema de juguete, no vas a reutilizarlo, pero el objetivo de hacer ejercicios es desarrollar buenos hábitos, ¡y tener en cuenta tu código de esta manera es definitivamente un buen hábito! Una regla general: si una función contiene más de una docena de líneas de código, debería considerar dividirla aún más.

  • el ejercicio le pide que realice un seguimiento de las sumas x, y, xx y xy al obtener puntos de entrada. Creo que esto es una mala idea, o al menos más C-ish que Python-ish, ya que te obliga a hacer dos tareas diferentes a la vez (obtener puntos y hacer cálculos sobre ellos). Mi consejo sería: si obtienes puntos, obtén puntos; si estás haciendo matemáticas, haz matemáticas; no intentes hacer ambas cosas a la vez.

  • De forma similar, no me gusta la forma en que tiene el cálculo de la regresión preocupándose acerca de dónde están los lados de la ventana. ¿Por qué debería saber o preocuparse por las ventanas? Espero que les guste mi solución a este ;-)

Aquí está mi versión refactorizado de su código:

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

Me he quedado atrapado en este problema y tu solución ayudó lo entiendo inmensamente. Sin embargo, nunca había visto un subdefinido antes. ¿Cómo funciona? Define la función, pero nunca se llama realmente, al parecer en la prueba. –

3

¡El ciclo for está todo revuelto! usted tiene una i que los cambios en el bucle, pero luego utiliza gp que es siempre 0.

quieres algo más como:

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

... o mover a gp = 0 antes del bucle.

... o suelte esa parte por completo y agregue sumXY y sumXX al sumX y sumY.

en ambos sentidos, una vez que lo arregles, debería estar bien (bueno, o tal vez algún otro error ...).

Cuestiones relacionadas