~~~~~~~~~ 更新 - 谢谢!我应该在原来的问题中更加具体。我正在尝试创建一个分配表,用于投资组合优化程序。因此,列将是证券,每行是不同的分配。每行必须加起来1(或100%),我希望能够指定增量。因此,例如,如果有三个证券并且我希望增量为1%,则第一行可以是98%,1%,1%。下一行可能是97%,1%,2%等等。最后,我有一个包含每个可能的分配组合的大表(基于指定的间隔)。这有帮助吗? ~~~~~~
我希望在R中创建一个分配表,但我已经碰壁了。我在多本书籍和网站上研究过这个问题,似乎找不到直接的方法。
在最基本的形式中,我希望生成一个类似于下面的表格。
假设只有三个变量,每行必须加起来为。
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来做到这一点。谁能帮我吗?我甚至不确定从哪里开始。
非常感谢,
安德鲁
答案 0 :(得分:2)
听起来你正在寻找的是一种产生排列的方法。在这种情况下,请尝试“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 :(得分:2)
确定性方法:
如果您想要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
答案 2 :(得分:0)
只是一个想法,但是......
如何确定每列的值并不完全清楚;从您的示例中猜测,看起来这些值是seq(0, 1, .25)
的随机抽样,只要这些行加起来为1
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)
}