【问题标题】:Random integers (no permutation)随机整数(无排列)
【发布时间】:2013-11-08 15:16:51
【问题描述】:

假设我有这个工作示例:

lover_bound = 10;
upper_bound = 180;
steps = 10;
NumeroCestelli = 8; 

livello = [lover_bound:steps:upper_bound];
L = length(livello);
n_c = ceil((factorial(L+NumeroCestelli-1))/(factorial(NumeroCestelli)*factorial(L-1)));

randIdxs = randi([1,L],n_c,NumeroCestelli);
PianoSperimentale = single(livello(randIdxs)); 

我需要执行一个n_c x NumeroCestelli 矩阵(称为PianoSperimentale),其中每一行都是唯一的。不允许任何形式的排列。使用 randi 我无法执行我的要求。

[10 20 30 40 50 60 70 80] is equal to [80 70 60 50 40 30 20 10]

PianoSperimentale 应该是一个1081575x8 矩阵。过去我使用Combinator) 函数,但对于非常大的矩阵来说非常慢。

[PianoSperimentale] = combinator(L,NumeroCestelli,'c','r');

for i=1:L
    PianoSperimentale(PianoSperimentale==i)=livello(i);
end

那么,有一种方法可以执行与combinator 相同的矩阵,但速度为randi

编辑:我允许选择相同的数字两次 (NumberOfCombinations = (NumeroCestelli+L-1)!/(NumeroCestelli!(L-1)!)

建议的修改

我需要生成从 18 个元素的向量中选择任何 8 个数字时获得的完整组合(带有重复项)。这可以通过使用Combinator 函数来完成,但对于非常大的矩阵来说非常慢。任何人都可以建议一种更快的方法来生成它吗?

示例:使用“来自向量 4 的样本 3”会产生以下结果:

1 1 1
1 1 2
1 1 3
1 1 4
1 2 2
1 2 3
1 2 4
1 3 3
1 3 4
1 4 4
2 2 2
2 2 3
2 2 4
2 3 3
2 3 4
2 4 4
3 3 3
3 3 4
3 4 4
4 4 4

我知道对于一个由 18 个元素组成的向量,从中选择了 8 个元素,我将得到总共 (18+8-1)!/8!*(18-1)! 个可能的组合,或 1081578 行 8 个值。谁能帮我找到一个快速的算法来做到这一点?

【问题讨论】:

  • 那么...问题是什么?
  • @Dan 我需要执行一个n_c x NumeroCestelli 矩阵[...],其中每一行都是唯一的,不使用组合器。
  • @Dan 我认为 gmeroni 需要随机生成数字行,其中每个生成的行都是唯一的“模”排列

标签: matlab random matrix


【解决方案1】:

出于“历史”原因,我正在写一个新答案而不是删除我的旧答案(该问题的很多来回是理解问题的必要序言,因此这个答案甚至是有意义的)。 TL;DR:最后是完整代码。

这是一个非常棘手的问题,但我想我明白了。关键的见解是,您对结果矩阵中正确数量的元素的表达式(L+H-1)!/(H!(L-1)!) 强烈建议“从 L + H - 1 中选择 H”与您的问题的解决方案之间存在关系。 Trick 正在寻找这种关系。我首先写出combnk(5, 3) 的结果(在这个大小下,你可以手动写出所有组合并寻找模式):

1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5

我们如何将其转换为 1 2 3 的唯一组合(包括重复)?我注意到有三组有连续的数字:

1 2 3
2 3 4
3 4 5

这给了我一个想法,即我需要对连续数字的差异做一些事情 - 不知何故,如果差异是 1,我需要重复这个数字。这种洞察力很快导致了以下代码:

L = 3; % pick three numbers
H = 3; % from three numbers: 1,2,3

a = combnk(1:L+H-1, L);  % generate all "combinations" of 1,2,3,4,5 without repeats

% the "magic" line: compress into "combinations with repeats"
b = cumsum([a(:,1)  diff(a,[],2) - 1],2);

对于上面的例子,这给出了

 1 1 1
 1 1 2
 1 1 3
 1 2 2
 1 2 3
 1 3 3
 2 2 2
 2 2 3
 2 3 3
 3 3 3 

这是怎么发生的?嗯,a(沿第二维)的diff

 1 1
 1 2
 1 3
 2 1
 2 2
 3 1
 1 1
 1 2
 2 1
 1 1

所以diff(a,[],2)-1)

 0 0
 0 1
 0 2
 1 0
 1 1
 2 0
 0 0
 0 1
 1 0
 0 0

