【问题标题】:algorithm for breaking single set of rows & columns into n rectangular fragments of random rows & random columns, randomly overlapping将单组行和列分解为随机行和随机列的 n 个矩形片段的算法,随机重叠
【发布时间】:2016-01-06 15:33:23
【问题描述】:

我想将(给定的)单组 D 的行和列(例如电子表格或数据库表)的数据转换为随机生成的一组 N 个片段,给定的数字 n 是

澄清一下:“n”是用户提供的一个非零整数,意思是“使用 D,至少还给我 n 个片段”。 “N”是返回的片段的实际数量。一种可接受的算法是产生至少 n 个片段的算法。对于两种可接受的算法 X 和 Y,如果在其他条件相同的情况下,X 产生的 N 比 Y 产生的 N 更接近 n,则 X 比 Y 更好。

此外,任何分片中任何一行中的数据也必须包含在 D 中的一行中。(每个分片还需要包含一个标识符列,例如行 ID 或其他具有唯一值的列,但这应该输出片段时添加是微不足道的)。因此,例如,如果 D 包含姓名和电话号码以及其他列,那么其中包含姓名和电话号码的任何片段都应该始终具有与该行名称相关联的正确电话号码。

一般来说,如果任何列存在于片段中的任何位置,则它必须存在于该片段的每一行(例如,如果第 1 行包含 A、B 和 C 列,则第 2 行必须包含这些相同的列),列也是如此(例如,如果 B 列包含第 4、5 和 6 行,则片段中的每个其他列也必须包含第 4、5 和 6 行)。

如果 N = 4,那么我想出的最简单的方法是:

  1. 对于每一行,掷一枚硬币。如果是正面,则分配给片段 1
  2. 对于每一行,掷一枚硬币。如果正面,则分配给片段 2
  3. 对于每一行,如果它没有分配给片段 1 或片段 2,则掷硬币,如果是正面,则分配给片段 1,否则分配给片段 2
  4. 对所有列重复上述 3 个步骤。现在我们有了片段 1 和 2,但它们不一定涵盖 D 中的所有数据。继续到 3 和 4。
  5. 对于每一行,掷一枚硬币。如果是正面,则分配给片段 3;否则,如果该行已分配给片段 2,但未分配给片段 1,则分配给片段 3。
  6. 对于每一列,掷一枚硬币。如果是正面,则分配给片段 3;否则,如果该列分配给片段 2 而不是片段 1,则分配给片段 3。
  7. 对于每一行,掷一枚硬币。如果是正面,则分配给片段 4;否则,如果该行已分配给片段 1,但未分配给片段 2,则分配给片段 4。
  8. 对于每一列,掷一枚硬币。如果是正面,则分配给片段 4;否则,如果此列分配给片段 1 而不是片段 2,则分配给片段 4

我相信这应该会产生 4 个可能看起来像这样的片段,假设行和列被重新排序为片段 1 的连续块,并且在不与之冲突的情况下尽可能与片段连续2(绿色是黄色+蓝色重叠的地方):

但是,这种方法似乎难以扩展到更高的 N 值。有没有更简单的方法可以将这种方法推广到任何 n 或 N 值?

【问题讨论】:

  • 你说有N个片段,n一定是
  • n 只是一个大于零的整数,是算法的输入
  • 是什么意思?例如,为什么我不能简单地说“让 n = 42”?
  • 意思是“我想把数据集 D 分成至少 n 个片段”。如果可以说“我想将数据集 D 分解成 完全 n 个片段”会更好
  • 确实,nN 的概念仍然不清楚。需要清楚地说明它们是什么,有什么区别,以及为什么需要两者。到目前为止,我知道 N 是一个输入,而 n 将是生成的片段的实际数量,以防算法无法达到 N 的计数,但后来你写到 n 是算法的输入......令人困惑。

标签: algorithm overlap rectangles random-sample


【解决方案1】:

--编辑(添加第 0 步)--

步骤 0. 随机分配每个片段的概率权重;随机挑选时使用这些权重。第 1 步和第 2 步可能需要不同的权重结构。

步骤 1. 为每列分配一组随机片段(这在某种程度上类似于 @Jim 为每个单元格提出的建议,但以列为基础)。所以最后,每一列都属于一个或多个片段。如果您为每列分配至少 2 个片段会更好;我在下面解释为什么我建议这个技巧。

您应该要求进行最终检查以确保所有片段至少出现一次,如果没有,请尝试将丢失的片段添加到随机列数中。

在这个阶段,所有片段都存在,但它们占据了每一行。

第 2 步。扫描每一行并随机删除一些(不是全部)为该行分配的片段。您不能删除仅从该片段中表示该行中至少一个单元格的片段。这就是为什么在第 1 步中,我建议您每列至少选择 2 个片段,因此您始终可以安全地删除每行至少一个片段。如果您不这样做,则某些片段(至少一列上的唯一占用者)可能永远不会被删除,并且会继续占用每一行。

