numpy 使用scipy.optimize.fmin_bfgs进行逻辑回归分类器引线除以零误差

csbfibhn  于 2023-10-19  发布在  其他
关注(0)|答案(1)|浏览(98)

我试图实现我的二元逻辑回归分类器,我决定使用scipy.optimize.fmin_bfgs来最小化目标函数(loglikelihood),如以下公式所示:

该目标函数的梯度计算为:

其中:

现在我有了LogisticRegression类,它有sigmoid函数来计算sigmoid,loglikelihood函数来计算loglikelihood,gradient来计算梯度。最后,我有我的learn_classifier方法,它调用optimize.fmin_bfgs函数来找到最佳权重向量。我的训练数据集由2013个元组组成,每个元组有113个属性,其中第一个属性是结果(取1或0)。下面是我的代码:

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

类是读取csv文件的解析器,我没有粘贴在这里。但我很确定init函数正确地将csv解析为表示训练数据的2-D numpy数组。这个2-D数组具有形状(2013,113),其中第一列是训练输出。当我运行learn_classifier函数时,它给出了这些警告并终止:

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_weight参数被假设为1D(shape = 113),我的v_x是2d,形状为(2013,112)(因为我没有计算结果列),我的v_y是1d,形状为(2013)。

zengzsys

zengzsys1#

我自己也在处理问题。对np.exp的调用可以非常快速地创建足够大的数字,使其溢出float64。即使使用numpy的longdouble数据类型(它 * 可能 * 提供更高的分辨率,取决于你的CPU),我也会遇到数值问题。
我发现,至少在某些情况下,使用特征缩放和归一化解决数值问题。如果您有n个特征,对于每个特征,从该特征中减去均值,然后除以特征的标准差。numpy代码是:

for row in X.shape[0]:
    X[:, row] -= X[:, row].mean()
    X[:, row] /= X[:, row].std()

可能有一种更向量化的方法来完成它,而不需要显式循环。:)的情况下,
你也可以看看我的toy implementation of it here
或者,你可以看看这个技术,which describes taking the log of the exponential in order to prevent overflow

相关问题