Борьба с алгоритмом минимизации BFGS для логистической регрессии в Clojure с помощью Incanter

Я пытаюсь реализовать простой пример логистической регрессии в Clojure, используя библиотеку Incanter для анализа данных. Я успешно закодировал функции Sigmoid и Cost, но функция минимизации Incanter BFGS, кажется, вызывает у меня некоторые проблемы.

(ns ml-clj.logistic
  (:require [incanter.core :refer :all]
            [incanter.optimize :refer :all]))


(defn sigmoid
  "compute the inverse logit function, large positive numbers should be
close to 1, large negative numbers near 0,
z can be a scalar, vector or matrix.
sanity check: (sigmoid 0) should always evaluate to 0.5"
  [z]
  (div 1 (plus 1 (exp (minus z)))))

(defn cost-func
  "computes the cost function (J) that will be minimized
   inputs:params theta X matrix and Y vector"
  [X y]
  (let
      [m (nrow X)
       init-vals (matrix (take (ncol X) (repeat 0)))
       z (mmult X init-vals)
       h (sigmoid z)
       f-half (mult (matrix (map - y)) (log (sigmoid (mmult X init-vals))))
       s-half (mult (minus 1 y) (log (minus 1 (sigmoid (mmult X init-vals)))))
       sub-tmp (minus f-half s-half)
       J (mmult (/ 1 m) (reduce + sub-tmp))]
    J))

Когда я пытаюсь (minimize (cost-func X y) (matrix [0 0])) дать minimize функцию и запустить параметры, REPL выдает ошибку.

ArityException Wrong number of args (2) passed to: optimize$minimize  clojure.lang.AFn.throwArity (AFn.java:437)

Я очень смущен тем, что именно ожидает функция минимизации.

Для справки, я переписал все это на python, и весь код работает, как и ожидалось, с использованием того же алгоритма минимизации.

import numpy as np
import scipy as sp
data = np.loadtxt('testSet.txt', delimiter='\t')

X = data[:,0:2]
y = data[:, 2]


def sigmoid(X):
    return 1.0 / (1.0 + np.e**(-1.0 * X))

def compute_cost(theta, X, y):
    m = y.shape[0]
    h = sigmoid(X.dot(theta.T))
    J = y.T.dot(np.log(h)) + (1.0 - y.T).dot(np.log(1.0 - h))
    cost = (-1.0 / m) * J.sum() 
    return cost

def fit_logistic(X,y):
    initial_thetas = np.zeros((len(X[0]), 1))
    myargs = (X, y)
    theta = sp.optimize.fmin_bfgs(compute_cost, x0=initial_thetas,
                                     args=myargs)
    return theta

вывод

Current function value: 0.594902
         Iterations: 6
         Function evaluations: 36
         Gradient evaluations: 9
array([ 0.08108673, -0.12334958])

Я не понимаю, почему код Python может работать успешно, но моя реализация Clojure дает сбой. Какие-либо предложения?

Обновить

перечитывая строку документации для minimize, я пытался вычислить производную от cost-func, которая выдает новую ошибку.

(def grad (gradient cost-func (matrix [0 0])))
(minimize cost-func (matrix [0 0]) (grad (matrix [0 0]) X))
ExceptionInfo throw+: {:exception "Matrices of different sizes cannot be differenced.", :asize [2 1], :bsize [1 2]}  clatrix.core/- (core.clj:950)

использование trans для преобразования матрицы столбцов 1xn в матрицу строк nx1 просто дает ту же ошибку с противоположными ошибками.

:asize [1 2], :bsize [2 1]}

Я довольно потерян здесь.


person idclark    schedule 10.11.2013    source источник
comment
1) Почему (minimize (cost-func X y) (matrix [0 0]))? Первый аргумент должен быть cost-func вместо (cost-func X y). 2) вы должны указать f-prime в качестве третьего аргумента.   -  person SaltyEgg    schedule 10.11.2013
comment
хорошо, но куда мне тогда передать свои данные? эквивалент python имеет параметр args, который я могу передать в своих обучающих данных. Я не вижу ничего подобного в строке документации для minimize.   -  person idclark    schedule 10.11.2013
comment
вы можете использовать закрытие   -  person SaltyEgg    schedule 11.11.2013


Ответы (2)


Я ничего не могу сказать о вашей реализации, но incanter.optimize/minimize ожидает (как минимум) три параметра, а вы указываете только два:

Arguments:
  f -- Objective function. Takes a collection of values and returns a scalar
       of the value of the function.
  start -- Collection of initial guesses for the minimum
  f-prime -- partial derivative of the objective function. Takes
             a collection of values and returns a collection of partial
             derivatives with respect to each variable. If this is not
             provided it will be estimated using gradient-fn.

К сожалению, я не могу сказать вам прямо, что поставить (для f-prime?) здесь, но, возможно, кто-то другой. Кстати, я думаю, что ArityException Wrong number of args (2) passed to [...] здесь очень полезен.

Редактировать: На самом деле я думаю, что приведенная выше строка документации неверна, поскольку исходный код не использует gradient-fn для оценки f-prime. Может быть, вы можете использовать incanter.optimize/gradient для создания своего собственного?

person xsc    schedule 10.11.2013
comment
Спасибо за совет! Я отредактировал свой исходный пост, попытавшись использовать gradient для вычисления производной. Это само по себе вызывает еще одно несовпадение с матрицами. это оказывается довольно разочаровывающей кроличьей норой. - person idclark; 12.11.2013

Во-первых, ваша функция стоимости должна иметь параметр для тета, такой как ваша реализация Python, однако ваша реализация зафиксирована как начальное значение.

Во-вторых, если ваша функция затрат верна, вы можете вызвать оптимизацию следующим образом.

(optimize (fn [theta] (cost-func theta X y)) [0 0 0])

Надеюсь, это поможет вам.

person chunsj    schedule 29.03.2016