【问题标题】:Theta problems with Logistic RegressionsLogistic 回归的 Theta 问题
【发布时间】:2021-06-12 03:13:30
【问题描述】:

全新的机器学习。类项目让我们输入下面的代码。 首先我收到警告:

AttributeError: 'LogisticRegression' object has no attribute 'theta'.

如果我在 init 段中定义 theta 并添加 self.theta,则可以修复该错误,但我的模型不起作用。

def __init__(self, lr=0.01, num_iter=100000, fit_intercept=True, theta = 0, verbose=False):
        self.lr = lr
        self.num_iter = num_iter
        self.fit_intercept = fit_intercept
        self.theta = theta

产生以下错误:

model = LogisticRegression(lr=0.1, num_iter=300000)
preds = model.predict(X)
(preds == y).mean()
<ipython-input-198-c30787a24caa>:43: DeprecationWarning: elementwise comparison failed; this will raise an error in the future.
  (preds == y).mean()
Traceback (most recent call last):
  File "<ipython-input-198-c30787a24caa>", line 43, in <module>
    (preds == y).mean()
AttributeError: 'bool' object has no attribute 'mean'

请参阅下面的代码(众所周知的代码),感谢任何提示!

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn import datasets

iris = datasets.load_iris()
X = iris.data[:, :2]
y = (iris.target != 0) * 1


# Logistic Regression Class for Sigmoid Func, Loss Func, and Gradient Descent
class LogisticRegression:
    def __init__(self, lr=0.01, num_iter=100000, fit_intercept=True, verbose=False):
        self.lr = lr
        self.num_iter = num_iter
        self.fit_intercept = fit_intercept
        self.verbose = verbose
    def __add_intercept(self, X):
        intercept = np.ones((X.shape[0], 1))
        return np.concatenate((intercept, X), axis=1)
    def __sigmoid(self, z):
        return 1 / (1 + np.exp(-z))
    def __loss(self, h, y):
        return (-y * np.log(h) - (1 - y) * np.log(1 - h)).mean()
    def fit(self, X, y):
        if self.fit_intercept:
            X = self.__add_intercept(X)
        self.theta = np.zeros(X.shape[1])

        for i in range(self.num_iter):
            z = np.dot(X, self.theta)
            h = self.__sigmoid(z)
            gradient = np.dot(X.T, (h - y)) / y.size
            self.theta -= self.lr * gradient
            
            if(self.verbose ==True and i % 10000 == 0):
                z = np.dot(X, self.theta)
                h = self.__sigmoid(z)
                print(f'loss: {self.__loss(h, y)} \t')


    def predict_prob(self, X):
        if self.fit_intercept:
            X = self.__add_intercept(X)
        return self.__sigmoid(np.dot(X, self.theta))
      
    def predict(self, X):
        return self.predict_prob(X).round()


model = LogisticRegression(lr=0.1, num_iter=300000)
preds = model.predict(X)
(preds == y).mean()

np.shape(preds)
np.shape(preds)
np.shape(y)
plt.figure(figsize=(10, 6))
plt.scatter(X[y == 0][:, 0], X[y == 0][:, 1], color='g', label='0')
plt.scatter(X[y == 1][:, 0], X[y == 1][:, 1], color='y', label='1')
plt.legend()
x1_min, x1_max = X[:,0].min(), X[:,0].max(),
x2_min, x2_max = X[:,1].min(), X[:,1].max(),
xx1, xx2 = np.meshgrid(np.linspace(x1_min, x1_max), np.linspace(x2_min, x2_max))
grid = np.c_[xx1.ravel(), xx2.ravel()]
probs = model.predict_prob(grid).reshape(xx1.shape)
plt.contour(xx1, xx2, probs, [0.5], linewidths=1, colors='red')

【问题讨论】:

    标签: python numpy scikit-learn


    【解决方案1】:

    您需要将self.theta 设置为数组,而不是标量(至少在这个特定问题中)。

    在您的情况下,(截取-增强)X 是一个 '3 by n' 数组,因此请尝试self.theta = [0, 0, 0]。这将更正特定错误'bool' object has no attribute 'mean'。尽管如此,这只会产生 preds 作为零向量;你还没有拟合模型。

    为了让您知道我是如何处理错误的,我首先找到错误消息指向的确切行,并将print(preds == y) 放在该行之前,然后打印出False。我猜你所期望的是TrueFalses 的向量。您的y 似乎还可以;它是一个向量(具体来说是一个list)。所以我尝试了print(pred),它向我展示了一个 '3 by n' 数组,这很奇怪。现在从那条线往上走,我发现pred 来自predict_prob(),尤其是np.dot(X, self.theta)。在这里,当X 是'3 x n' 数组并且self.theta 是标量时,numpy 似乎将标量乘以数组中的每个项目并返回数组(与原始数组具有相同的维度),而不是矩阵乘法!所以需要显式提供self.theta作为数组(符合X的维度)。

    希望答案及其背后的推理有所帮助。


    至于你在评论中提到的红线,我猜也是因为你没有拟合模型。 (要查看问题,请将 print(probs) 放在 plt.countour(...) 之前。您将看到一个只有 0.5 的数组。)

    所以尝试将model.fit(X, y) 放在preds = model.predict(X) 之前。 (您还需要将self.verbose = verbose 放入__init__()。)

    之后,我得到以下信息:

    【讨论】:

    • 你又来了!希望有一天我能像你一样有能力,我的朋友。非常感谢。