48287


以下のコードを実行すると

> AttributeError: 'LogisticRegression' object has no attribute 'w'

と表示されます。LogisticRegressionのクラスにはwのメソッドは作ってないのですがどうしてでしょう？

[code]

    import numpy as np
    from numpy import *
    import scipy.optimize as op
    import matplotlib.pyplot as plt
    import seaborn as sns
    
    sns.set_style("whitegrid")
    
    
    class LogisticRegression(object):
        def __init__(self, X, y, alg=0, eta=0.001, w=None):
            self.X = X
            self.y = y
            self.alg = alg
            self.eta = eta
            self.m, self.n = np.shape(X)
            if not (w is None):
                self.w = np.random.randn(self.n, 1)
    
        def sigFunc(self, z):
            return 1.0 / (1.0 + np.exp(-z))
    
        def decide(self, x):
            return np.where(x >= 0.5, 1, 0)
    
        def costfunc(self, w):
            z = np.dot(self.X, w)
            phi = self.sigFunc(z)
            part1 = np.multiply(self.y, np.log(phi))
            part2 = np.multiply((1 - self.y), np.log(1 - phi))
            J = (-part1 - part2).sum() / self.m
            grad = np.dot(self.X.T, (phi - self.y))/self.m
            return J, grad
    
        def graddescent(self, maxiter):
            self.J = []
            self.epoch = []
            for i in range(0, maxiter):
                J, grad = self.costfunc(self.w)
                self.J.append(J)
                self.epoch.append(i)
                self.w = self.w - self.eta * grad
            return self.w
    
        def fit(self):
            if self.alg == 0:
                maxiter = 1000
                self.w = self.graddescent(maxiter)
            else:
                Result = op.minimize(fun=self.costfunc,
                                     x0=self.w,
                                     args=(self.X, self.y),
                                     method='TNC',
                                     jac=True)
                self.w = Result.x
                self.w = self.w.T
    
            z = np.dot(self.X, self.w)
            phi = self.sigFunc(z)
            correctAnswer = np.where(np.array(self.y == self.decide(phi)) == True, 1, 0)
            self.accuracy = float(sum(correctAnswer)) / len(correctAnswer)
    
        def plot(self):
            ind_1 = np.where(self.y == 1)
            ind_0 = np.where(self.y == 0)
    
            x1_1 = self.X[:, [1]].min()
            x1_2 = self.X[:, [1]].max()
    
            x2_1 = -(self.w[0, 0] + self.w[1, 0] * x1_1) / self.w[2, 0]
            x2_2 = -(self.w[0, 0] + self.w[1, 0] * x1_2) / self.w[2, 0]
    
            plt.plot(self.X[ind_1, [1]], self.X[ind_1, [2]], "bo", markersize=3)
            plt.plot(self.X[ind_0, [1]], self.X[ind_0, [2]], "ro", markersize=3)
    
            plt.plot([x1_1, x1_2], [x2_1, x2_2], "g-")
            plt.show()
    
        def lossplot(self):
            plt.plot(self.epoch, self.J)
            plt.xlabel("Epoch")
            plt.ylabel("cost")
            plt.show()
    
    x1 = np.random.normal([2, 2], 0.5, (500, 2))
    x2 = np.random.normal([-2, -2], 0.5, (500, 2))
    y1 = np.zeros(500).T
    y2 = np.ones(500).T
    Y = np.concatenate((y1, y2), axis=0)
    x = np.concatenate((x1, x2), axis=0)
    X = np.concatenate((np.ones(1000).reshape(-1, 1), x), axis=1)
    
    lr = LogisticRegression(X, Y, alg=0, eta=0.001)
    
    lr.fit()
    
[/code]

またplotの部分のコードをもっとシンプルにする方法はないでしょうか？よろしくお願いします


CC BY-SA 4.0
2018-09-11T13:42:49.040
48286
2018-09-12T03:57:54.150
2018-09-11T14:19:17.313
19110
question
python python3
PythonでAttributeError:


この AttributeError は、メンバ変数かメンバ関数かにかかわらず「`w` という
[attribute](https://docs.python.org/ja/3/glossary.html#term-attribute)
が存在しない」ことを言っています。つまり「`self.w` のように参照しようとしたとき、 `w` が無いので失敗した」というエラーです。

さて、`LogisticRegression` クラスの `__init__()` では、`w` が `None` でなかったときだけ `self.w`
を宣言しています。

[code]

    def __init__(self, X, y, alg=0, eta=0.001, w=None):
        # ... 中略 ...
        if not (w is None):
            self.w = np.random.randn(self.n, 1)
    
[/code]

したがって `w` が `None` のときには `self.w` が存在せず、他のメソッドで `self.w` を参照しようとしたときにエラーとなります。

以下は、問題を再現できる小さなサンプルコードです。[Wandbox
上で実行できますのでお確かめください。](https://wandbox.org/permlink/Be1wETBbtRcUCQya)

[code]

    class C:
        def __init__(self, a=None):
            # a が提供されたときだけ self.a を定義する
            if not (a is None):
                self.a = a
        def get(self):
            return self.a
    
    if __name__ == '__main__':
        # これは成功
        c1 = C(a=42)
        print(c1.get())
        # これは AttributeError
        c2 = C()
        print(c2.get())  # この get() の実行中にエラーが起こる
    
[/code]

この問題を回避するためには、たとえば三項演算子を使って

[code]

    self.a = ほげほげ if 条件 else ぴよぴよ
    
[/code]

のように書くと良いでしょう。

## 追記: どのようにしてエラーの原因を探ったか？

以下のコメントを頂きました。

> どうしてこのAttributeErrorがそういった内容のエラーだとわかったんですか？

私は次のような流れで考えてエラー原因を特定しました。

  1. エラーを読む。今回のエラーは `LogisticRegression` に `w` が無いというエラーです。質問文には載っていませんがエラーのトレースバックも含めてすべて読むと、`J, grad = self.costfunc(self.w)` という行でエラーが起こっていることが分かります。
[code]     Traceback (most recent call last):

      File "test.py", line 95, in <module>
        lr.fit()
      File "test.py", line 48, in fit
        self.w = self.graddescent(maxiter)
      File "test.py", line 39, in graddescent
        J, grad = self.costfunc(self.w)
    AttributeError: 'LogisticRegression' object has no attribute 'w'
    
[/code]

  2. 怪しいのは `w` です。エラーが起こっている行では `self.w` という形で `w` を参照しています。では `w` はどこで定義されているのでしょうか？

  3. Python の慣例的に、メンバ変数を定義するのは `__init__()` 関数でしょう。`__init__()` を読んでみます。
[code]     def __init__(self, X, y, alg=0, eta=0.001, w=None):

        self.X = X
        self.y = y
        self.alg = alg
        self.eta = eta
        self.m, self.n = np.shape(X)
        if not (w is None):
            self.w = np.random.randn(self.n, 1)
    
[/code]

  4. むむ、`self.w` は if 文の中で初めて宣言されているように見えます。他の箇所では宣言しているのでしょうか？

  5. `w` で全コードを検索してみると、どうも `__init__()` 以外では `self.w` を宣言していないようです。
  6. ということは `__init__()` で `self.w` が宣言されていない場合があるために「`w` が無い」というエラーになるのでしょう。
  7. 試しに `__init__()` 関数で `self.w` を正しく宣言してみます。上手くいきました。これが原因でしょう。


CC BY-SA 4.0
2018-09-11T14:28:55.567
48287
2018-09-12T03:57:54.150
2018-09-12T03:57:54.150
19110
19110
48286
answer