R中矩阵的优化
Optimisation of matrix in R
我是 optimisation/calibration R 模型的新手,但我很想学习,确实需要一些帮助。我的问题与人口统计建模有关。
我做了一些研究并找到了帮助 here and 但都没有完全回答我的问题。
我有一个标量(倾向)矩阵,其中每一列的总和必须为 1。这些倾向用于估计给定人口(按年龄划分的人)将产生的家庭数量。倾向模型往往会高估历史上的家庭数量(我知道真实的家庭数量)。
我想通过调整倾向来校准模型以最大限度地减少家庭数量的误差,使得列仍然加到 1 并且初始值为零的倾向必须保持为零。
简单示例:
# Propensities matrix
mtx <- matrix(c(0.00, 0.00, 0.85, 0.00, 0.15, 0.35, 0.45, 0.00,
0.20, 0.00, 0.65, 0.15, 0.00, 0.20, 0.00), ncol = 3)
# Population by age cohort
pop <- c(2600, 16200, 13400)
# True number of households
target <- c(7000, 4500, 5500)
# Function to optimise
hh <- function(mtx, pop, target) {
# Estimate living arrangements
x <- mtx %*% pop
# Estimate number of households using parent cohorts (1,2 and 4)
x <- c(x[1,1]/2, x[2,1]/2, x[4,1]) - target
return(x)
}
我没有在 optimisation/calibration 步骤中包含我的任何代码,因为这会很尴尬,而且我无法让任何东西工作!
理想情况下,在此过程结束时,我将拥有一组可以很好地概括许多不同地区的倾向。关于我应该如何实现它的任何建议?有用的链接?
更新
下面的代码片段执行了 Enrico 建议的本地搜索方法。
library(tidyverse)
library(NMOF)
data <- list(mtx = matrix(c(0.00, 0.00, 0.90, 0.00, 0.10, 0.25, 0.50, 0.00,
0.25, 0.00, 0.60, 0.20, 0.00, 0.20, 0.00), ncol = 3),
pop = c(2600, 16200, 13400),
target = c(7190, 4650, 5920))
# True mtx
mtx.true <- matrix(c(0.00, 0.00, 0.75, 0.00, 0.25, 0.35, 0.45, 0.00,
0.20, 0.00, 0.65, 0.15, 0.00, 0.20, 0.00), ncol = 3)
# Function to optimise
households <- function(x, data) {
# Estimate living arrangements
z <- x %*% data$pop
# Estimate number of households using parent cohorts (1,2 and 4)
z <- c(z[1,1]/2, z[2,1]/2, z[4,1]) - data$target
sum(abs(z))
}
# Local search function to perturb propensities
neighbour <- function(x, data) {
# Choose random column from mtx
i <- sample(1:ncol(x), 1)
# Select two non-zero propensities from mtx column
j <- which(x[, i] != 0) %>% sample(2, replace = FALSE)
# Randomnly select one to perturb positively
x[j[1], i] <- 0.1 * (1 - x[j[1], i]) + x[j[1], i]
# Perturb second propensity to ensure mtx column adds to 1
x[j[2], i] <- x[j[2], i] + (1 - sum(x[,i]))
x
}
# Local search algorithm inputs
localsearch <- list(x0 = data$mtx,
neighbour = neighbour,
nS = 50000,
printBar = FALSE)
# Execute
now <- Sys.time()
solution <- LSopt(OF = households, algo = localsearch, data)
#>
#> Local Search.
#> Initial solution: 2695
#> Finished.
#> Best solution overall: 425.25
Sys.time() - now
#> Time difference of 6.33272 secs
# Inspect propensity matrices
print(solution$xbest)
#> [,1] [,2] [,3]
#> [1,] 0.0000000 0.3925 0.6
#> [2,] 0.0000000 0.4250 0.2
#> [3,] 0.2937976 0.0000 0.0
#> [4,] 0.0000000 0.1825 0.2
#> [5,] 0.7062024 0.0000 0.0
print(mtx.true)
#> [,1] [,2] [,3]
#> [1,] 0.00 0.35 0.65
#> [2,] 0.00 0.45 0.15
#> [3,] 0.75 0.00 0.00
#> [4,] 0.00 0.20 0.20
#> [5,] 0.25 0.00 0.00
谢谢!
我只能评论优化部分
您提供的代码已经足够;只有您的 objective 函数计算为向量。您需要将此向量转换为要最小化的单个数字,例如平方和或绝对值。
说到方法,我会尝试启发法;事实上,我会尝试一种本地搜索方法。这些方法通过您定义的函数对解决方案进行操作;因此,您可以将您的解决方案编码为矩阵。更具体地说,您需要两个函数:objective 函数(您基本上拥有)和一个邻域函数,它将解决方案作为输入并对其进行修改。在您的特定情况下,它可能需要一个矩阵,select 一列中的两个 none-零元素,然后增加一个并减少另一个。因此,列总和将保持不变。
也许教程 http://enricoschumann.net/files/NMOF_Rmetrics2012.pdf is of interest, with R code http://enricoschumann.net/files/NMOF_Rmetrics2012.R .
我是 optimisation/calibration R 模型的新手,但我很想学习,确实需要一些帮助。我的问题与人口统计建模有关。
我做了一些研究并找到了帮助 here and
我有一个标量(倾向)矩阵,其中每一列的总和必须为 1。这些倾向用于估计给定人口(按年龄划分的人)将产生的家庭数量。倾向模型往往会高估历史上的家庭数量(我知道真实的家庭数量)。
我想通过调整倾向来校准模型以最大限度地减少家庭数量的误差,使得列仍然加到 1 并且初始值为零的倾向必须保持为零。
简单示例:
# Propensities matrix
mtx <- matrix(c(0.00, 0.00, 0.85, 0.00, 0.15, 0.35, 0.45, 0.00,
0.20, 0.00, 0.65, 0.15, 0.00, 0.20, 0.00), ncol = 3)
# Population by age cohort
pop <- c(2600, 16200, 13400)
# True number of households
target <- c(7000, 4500, 5500)
# Function to optimise
hh <- function(mtx, pop, target) {
# Estimate living arrangements
x <- mtx %*% pop
# Estimate number of households using parent cohorts (1,2 and 4)
x <- c(x[1,1]/2, x[2,1]/2, x[4,1]) - target
return(x)
}
我没有在 optimisation/calibration 步骤中包含我的任何代码,因为这会很尴尬,而且我无法让任何东西工作!
理想情况下,在此过程结束时,我将拥有一组可以很好地概括许多不同地区的倾向。关于我应该如何实现它的任何建议?有用的链接?
更新
下面的代码片段执行了 Enrico 建议的本地搜索方法。
library(tidyverse)
library(NMOF)
data <- list(mtx = matrix(c(0.00, 0.00, 0.90, 0.00, 0.10, 0.25, 0.50, 0.00,
0.25, 0.00, 0.60, 0.20, 0.00, 0.20, 0.00), ncol = 3),
pop = c(2600, 16200, 13400),
target = c(7190, 4650, 5920))
# True mtx
mtx.true <- matrix(c(0.00, 0.00, 0.75, 0.00, 0.25, 0.35, 0.45, 0.00,
0.20, 0.00, 0.65, 0.15, 0.00, 0.20, 0.00), ncol = 3)
# Function to optimise
households <- function(x, data) {
# Estimate living arrangements
z <- x %*% data$pop
# Estimate number of households using parent cohorts (1,2 and 4)
z <- c(z[1,1]/2, z[2,1]/2, z[4,1]) - data$target
sum(abs(z))
}
# Local search function to perturb propensities
neighbour <- function(x, data) {
# Choose random column from mtx
i <- sample(1:ncol(x), 1)
# Select two non-zero propensities from mtx column
j <- which(x[, i] != 0) %>% sample(2, replace = FALSE)
# Randomnly select one to perturb positively
x[j[1], i] <- 0.1 * (1 - x[j[1], i]) + x[j[1], i]
# Perturb second propensity to ensure mtx column adds to 1
x[j[2], i] <- x[j[2], i] + (1 - sum(x[,i]))
x
}
# Local search algorithm inputs
localsearch <- list(x0 = data$mtx,
neighbour = neighbour,
nS = 50000,
printBar = FALSE)
# Execute
now <- Sys.time()
solution <- LSopt(OF = households, algo = localsearch, data)
#>
#> Local Search.
#> Initial solution: 2695
#> Finished.
#> Best solution overall: 425.25
Sys.time() - now
#> Time difference of 6.33272 secs
# Inspect propensity matrices
print(solution$xbest)
#> [,1] [,2] [,3]
#> [1,] 0.0000000 0.3925 0.6
#> [2,] 0.0000000 0.4250 0.2
#> [3,] 0.2937976 0.0000 0.0
#> [4,] 0.0000000 0.1825 0.2
#> [5,] 0.7062024 0.0000 0.0
print(mtx.true)
#> [,1] [,2] [,3]
#> [1,] 0.00 0.35 0.65
#> [2,] 0.00 0.45 0.15
#> [3,] 0.75 0.00 0.00
#> [4,] 0.00 0.20 0.20
#> [5,] 0.25 0.00 0.00
谢谢!
我只能评论优化部分
您提供的代码已经足够;只有您的 objective 函数计算为向量。您需要将此向量转换为要最小化的单个数字,例如平方和或绝对值。
说到方法,我会尝试启发法;事实上,我会尝试一种本地搜索方法。这些方法通过您定义的函数对解决方案进行操作;因此,您可以将您的解决方案编码为矩阵。更具体地说,您需要两个函数:objective 函数(您基本上拥有)和一个邻域函数,它将解决方案作为输入并对其进行修改。在您的特定情况下,它可能需要一个矩阵,select 一列中的两个 none-零元素,然后增加一个并减少另一个。因此,列总和将保持不变。
也许教程 http://enricoschumann.net/files/NMOF_Rmetrics2012.pdf is of interest, with R code http://enricoschumann.net/files/NMOF_Rmetrics2012.R .