2

我正在尝试计算每个选举候选人(特别是 Stack Overflow 2014 版主选举)的第一、第二和第三选择票数。我下载了数据文件并打开了它。根据我对文件格式的基本解释,我编写了一个 PHP 脚本来计算选票:

<?php

$lines = file("stackoverflow-com-2014-election-results.blt");
unset($lines[0]);

$ballots = 0;
$first = array();
$second = array();
$third = array();

for ($i = 1;; $i++) {
    $line = explode(" ", trim($lines[$i]));
    if ($line[0] != 1) break;
    $ballots++;
    @$first[$line[1]]++;
    @$second[$line[2]]++;
    @$third[$line[3]]++;
}

$names = array();

for ($i++; $i < count($lines); $i++) {
    $names[count($names) + 1] = trim(trim($lines[$i]), '"');
}

printf("%20s%8s%8s%8s%8s\n", "Name", "1st", "2nd", "3rd", "Total");
print(str_repeat("-", 52) . "\n");
foreach ($names as $id => $name) {
    printf("%20s%8s%8s%8s%8s\n", $name,
        $first[$id], $second[$id], $third[$id],
        $first[$id] + $second[$id] + $third[$id]);
}
print(str_repeat("-", 52) . "\n");
printf("Ballots: %d\n", $ballots);

当我在命令行运行它时,它会打印这个表:

                Name     1st     2nd     3rd   Total
----------------------------------------------------
                Undo    1358    1425    1814    4597
            bluefeet    3352    3148    2287    8787
          0x7fffffff    1932    2147    2159    6238
            Bohemian    5678    2935    2415   11028
        Jon Clements    1531    1527    1618    4676
            Doorknob    1165    1720    1753    4638
         Raghav Sood    1358    1565    1571    4494
      Siddharth Rout    1732    1872    1866    5470
                Matt    1381    1988    2009    5378
              meagar    1903    2382    2881    7166
----------------------------------------------------
Ballots: 21571

我的问题是当我在同一个文件上运行它时,我无法让它与 OpenSTV 所说的相匹配。“第一选择的数量”都略有不同:

Ballot file contains 21571 non-empty ballots.

Counting votes for Stack Overflow Moderator Election 2014 using Meek STV.
10 candidates running for 3 seats.

 R|Undo          |bluefeet      |0x7fffffff    |Bohemian      |Jon Clements  
  |              |              |              |              |              
  |--------------+--------------+--------------+--------------+--------------
  |Doorknob      |Raghav Sood   |Siddharth Rout|Matt          |meagar        
  |              |              |              |              |              
  |--------------+--------------+--------------+--------------+--------------
  |Exhausted     |Surplus       |Threshold     
  |              |              |              
=============================================================================
 1|   1379.000000|   3372.000000|   1951.000000|   5707.000000|   1545.000000
  |   1181.000000|   1375.000000|   1749.000000|   1389.000000|   1923.000000
  |      0.000000|    314.249999|   5392.750001
  |--------------------------------------------------------------------------
  | Count of first choices. Candidate Bohemian has reached the threshold and
  | is elected.
=============================================================================
[...]

我究竟做错了什么?或者 OpenSTV 有什么不同?


更新:我的脚本破坏了,因为它没有考虑到一些用第二或第三选择编码的行,而没有设置先前的选择。我猜这是由于选举中的用户有时会取消选择先前的选择造成的:在选择了两个候选人之后,取消选择第一选择的候选人应该将唯一剩余的选定候选人视为用户的首选。

固定版本:

<?php

$lines = file("stackoverflow-com-2014-election-results.blt");

$line = explode(" ", trim($lines[0]));
$numCandidates = $line[0];
$numChoices = $line[1];
$choiceVotes = array_fill(1, $numChoices, array_fill(1, $numCandidates, 0));

$totalBallots = 0;

for ($i = 1;; $i++) {
    $line = explode(" ", trim($lines[$i]));
    if ($line[0] == 0) break;
    $totalBallots++;
    for ($j = 1, $k = 1; $j <= $numChoices; $j++) {
        if ($line[$j] != 0) $choiceVotes[$k++][$line[$j]]++;
    }
}

$names = array();
for ($j = 1; $j <= $numCandidates; $j++) {
    $names[$j] = trim(trim($lines[$j + $i]), '"');
}

