math - 优化函数(例如,电容器充电)曲线的参数以拟合数据
问题描述
在我尝试将表单的函数拟合y = a * (1 - exp(-x / b))
到某些给定数据时,我有点迷茫。我怀疑apache-common-math 的优化包可能会有所帮助,但我还没有成功使用它。您可以在下面找到一些代码来解释我想要实现的目标。
import kotlin.math.exp
import kotlin.random.Random
// Could be interpreted as a capacitor-charging curve with Vs = a and t = b
fun fGeneric(a: Double, b: Double, x: Double) = a * (1 - exp(-x / b))
fun fGiven(x: Double) = fGeneric(a = 10.0, b = 200.0, x = x)
fun fGivenWithNoise(x: Double) = fGiven(x) + Random.nextDouble(-0.1, 0.1)
fun main() {
val xs = (0..1000).map(Int::toDouble).toDoubleArray()
val ys = xs.map { x -> fGivenWithNoise(x) }.toDoubleArray()
// todo: From data, find a and b, such that fGeneric fits optimally.
}
我需要提供MultivariateDifferentiableVectorFunction
接口的实现吗?如果是这样,它需要是什么样子?
解决方案
通过使用找到解决方案lbfgs4j
:
package com.jaumo.ml.lifetimevalue
import com.github.lbfgs4j.LbfgsMinimizer
import com.github.lbfgs4j.liblbfgs.Function
import kotlin.math.exp
import kotlin.random.Random
// Could be interpreted as a capacitor-charging curve with Vs = a and t = b
fun fGeneric(a: Double, b: Double, x: Double) = a * (1 - exp(-x / b))
fun fGiven(x: Double) = fGeneric(a = 10.0, b = 200.0, x = x)
fun fGivenWithNoise(x: Double) = fGiven(x) + Random.nextDouble(-0.1, 0.1)
private fun subtractVectors(a: DoubleArray, b: DoubleArray): DoubleArray {
assert(a.size == b.size)
val result = DoubleArray(a.size)
(a.indices).forEach { dim ->
result[dim] = a[dim] - b[dim]
}
return result
}
fun main() {
val xs = (0..1000).map(Int::toDouble).toDoubleArray()
val ys = xs.map { x -> fGivenWithNoise(x) }.toDoubleArray()
val f = object : Function {
override fun getDimension(): Int {
return 2
}
override fun valueAt(x: DoubleArray): Double {
val maxVal = x[0]
val slowness = x[1]
val capacitorFunc = { x0: Double ->
maxVal * (1 - exp(-x0 / slowness))
}
return subtractVectors(xs.map(capacitorFunc).toDoubleArray(), ys)
.map { it * it }
.sum()
}
override fun gradientAt(x: DoubleArray): DoubleArray {
val a = valueAt(doubleArrayOf(x[0] - 0.001, x[1]))
val b = valueAt(doubleArrayOf(x[0] + 0.001, x[1]))
val c = valueAt(doubleArrayOf(x[0], x[1] - 0.001))
val d = valueAt(doubleArrayOf(x[0], x[1] + 0.001))
return doubleArrayOf(b - a, d - c)
}
}
val minimizer = LbfgsMinimizer()
val x = minimizer.minimize(f, doubleArrayOf(1.0, 10.0))
println(x[0])
println(x[1])
}
结果看起来不错:
9.998170586347115
200.14238710377768
推荐阅读
- python - 我目前正在使用 python 和 tkinter 为 GUI 制作计算器。我已经创建了所有必要的按钮和文本框
- python - 如何将多个字段的可选特性与pydantic联系起来?
- variables - VHDL 乘法输入和相加结果
- multithreading - Jmeter我如何只能提取一次令牌并将其用于对我的api的do x请求
- linux - Raspberry Pi 脚本:如果损坏,请格式化 USB
- sql-server - 是否可以在不重复的情况下执行我在 IF EXISTS 语句中使用的相同查询?
- python - 用python计算向量中的每个4元素乘积
- python-3.x - 正则表达式 | 提取前面定义的字符串的数字
- migration - 如何将 jira 的 sprint 迁移到 Azure DevOps?
- c# - 使用 httpclient 将 curl 命令转换为 C# 代码