7

私はジョン・ゼレによるPythonプログラミングを読んでいて、下の写真に示されている演習の1つに固執しています。

以下の私のコードを見ることができます。私はコードが非常に醜いことを知っています。(ヒントをいただければ幸いです)

回帰運動の写真

これまでの私のコードは次のとおりです。

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

プログラムを実行すると、回帰直線が実際に最適な直線であるようには見えません。コードで回帰方程式を誤って解釈していると思います。正しい回帰直線を取得するには、何を変更する必要がありますか?

4

2 に答える 2

4

問題:

  • from my_library import *避けるべきです。あなたがそれから欲しいものを正確に指定する方が良いです。これにより、名前空間が整理された状態に保たれます。

  • 1つの巨大なコードブロックがあります。それを別々の機能に分割する方が良いです。これにより、考えてデバッグするのがはるかに簡単になり、後でコードを再利用するのに役立つ場合があります。確かに、これはトイプロブレムです。再利用するつもりはありませんが、演習を行うことの全体的なポイントは、良い習慣を身に付けることです。この方法でコードをファクタリングすることは、間違いなく良い習慣です。一般的な経験則-関数に約12行を超えるコードが含まれている場合は、さらに分割することを検討する必要があります。

  • この演習では、入力ポイントを取得する間、x、y、xx、およびxyの実行中の合計を追跡するように求められます。これは一種の悪い考えだと思います-または少なくともPythonっぽいよりもCっぽい-一度に2つの異なるタスクを実行する必要があります(ポイントを取得してそれらに対して数学を実行する)。私のアドバイスは次のとおりです。ポイントを取得している場合は、ポイントを取得します。あなたが数学をしているなら、数学をしなさい。両方を同時に実行しようとしないでください。

  • 同様に、ウィンドウの側面がどこにあるかを心配して回帰計算を行う方法は好きではありません。なぜそれはウィンドウを知っているか、気にする必要がありますか?私はあなたがこれに対する私の解決策を気に入ってくれることを願っています;-)

これが私のリファクタリングされたバージョンのコードです:

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()
于 2012-05-16T02:19:40.980 に答える
3

ループはforすべてめちゃくちゃです!iループ内で変化するが、常に0であるを使用しgpます。

あなたはもっと次のようなものが欲しいです:

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

...またはgp = 0forループの前に移動します。

sumXY...またはその部分を完全に削除し、とにaとasumXXを追加しsumXますsumY

いずれにせよ、問題がないことを修正したら(まあ、または他のバグかもしれません...)。

于 2012-05-16T00:24:23.753 に答える