【问题标题】:Double random assignment with equal groups具有相等组的双重随机分配
【发布时间】:2014-05-28 15:56:49
【问题描述】:

我正在尝试为我正在开发的网站构建一个随机样本和随机分配生成器,该网站应该将相同数量的随机选择的项目分配给一组可变的人。

例如:

本轮测评共有 9 位测评员,477 道题,需要两名测评员各打分(同一测评员不会对同一题进行两次评分)。这样一来,总共需要进行 954 项“评估”,每位评估员 106 项。

因此,我需要一个最终列表,例如...

(Item, Assessor1, Assessor2)
(1, A, B)
(2, C, D)
(3, E, F)
(4, G, H)
(5, H, B)
(6, B, F)
.
.
.
And so on

我找到了可以生成随机数的网站,甚至一些可以对组进行随机分配的网站,但即便如此,我仍然发现同一评估员会在整个结果中对同一项目进行评分的情况。

我不太关心固有的随机性,而是更关心确保每个结果列表中的每个评估员都对相同数量的项目进行评分,而不是对相同的项目进行评分。

我通常可以达到我拥有它的程度 - 接近 - 也许一个评分员会多 1 或 2 分,而另一位会少 1 或 2 分,但不幸的是,他们是平等的分组是一个硬性要求。

编辑

实现了@Tinstaafl 的代码并运行了以下代码:

  Dim col As New MyItemCollection

    col.AddAssessor("A")
    col.AddAssessor("B")
    col.AddAssessor("C")
    col.AddAssessor("D")
    col.AddAssessor("E")
    col.AddAssessor("F")
    col.AddAssessor("G")
    col.AddAssessor("H")
    col.AddAssessor("I")

    For I As Integer = 1 To 477
        col.AddItem(I.ToString)
    Next

    Dim newList As List(Of MyItemCollection.MyItem) = col.AssignAssessors

    For Each item As MyItemCollection.MyItem In col.itemlist
        Response.Write(item.ToString & "<br/>")
    Next

不幸的是我的输出看起来像

1 - F - F
2 - I - I
3 - E - E
4 - F - F
5 - C - C
6 - D - D
7 - G - G
8 - A - A
9 - C - C
10 - B - B
11 - D - D
12 - D - D
13 - D - D
14 - D - D
15 - H - H

等等……

【问题讨论】:

    标签: vb.net algorithm random random-sample


    【解决方案1】:

    我能想到的一个思路如下:

    随机分配评估员 {1-9}。然后根据本次shuffle的结果依次分配前4.5个item。

    然后再次洗牌。再次将它们按顺序分配给下一个项目。如果第一个评估者恰好是已经分配给第 5 项的同一个评估者,则交换列表中的第一个和第二个评估者。

    对所有项目继续这样做。

    【讨论】:

      【解决方案2】:

      一种方法是为项目和评估者使用集合类和嵌入类。以下是展示如何生成列表的部分实现:

      Public Class MyItemCollection
          Class Assessor
              Public Name As String = ""
              Public Shared Operator <>(LH As Assessor, RH As Assessor) As Boolean
                  Return LH.Name <> RH.Name
              End Operator
              Public Shared Operator =(LH As Assessor, RH As Assessor) As Boolean
                  Return RH.Name = LH.Name
              End Operator
              Public Overrides Function ToString() As String
                  Return Name
              End Function
          End Class
          Class MyItem
              Public Name As String = ""
              Public Assessor1 As New Assessor
              Public Assessor2 As New Assessor
              Public Overrides Function ToString() As String
                  Return Name & " - " & Assessor1.ToString & " - " & Assessor2.ToString
              End Function
          End Class
          Private AssessorList As New List(Of Assessor)
          Private ItemList As New List(Of MyItem)
          Public Sub AddAssessor(Name As String)
              AssessorList.Add(New Assessor With {.Name = Name})
          End Sub
          Public Sub AddItem(Name As String)
              ItemList.Add(New MyItem With {.Name = Name})
          End Sub
          Private Rnd As New Random(Now.Millisecond * Now.Day * Now.Minute)
          Public Function AssignAssessors() As List(Of MyItem)
              Dim OutVal As New List(Of MyItem)
              Dim average As Integer = ((ItemList.Count \ AssessorList.Count) * 2) + 5
              Dim AssessorCount(AssessorList.Count - 1) As Integer
              For Each item As MyItem In ItemList
                  Dim firstassessorindex As Integer
                  Do
                      firstassessorindex = Rnd.Next(0, AssessorList.Count)
      
                  Loop Until AssessorCount(firstassessorindex) <= average
                  item.Assessor1 = AssessorList(firstassessorindex)
                  AssessorCount(firstassessorindex) += 1
                  Dim secondassessorindex As Integer
                  Do
                      secondassessorindex = Rnd.Next(0, AssessorList.Count)
      
                  Loop Until AssessorList(secondassessorindex) <> item.Assessor1 AndAlso AssessorCount(secondassessorindex) < average
                  item.Assessor2 = AssessorList(secondassessorindex)
                  AssessorCount(secondassessorindex) += 1
              Next
              OutVal = ItemList
              Return OutVal
          End Function
      End Class
      

      您的解释中不清楚的一件事是 Assessor1 和 Assessor2 之间的分布是否重要(如果评估者是第二个评估者的次数多于第一个评估者,这有关系吗?)。如果您需要,那么 AssessorCount 可能需要 List(Of Tuple(Integer, Integer)) 而不是 List(Of Integer)

      返回列表中每个项目的ToString 方法将采用以下格式 -

      ItemName - Assessor1Name - Assessor2Name

      【讨论】:

      • 试图实现你上面放的东西,但没有得到任何好处。它似乎所做的只是随机分配一名评估员,然后在两个地点分配相同的评估员。请查看我的问题编辑以了解我使用的代码。
      • @TheTXI - 抱歉有几个错别字。现在应该会更好。
      • 在我有机会回到这里之前,我设法自己完成了一个可行的概念证明。我现在几乎不敢去尝试你的了。明天早上我会试一试,我也会发布我的解决方案作为答案。
      【解决方案3】:

      我不确定我是否理解你的分配规则,但这可能很接近。

      var assessors = new []
      {
          "A", "B", "C",
          "D", "E", "F",
          "G", "H", "I",
      };
      
      var rnd = new Random();
      
      var query =
          from a1 in assessors
          from a2 in assessors
          where a1 != a2
          orderby rnd.Next()
          select new { a1, a2};
      
      var results =
          Enumerable
              .Range(1, 477)
              .Zip(query
                  .Repeat(),
                  (i, aa) => new
                  {
                      Item = i,
                      Assessor1 = aa.a1,
                      Assessor2 = aa.a2,
                  });
      

      我得到这样的结果:

        1  F  B
        2  E  C
        3  D  H
          ... 
      476  F  C
      477  B  E
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-01-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-30
        • 2011-10-02
        • 2014-03-14
        • 2022-09-28
        相关资源
        最近更新 更多