$rowFormat = "%20s" . str_repeat("%8s", $numChoices) . "%8s\n";
$separator = str_repeat("-", 20 + (8 * $numChoices) + 8) . "\n";

$row = array("Name");
for ($i = 1; $i <= $numChoices; $i++) $row[] = $i . gmdate('S', $i * 86400 - 1);
$row[] = "Total";
vprintf($rowFormat, $row);

print $separator;
foreach ($names as $id => $name) {
    $row = array($name);
    $candidateTotal = 0;
    for ($i = 1; $i <= $numChoices; $i++) {
        $votes = $choiceVotes[$i][$id];
        $row[] = $votes;
        $candidateTotal += $votes;
    }
    $row[] = $candidateTotal;
    vprintf($rowFormat, $row);
}
print $separator;
printf("Ballots: %d\n", $totalBallots);
4

2 回答 2

1

我在包含选票行的数据文件上运行了您的脚本:21563

                Name     1st     2nd     3rd   Total
----------------------------------------------------
              meagar    1903    2382    2881    7166
         Raghav Sood    1357    1564    1570    4491
            Bohemian    5674    2935    2415   11024
          0x7fffffff    1932    2146    2159    6237
                Undo    1358    1424    1814    4596
            bluefeet    3352    3146    2284    8782
                Matt    1380    1988    2009    5377
        Jon Clements    1531    1526    1616    4673
      Siddharth Rout    1731    1871    1865    5467
            Doorknob    1165    1720    1752    4637
----------------------------------------------------
Ballots: 21563

我还将它导入到 Google 电子表格(链接)中:

谷歌电子表格

使用 .给出与您的脚本相同的结果countif()。例如:

=countif( data!B:B;$A2)

计算单元格的值C2

所以我必须得出结论,你没有使用相同的数据。中的数据

https://stackoverflow.com/election/download-result/5

甚至在您发布问题后发生了变化。

更新:

所以像这样的选票行:

1 0 6 0 0

与列:

Weight 1st 2nd 3rd end 

似乎被视为:

1 6 0

当通过 OpenSTV 获取时,即6作为第一选择并且0投票被忽略。

我做了一个测试,在那里我删除了0选择(链接到修改后的 .blt 文件

OpenSTV 的结果:

Ballot file contains 10 candidates and 21563 ballots.
No candidates have withdrawn.
Ballot file contains 21563 non-empty ballots.

Counting votes for Stack Overflow Moderator Election 2014 using Meek STV.
10 candidates running for 3 seats.

 R|meagar       |Raghav Sood  |Bohemian     |0x7fffffff   |Undo         |bluefeet     |Matt         
  |             |             |             |             |             |             |             
  |-------------+-------------+-------------+-------------+-------------+-------------+-------------
  |Jon Clements |Siddharth Rou|Doorknob     |Exhausted    |Surplus      |Threshold    
  |             |t            |             |             |             |             
====================================================================================================
 1|  1923.000000|  1374.000000|  5703.000000|  1951.000000|  1379.000000|  3372.000000|  1388.000000
  |  1544.000000|  1748.000000|  1181.000000|     0.000000|   312.249999|  5390.750001
  |-------------------------------------------------------------------------------------------------
  | Count of first choices. Candidate Bohemian has reached the threshold and is elected.
====================================================================================================

脚本的结果:

                Name     1st     2nd     3rd   Total
----------------------------------------------------
              meagar    1923    2378    2865    7166
         Raghav Sood    1374    1558    1559    4491
            Bohemian    5703    2922    2399   11024
          0x7fffffff    1951    2143    2143    6237
                Undo    1379    1419    1798    4596
            bluefeet    3372    3138    2272    8782
                Matt    1388    1991    1998    5377
        Jon Clements    1544    1516    1613    4673
      Siddharth Rout    1748    1870    1849    5467
            Doorknob    1181    1724    1732    4637
----------------------------------------------------
Ballots: 21563

我在哪里修改了你的脚本isset()

所以现在第一选择的数量似乎是一样的。

于 2014-03-09T01:43:21.730 回答
0

当我计算回车的数量,然后是这个字符串“1 10”时,我得到的总数是 1903。这与你对 meagar 的第一名投票的计数相匹配。我认为你的脚本是正确的。

于 2014-02-25T21:04:40.843 回答