执行最后一次检查以确保您没有完全擦除任何碎片。

注意 1。您可以通过以下概率控制重叠密度:a)在步骤 1 中每列选取 X 个片段,b)在步骤 2 中每行删除 Y 个片段。

注意 2。第 1 步可以针对行运行,第 2 步可以针对列运行,也许最好将第 1 步应用于更大的维度(以符合 OP 注释)。

【讨论】:

  • 谢谢,会试试的。乍一看,我担心的是,即使在使用概率时,随着行数的增加,结果分布最终可能会变得越来越多,而且在相当大的行数(比如 50,000)的情况下,发现获得看似随机的结果(不是 0% 或 100% 重叠)的概率可能需要大量试验和错误(和/或超过计算机的浮点精度能力)。并不是说这必然意味着这不能回答问题——但在实践中很难使用。
【解决方案2】:

一个非常简单的方法是为每个单元格分配一个从 1 到 15 的数字,包括 1 到 15。四位中的每一位对应于片段之一。因此,如果设置了位 0,则该单元格是片段 1 的一部分。如果设置了位 1,则设置了片段 2,依此类推。因此,分配了编号 1 的单元格将位于片段 1 中。编号为 9 的单元格(二进制为 1001)将属于片段 1 和 4。

最后你应该得到均匀分布在四个片段中的细胞。

对于任意数量的片段,n,选择一个介于 1 和 2^n 之间的数字。

如果有特殊限制,例如“如果 cell(row, 1) 在片段 x 中,则 cell(row, 5) 也必须包含在该片段中”,您可以在后处理中轻松地修复这些限制结果集的单次扫描。

【讨论】:

  • 考虑到我添加到问题中的说明(从“一般来说”开始),按照您的建议,如果 n = 4,那么 D 的尺寸(例如,1000 x 200)似乎更大对我来说,几乎所有 4 个片段都等于 D,因为如果给定列(行)中的任何单元格在片段 X 中,那么整个列(行)必须在 X 中。
  • @mwag:你是对的。让我再考虑一下,我会发布更新。
【解决方案3】:

给出的是:

  • D:一个矩阵,C 列,R 行,两个维度从 0 到 D-1 编号
  • N:所需的“片段”数,编号从 0 到 N-1。片段表示从原始矩阵中删除一些随机列和行所产生的矩阵。

必填:

矩阵 D 中的每个单元格必须是至少一个片段的一部分。

算法:

fragments = empty array []
usedCols = array [0, .., 0] // C elements
usedRows = array [0, .., 0] // R elements

For f in 0..N-1: 
   Let fragments[f] = object {cols: array [0, .., C-1], rows: array [0, .., R-1]}

   Let deleteCount = random number between 0 and (C-1)
   For i in 1..deleteCount:
      Let index = random number between 0 and (C-i)
      Let excludedCol = fragments[f].cols[index]
      Let usedCols[excludedCol] = 1
      // "splice" the column out of the fragment, 
      // moving elements at higher indices to one lower index.
      Remove fragments[f].cols[index]

   Let deleteCount = random number between 0 and (R-1)
   For i in 1..deleteCount:
      Let row = random number between 0 and (R-i)
      Let excludedRow = fragments[f].rows[index]
      Let usedRows[excludedRow] = 1
      Remove fragments[f].rows[index]  // "splice"

// Assign rows/columns that have not been assigned 
// to any fragment to a random fragment:
For col in 0..C-1:
   If usedCols[col] == 0 Then
      Let f = random number between 0 and N-1
      Add col to fragments[f].cols
For row in 0..R-1:
   If usedCols[row] == 0 Then
      Let f = random number between 0 and N-1
      Add row to fragments[f].rows

最后,您将拥有一个片段数组,每个片段有一个数组元素,每个元素定义一组行和一组属于该片段的列。

【讨论】:

  • 行数和列数不一定相同,这似乎与您的代码假设的不同,但我认为这对您的答案并不重要。此外,似乎 usedCols 和 usedRows 应该初始化为 [1..1] 并在 Remove 调用之前设置为 0。但无论我是否正在阅读,我都认为我明白了要点。然而……
  • ...在我看来,最后 8 行可能有缺陷。考虑如果 N = 4 和一个由 2 行和 2 列组成的过度简化的 D:将它们称为 A1、A2、B1 和 B2(类似于 Excel 单元格地址)。偶然地,假设 frag 1 = frag 2 = A1,并且 frag 3 = frag 4 = B2(A2 和 B1 未分配给任何 frag)。然后第 1 行和第 2 行都被使用了,A 列和 B 列也都被使用了,所以最后 8 行代码永远不会执行它们的 Add 语句,并且 A2 和 B1 仍然没有被任何片段表示。
猜你喜欢
  • 1970-01-01
  • 2021-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-15
  • 2018-06-29
  • 1970-01-01
相关资源
最近更新 更多