在R中创建预填充分配表

  • 本文关键字:填充 分配 创建
  • 更新时间 :
  • 英文 :


~~~~~~~~~更新-谢谢!我本来应该在最初的问题中说得更具体一些。我正在尝试创建一个分配表,用于投资组合优化程序。因此,列将是证券,每一行都是不同的分配。每行加起来必须达到1(或100%(,我希望能够指定增量。例如,如果有三种证券,我希望增量为1%,第一行可以是98%、1%、1%。下一行可以是97%、1%、2%等等。最后,我会有一个大表,其中包含所有可能的分配组合(基于指定的间隔(。这有帮助吗?~~~~~~

我想在R中创建一个分配表,但我遇到了困难。我在多本书和网站上研究过这个问题,似乎找不到一个直接的方法。

在最基本的形式中,我希望生成一个类似于下面的表。

假设只有三个变量,并且每一行加起来必须为1。

    v1   v2   v3 v1...v2...v3
1 0.25 0.25 0.50            1
2 0.25 0.50 0.25            1
3 0.50 0.25 0.25            1
4 0.75 0.25 0.00            1
5 0.75 0.00 0.25            1
6 1.00 0.00 0.00            1
7 0.50 0.25 0.25            1
8 0.25 0.25 0.50            1

理想情况下,我想返回一个矩阵。到目前为止,我没有运气用R来做这件事。有人能帮我吗?我甚至不知道从哪里开始。

非常感谢

Andrew

一种确定性方法:

如果您希望n变量中所有可能的组合都是非负的,求和为1,并将[0,1]除以s中的区间,则可以使用以下代码:

首先是一个函数,它给出了n整数的排列,这些整数和为s:

perms <- function(n, s)
{
    if(n==1) return(matrix(s,nrow=1,ncol=1))
    do.call(rbind, lapply(0:s, function(i) cbind(perms(n-1, s-i), i, deparse.level=0)))
}

现在定义列数和"剪切"数,并重新缩放:

> perms(3,4)/4
      [,1] [,2] [,3]
 [1,] 1.00 0.00 0.00
 [2,] 0.75 0.25 0.00
 [3,] 0.50 0.50 0.00
 [4,] 0.25 0.75 0.00
 [5,] 0.00 1.00 0.00
 [6,] 0.75 0.00 0.25
 [7,] 0.50 0.25 0.25
 [8,] 0.25 0.50 0.25
 [9,] 0.00 0.75 0.25
[10,] 0.50 0.00 0.50
[11,] 0.25 0.25 0.50
[12,] 0.00 0.50 0.50
[13,] 0.25 0.00 0.75
[14,] 0.00 0.25 0.75
[15,] 0.00 0.00 1.00

根据评论更新答案

听起来你正在寻找的是一种生成排列的方法。在这种情况下,请尝试"gtools"包中的permutations。首先,生成所有排列,然后只选择行总数为100的排列。

> ## install.packages(gtools)
> library(gtools)
> x <- permutations(101, 3, 0:100, repeats.allowed=TRUE)
> y <- x[rowSums(x) == 100, ]
> head(y)
     [,1] [,2] [,3]
[1,]    0    0  100
[2,]    0    1   99
[3,]    0    2   98
[4,]    0    3   97
[5,]    0    4   96
[6,]    0    5   95
> tail(y)
        [,1] [,2] [,3]
[5146,]   98    0    2
[5147,]   98    1    1
[5148,]   98    2    0
[5149,]   99    0    1
[5150,]   99    1    0
[5151,]  100    0    0

原始答案

希望我没有过于简单化,但也许你可以试试这样的东西。您没有指定是否应包括负数。我以为不会。

创建一个使用R的随机数生成器的小函数。我在函数中使用了runif。函数参数包括所需的列数(我已将默认值设置为3(、最小值和最大值。

myFun <- function(n = 3, min = 0, max = 1) {
  temp <- runif(n = n, min = min, max = max)
  temp/sum(temp)
}

使用replicate获取所需的行数。在这里,我说过要排5排。

set.seed(1)
y <- t(replicate(5, myFun()))
y
#           [,1]      [,2]      [,3]
# [1,] 0.2193406 0.3074170 0.4732425
# [2,] 0.4522318 0.1004252 0.4473430
# [3,] 0.4227516 0.2957136 0.2815348
# [4,] 0.1390588 0.4635751 0.3973661
# [5,] 0.3731857 0.2086423 0.4181721

验证每一行确实加起来是1:

rowSums(y)
# [1] 1 1 1 1 1

只是一个想法,但是。。。

目前还不完全清楚您希望如何确定每列的值;根据您的样本猜测,只要行加起来是1 ,这些值就好像是从seq(0, 1, .25)随机采样的

set.seed(222)
vals <- seq(0, 1, .25)
TotalRows <- 12
TotalCols <- 3
Lim       <- 1
# First Column
myDF <- data.frame(sample(vals, TotalRows, TRUE))
# Each next column, except last
for (i in 2:(TotalCols-1))
    myDF[, i] <- apply(myDF, 1, function(x) sample(vals[vals + sum(x) <= Lim], 1))
# Last column is difference from Lim (ie, from 1)
myDF[, TotalCols] <- apply(myDF, 1, function(x) Lim - sum(x) )
# Set Colnames if needed
colnames(myDF) <- paste0("Col", 1:TotalCols)
# Total Column if needed
myDF[, "TOTAL"] <- apply(myDF, 1, sum)
myDF
 #     Col1 Col2 Col3 TOTAL
 #  1  1.00 0.00 0.00     1
 #  2  0.00 0.75 0.25     1
 #  3  0.50 0.50 0.00     1
 #  4  0.00 0.00 1.00     1
 #  5  1.00 0.00 0.00     1
 #  6  1.00 0.00 0.00     1
 #  7  0.25 0.00 0.75     1
 #  8  0.50 0.00 0.50     1
 #  9  0.50 0.50 0.00     1
 #  10 0.00 0.25 0.75     1
 #  11 0.50 0.00 0.50     1
 #  12 0.00 0.50 0.50     1



作为一个不错的功能:

# example call:
creatTable(TotalRows=12, TotalCols=8)
# definition:
creatTable <- function(TotalRows, TotalCols, Lim=1, vals=seq(0, 1, .25), columnPrfx="Col")  {
  myDF <- data.frame(sample(vals, TotalRows, TRUE))
  for (i in 2:(TotalCols-1))
      myDF[, i] <- apply(myDF, 1, function(x) sample(vals[vals + sum(x) <= Lim], 1))
  myDF[, TotalCols] <- apply(myDF, 1, function(x) Lim - sum(x) )
  colnames(myDF) <- paste0(columnPrfx, 1:TotalCols)
  myDF[, "TOTAL"] <- apply(myDF, 1, sum)
}

最新更新