在这个表达式中,0 表示“重复最后一个数字”,而1 表示“加 1”,2 表示“加 2”。我们可以通过使用cumsum(累积和)函数并从组合的第一个数字开始来完成所有这些相加。这导致表达式

b = cumsum([a(:, 1) diff(a, [], 2) - 1]);

作为最后一步,您必须将其转换回您正在使用的索引。您的完整代码将是

L = 8;
H = 18;
a = combnk(1:L+H-1, L);
b = cumsum([a(:,1)  diff(a,[],2) - 1],2);
livello = 10:10:180;
PianoSperimentale = livello(b);

这将创建一个大小为b 的数组以及livello 中的值。

我相信这对你有用(我无法测试这个,因为我的家用电脑上没有 Matlab),并且它会尽可能快地解决这个问题。

【讨论】:

  • 做得很好。你抓住了问题的核心,你的解决方案非常优雅,你的解释很容易理解。以我的悲惨经历,像这样的好答案并没有得到很多赞成,因为没有其他人花时间阅读它们。不幸的是,投票系统倾向于简单的、易于验证的单行答案。
  • @nispio - 谢谢!像这样的评论值得50个赞!幸好我这样做是因为我喜欢它,而不是为了代表……我承认当我破解这个时我很高兴。我最初不相信的正确数量的“组合”等式最终是线索。这里面有深刻的教训……
  • @nispio - 我刚刚注意到您建议的编辑(完全正确,谢谢)被三位审阅者拒绝。我现在已经将该编辑应用于我的答案......(我无法弄清楚如何“推翻”拒绝,抱歉)
【解决方案2】:

我正在尝试解析您的问题。从“无排列”和“10 20 30 40 50 60 70 80”等价于“80 70 60 50 40 30 20 10”,我推断您需要从 18 中抽取 8 个数字,而不是两次相同的样本。

这意味着您要生成所有可能的组合(来自 18 个可能值的 8 个样本),并从中进行选择。只有 43758 种方法可以做到这一点;之后,您将不得不包括排列。因此,上述问题(如果我理解正确的话)无法解决。

编辑现在问题已更新,我认为以下将是一个解决方案:

lover_bound = 10;
upper_bound = 180;
steps = 10;
NumeroCestelli = 8; 

livello = [lover_bound:steps:upper_bound];
livello = [livello livello];

PianoSperimentale = combnk(livello, 8);

因为每个数字出现两次,您可以让它重复。不幸的是,这将允许多个“双打”(例如 [10 10 20 20 30 30 40 40] 将被允许)并且这比您计算的表达式(即 36!/(28!8!) ~ 30M )。一种可能的方法(最多允许一个双精度)是

livello = lover_bound:steps:upper_bound;

for ii = 1:numel(livello)
  PS(ii,:,:) = combnk([livello livello(ii)], 8);
end

PianoSperimentale = reshape(PS, [], 8);

这允许“每个循环一个重复的数字”,我相信这更接近您的想法,尽管组合的数量将是 18 * (19!/(19-8)!8!) = 1360476,比您的表达式大一点。我现在无法测试这个,因为我这台电脑上没有 Matlab...

【讨论】:

  • 不,假设我有L=3H=2。没有排列的可能组合是:[1 1],[1 2],[2 2],[1 3],[2 3],[3 3]。计算组合数的公式为# = (H+L-1)!/(H!(L-1)!)
  • 我明白了 - 您允许选择相同的数字两次(112233)。这并不是通常如何定义“组合”,因此您可能想在您的问题中澄清这一点。我使用通常的 C(H,L) = H!/(H-L)!L! 公式...
  • 因此,如果我理解正确,问题会归结为“生成从 18 中选择的 8 个数字的所有组合,允许重复”。这没有任何随机性(尽管您最终可能会选择对它们进行洗牌),因为(根据您的方程式)恰好有 1081575 个可能的值,并且您想要所有这些值。对吗?
  • 你是对的,我在我的问题中澄清了。是的,这是我需要的。
  • 我不认为你对组合数量的表达是正确的 - 看看我的解决方案,让我知道你的想法......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-11
  • 2018-11-06
  • 2017-11-02
  • 2012-06-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多