Python 将scipy.optimize.fmin_bfgs用于逻辑回归分类器导致除以零误差

Python 将scipy.optimize.fmin_bfgs用于逻辑回归分类器导致除以零误差,python,numpy,data-mining,logistic-regression,Python,Numpy,Data Mining,Logistic Regression,我正在尝试实现我的二元逻辑回归分类器,我决定使用scipy.optimize.fmin_bfgs最小化目标函数(对数似然),如下式所述: 该目标函数的梯度计算如下: 其中: 现在我有一个逻辑回归类,它有一个sigmoid函数来计算sigmoid,一个loglikelike函数来计算loglikelike,还有一个梯度来计算梯度。最后,我有我的learn_分类器方法,它调用optimize.fmin_bfgs函数来寻找最佳权重向量。我的训练数据集由2013个元组组成,每个元组有113个属性,

我正在尝试实现我的二元逻辑回归分类器,我决定使用scipy.optimize.fmin_bfgs最小化目标函数(对数似然),如下式所述:

该目标函数的梯度计算如下:

其中:

现在我有一个逻辑回归类,它有一个sigmoid函数来计算sigmoid,一个loglikelike函数来计算loglikelike,还有一个梯度来计算梯度。最后,我有我的learn_分类器方法,它调用optimize.fmin_bfgs函数来寻找最佳权重向量。我的训练数据集由2013个元组组成,每个元组有113个属性,其中第一个属性是结果(取一或零)。这是我的密码:

from features_reader import FeaturesReader
import numpy as np
from scipy import optimize
from scipy.optimize import check_grad


class LogisticRegression:
    def __init__(self, features_reader = FeaturesReader()):
        features_reader.read_features()
        fHeight = len(features_reader.feature_data)
        fWidth = len(features_reader.feature_data[0])
        tHeight = len(features_reader.test_data)
        tWidth = len(features_reader.test_data[0])

        self.training_data = np.zeros((fHeight, fWidth))
        self.testing_data = np.zeros((tHeight, tWidth))

        print 'training data size: ', self.training_data.shape
        print 'testing data size: ', self.testing_data.shape
        for index, item in enumerate(features_reader.feature_data):
            self.training_data[index, 0] = item['outcome']
            self.training_data[index, 1:] = np.array([value for key, value in item.items() if key!='outcome'])

    def sigmoid(self, v_x, v_weight):
        return 1.0/(1.0 + np.exp(-np.dot(v_x, v_weight[1:])+v_weight[0]))

    def loglikelihood(self, v_weight, v_x, v_y):
        return -1*np.sum(v_y*np.log(self.sigmoid(v_x, v_weight)) + (1-v_y)*(np.log(1-self.sigmoid(v_x, v_weight))))

    def gradient(self, v_weight, v_x, v_y):
        gradient = np.zeros(v_weight.shape[0])
        for row, y in zip(v_x,v_y):
            new_row = np.ones(1+row.shape[0])
            new_row[1:] = row
            y_prime = self.sigmoid(new_row[1:], v_weight)
            gradient+=(y_prime-y)*new_row
        return gradient

    def learn_classifier(self):
        result = optimize.fmin_bfgs(f=self.loglikelihood,
                               x0=np.zeros(self.training_data.shape[1]),
                               fprime=self.gradient,
                               args=(self.training_data[:,1:], self.training_data[:,0]))
        return result


def main():
    features_reader = FeaturesReader(filename = 'features.csv', features_file = 'train_filter1.arff')
    logistic_regression = LogisticRegression(features_reader)

    result = logistic_regression.learn_classifier()
    print result


if __name__ == "__main__":
    main()
FeaturesReader类是读取csv文件的解析器,我没有在这里粘贴该文件。但我非常确定init函数正确地将csv解析为表示训练数据的二维numpy数组。该二维阵列具有形状(2013,113),其中第一列是训练输出。当我运行learn_分类器函数时,它会发出以下警告并终止:

training data size:  (2013, 113)
testing data size:  (4700, 113)

logistic_regression.py:26: RuntimeWarning: overflow encountered in exp
  return 1.0/(1.0 + np.exp(-np.dot(v_x, v_weight[1:])+v_weight[0]))

logistic_regression.py:30: RuntimeWarning: divide by zero encountered in log
  return -1*np.sum(v_y*np.log(self.sigmoid(v_x, v_weight)) + (1-v_y)*(np.log(1-self.sigmoid(v_x, v_weight))))

logistic_regression.py:30: RuntimeWarning: invalid value encountered in multiply
  return -1*np.sum(v_y*np.log(self.sigmoid(v_x, v_weight)) + (1-v_y)*(np.log(1-self.sigmoid(v_x, v_weight))))

Warning: Desired error not necessarily achieved due to precision loss.
     Current function value: nan
     Iterations: 1
     Function evaluations: 32
     Gradient evaluations: 32

所以我有三个错误:1。除以零误差,2。exp 3中遇到溢出。乘法中遇到无效值。算法在第一次异常迭代后终止。我不知道为什么会这样?你们认为我在计算对数似然和梯度时做错了什么吗?你认为这些错误还来自哪里?更具体地说,在我的对数似然函数中,我的w_权重参数被假定为1D(shape=113),我的v_x是2d并且有形状(2013112)(因为我不计算结果列),我的v_y是1D并且有形状(2013)。

我自己一直在处理这个问题。调用
np.exp
可以非常快速地创建足够大的数字,使其溢出浮点64。即使使用numpy的
longdouble
数据类型(根据您的CPU提供更多分辨率),我也会遇到数字问题

我发现,至少在某些情况下,使用特征缩放和规范化可以解决数值问题。如果您有
n
特征,则为每个特征减去该特征的平均值,然后除以特征的标准偏差。numpy代码是:

for row in X.shape[0]:
    X[:, row] -= X[:, row].mean()
    X[:, row] /= X[:, row].std()
可能有一种更为矢量化的方法可以在不使用显式循环的情况下执行此操作。:)

你也可以看看我的

或者,您可以查看此技术