如何将此代码推广到多变量方程?
How to generalize this code for multi variable equations?
我是 LISP 的新手。我正在学习 Andrew Ng 在 Coursera 中的机器学习课程(仍然是第一周)。我想尝试在 LISP 中做线性回归。
我编写了单变量线性回归的代码。该代码似乎工作正常。我想将其概括为多变量线性函数。我想知道如何开始这样做。我想以这样的方式结束:
(defun run-linear-regression alpha iterations training-set number-of-variables (...))
这将依次创建一个假设生成器函数,其中包含输入变量数、这些假设的偏导函数等。
以下是我目前的代码。我不需要任何人为我编写此代码,但将不胜感激有关如何去做我想做的事情的一些指导。此外,也欢迎任何关于如何改进我目前的代码(性能、风格等)的一般性评论。
(defun make-hypothesis (theta1 theta2)
(lambda (x)
(+ theta1 (* x theta2))))
(defun make-cost-function (hypothesis)
(lambda (training-data)
(let* ((x (car training-data)) (y (cadr training-data))
(val (- (funcall hypothesis x) y)))
(* val val))))
(defun make-J-1 (cost-function)
(lambda (training-set) (float
(/
(reduce #'+ (mapcar cost-function training-set))
(* 2 (length training-set))))))
(defun make-J (theta1 theta2)
(make-J-1 (make-cost-function (make-hypothesis theta1 theta2))))
(defun make-part-deriv-1 (hypothesis)
(lambda (test-set)
(let ((m (length test-set)))
(float (/
(reduce #'+ (mapcar (lambda(elem)(- (funcall hypothesis (car elem)) (cadr elem))) test-set))
m)))))
(defun make-part-deriv-2 (hypothesis)
(lambda (test-set)
(let ((m (length test-set)))
(float (/
(reduce #'+ (mapcar (lambda(elem)(* (- (funcall hypothesis (car elem)) (cadr elem)) (funcall hypothesis (car elem)))) test-set))
m)))))
(defun make-learn-fn (alpha theta1 theta2 make-part-deriv)
(lambda (test-set)
(let* ((hypothesis (make-hypothesis theta1 theta2)) (pdv (funcall make-part-deriv hypothesis)))
(* alpha (funcall pdv test-set)))))
(defun make-learners (alpha)
(list
(lambda (theta1 theta2 test-set) (- theta1 (funcall (make-learn-fn alpha theta1 theta2 #'make-part-deriv-1) test-set)))
(lambda (theta1 theta2 test-set) (- theta2 (funcall (make-learn-fn alpha theta1 theta2 #'make-part-deriv-2) test-set)))))
(defun run-linear-regression (alpha iterations training-set &optional (theta1 0) (theta2 0) (printer nil))
(let ((t1 theta1) (t2 theta2))
(dotimes (i iterations)
(if (not (null printer))
(funcall printer t1 t2))
(let* ((funcs (make-learners alpha))
(nt1 (funcall (car funcs) t1 t2 training-set))
(nt2 (funcall (cadr funcs) t1 t2 training-set)))
(setq t1 nt1)
(setq t2 nt2)))
(list t1 t2)))
最后,我会这样称呼它:
(defvar *training-set* '((15 20) (700 6) (23 15) (19 19) (204 15) (60 150) (87 98) (17 35) (523 29)))
(run-linear-regression 0.0001 1000000 *training-set*)
我不熟悉这里的数学,但由于没有其他人写出更好的答案,这里有一些一般性建议。
您应该更改 RUN-LINEAR-REGRESSION
以获取变量列表以及学习者函数列表。例如:
(defun run-linear-regression (iterations training-set
variables learners)
(let ((vars variables))
(dotimes (i iterations)
(setf vars (mapcar (lambda (function)
(funcall function vars training-set))
learners)))
vars))
这将学习者作为参数而不是将它们放在函数中。您的原始代码使学习者处于循环中,这似乎没有必要,因为 MAKE-LEARNERS
仅将 ALPHA
作为参数,并且永远不会改变,因此生成的学习者将始终相同.
我们还需要更改 MAKE-LEARNERS
以便 lambda 函数采用变量列表:
(defun make-learners (alpha)
(list (lambda (variables test-set)
(destructuring-bind (theta1 theta2) variables
(- theta1 (funcall (make-learn-fn alpha theta1 theta2
#'make-part-deriv-1)
test-set))))
(lambda (variables test-set)
(destructuring-bind (theta1 theta2) variables
(- theta2 (funcall (make-learn-fn alpha theta1 theta2
#'make-part-deriv-2)
test-set))))))
这与您拥有的几乎相同,但它使用 DESTRUCTURING-BIND
从列表 VARIABLES
中提取 THETA1
和 THETA2
。现在我们可以这样调用 RUN-LINEAR-REGRESSION
:
(run-linear-regression 1000000 *training-set* '(0 0) (make-learners 0.0001))
;=> (42.93504 2.5061023e-4)
要添加更多变量,您可以编写一个合适的 MAKE-LEARNERS
版本。因为我不懂数学,所以我真的不能举个例子。
我是 LISP 的新手。我正在学习 Andrew Ng 在 Coursera 中的机器学习课程(仍然是第一周)。我想尝试在 LISP 中做线性回归。 我编写了单变量线性回归的代码。该代码似乎工作正常。我想将其概括为多变量线性函数。我想知道如何开始这样做。我想以这样的方式结束:
(defun run-linear-regression alpha iterations training-set number-of-variables (...))
这将依次创建一个假设生成器函数,其中包含输入变量数、这些假设的偏导函数等。
以下是我目前的代码。我不需要任何人为我编写此代码,但将不胜感激有关如何去做我想做的事情的一些指导。此外,也欢迎任何关于如何改进我目前的代码(性能、风格等)的一般性评论。
(defun make-hypothesis (theta1 theta2)
(lambda (x)
(+ theta1 (* x theta2))))
(defun make-cost-function (hypothesis)
(lambda (training-data)
(let* ((x (car training-data)) (y (cadr training-data))
(val (- (funcall hypothesis x) y)))
(* val val))))
(defun make-J-1 (cost-function)
(lambda (training-set) (float
(/
(reduce #'+ (mapcar cost-function training-set))
(* 2 (length training-set))))))
(defun make-J (theta1 theta2)
(make-J-1 (make-cost-function (make-hypothesis theta1 theta2))))
(defun make-part-deriv-1 (hypothesis)
(lambda (test-set)
(let ((m (length test-set)))
(float (/
(reduce #'+ (mapcar (lambda(elem)(- (funcall hypothesis (car elem)) (cadr elem))) test-set))
m)))))
(defun make-part-deriv-2 (hypothesis)
(lambda (test-set)
(let ((m (length test-set)))
(float (/
(reduce #'+ (mapcar (lambda(elem)(* (- (funcall hypothesis (car elem)) (cadr elem)) (funcall hypothesis (car elem)))) test-set))
m)))))
(defun make-learn-fn (alpha theta1 theta2 make-part-deriv)
(lambda (test-set)
(let* ((hypothesis (make-hypothesis theta1 theta2)) (pdv (funcall make-part-deriv hypothesis)))
(* alpha (funcall pdv test-set)))))
(defun make-learners (alpha)
(list
(lambda (theta1 theta2 test-set) (- theta1 (funcall (make-learn-fn alpha theta1 theta2 #'make-part-deriv-1) test-set)))
(lambda (theta1 theta2 test-set) (- theta2 (funcall (make-learn-fn alpha theta1 theta2 #'make-part-deriv-2) test-set)))))
(defun run-linear-regression (alpha iterations training-set &optional (theta1 0) (theta2 0) (printer nil))
(let ((t1 theta1) (t2 theta2))
(dotimes (i iterations)
(if (not (null printer))
(funcall printer t1 t2))
(let* ((funcs (make-learners alpha))
(nt1 (funcall (car funcs) t1 t2 training-set))
(nt2 (funcall (cadr funcs) t1 t2 training-set)))
(setq t1 nt1)
(setq t2 nt2)))
(list t1 t2)))
最后,我会这样称呼它:
(defvar *training-set* '((15 20) (700 6) (23 15) (19 19) (204 15) (60 150) (87 98) (17 35) (523 29)))
(run-linear-regression 0.0001 1000000 *training-set*)
我不熟悉这里的数学,但由于没有其他人写出更好的答案,这里有一些一般性建议。
您应该更改 RUN-LINEAR-REGRESSION
以获取变量列表以及学习者函数列表。例如:
(defun run-linear-regression (iterations training-set
variables learners)
(let ((vars variables))
(dotimes (i iterations)
(setf vars (mapcar (lambda (function)
(funcall function vars training-set))
learners)))
vars))
这将学习者作为参数而不是将它们放在函数中。您的原始代码使学习者处于循环中,这似乎没有必要,因为 MAKE-LEARNERS
仅将 ALPHA
作为参数,并且永远不会改变,因此生成的学习者将始终相同.
我们还需要更改 MAKE-LEARNERS
以便 lambda 函数采用变量列表:
(defun make-learners (alpha)
(list (lambda (variables test-set)
(destructuring-bind (theta1 theta2) variables
(- theta1 (funcall (make-learn-fn alpha theta1 theta2
#'make-part-deriv-1)
test-set))))
(lambda (variables test-set)
(destructuring-bind (theta1 theta2) variables
(- theta2 (funcall (make-learn-fn alpha theta1 theta2
#'make-part-deriv-2)
test-set))))))
这与您拥有的几乎相同,但它使用 DESTRUCTURING-BIND
从列表 VARIABLES
中提取 THETA1
和 THETA2
。现在我们可以这样调用 RUN-LINEAR-REGRESSION
:
(run-linear-regression 1000000 *training-set* '(0 0) (make-learners 0.0001))
;=> (42.93504 2.5061023e-4)
要添加更多变量,您可以编写一个合适的 MAKE-LEARNERS
版本。因为我不懂数学,所以我真的不能举个例子。