【问题标题】:How to choose a random line from a text file如何从文本文件中选择随机行
【发布时间】:2013-02-17 18:48:46
【问题描述】:

我正在尝试为我的学校制定一个彩票计划(我们有一个经济体系)。

我的程序生成数字并将其保存到文本文件中。当我想从我的发电机中“拉”出数字时,我希望它确保有赢家。

问:我如何让 Python 从我的文本文件中随机选择一行并将我的输出作为该数字给出?

【问题讨论】:

    标签: python file random python-3.3


    【解决方案1】:

    我如何让 python 从我的文本文件中随机选择一行并将我的输出作为那个数字?

    假设文件相对较小,以下可能是最简单的方法:

    import random
    line = random.choice(open('data.txt').readlines())
    

    【讨论】:

      【解决方案2】:

      如果文件非常大 - 您可以在给定文件大小的情况下寻找文件中的随机位置,然后获取下一个完整行:

      import os, random 
      def get_random_line(file_name):
          total_bytes = os.stat(file_name).st_size 
          random_point = random.randint(0, total_bytes)
          file = open(file_name)
          file.seek(random_point)
          file.readline() # skip this line to clear the partial line
          return file.readline()
      

      【讨论】:

      • 该方法会使较短的行被选择的机会较小,因此如果您真的希望随机生成器以相同的概率选择每一行,这不是一个好的选择。
      • 它也永远不会返回第一行,并且当 random_point 在最后一行时根本不会返回一行。
      【解决方案3】:
      def random_line():
          line_num = 0
          selected_line = ''
          with open(filename) as f:
              while 1:
                  line = f.readline()
                  if not line: break
                  line_num += 1
                  if random.uniform(0, line_num) < 1:
                      selected_line = line
          return selected_line.strip()
      

      虽然这里给出的大多数方法都可以工作,但它们倾向于一次将整个文件加载到内存中。但不是这种方法。因此,即使文件很大,这也可以。

      乍一看,这种方法不是很直观。这背后的定理表明,当我们在其中看到 N 行时,到目前为止,它们中的每一个都被选中的概率恰好是 1/N。

      From Page no 123 of 'Python Cookbook'

      【讨论】:

        【解决方案4】:

        对你的输入文件稍作修改(将项目的数量存储在第一行),你可以统一选择一个数字,而不必先将整个文件读入内存。

        import random
        def choose_number( frame ):
            with open(fname, "r") as f:
                count = int(f.readline().strip())
                for line in f:
                    if not random.randrange(0, count):
                        return int(line.strip())
                    count-=1
        

        假设您有 100 个数字。选择第一个数字的概率是 1/100。选择第二个数字的概率是 (99/100)(1/99) = 1/100。选择第三个数字的概率是 (99/100)(98/99)(1/98) = 1/100。我将跳过正式的证明,但选择 100 个数字中的任何一个的几率都是 1/100。

        将计数存储在第一行并不是绝对必要的,但它可以省去为了计算行数而读取整个文件的麻烦。无论哪种方式,您都不需要将整个文件存储在内存中以相同概率选择任何单行。

        【讨论】:

        • 如果您已经将行数作为第一个元素,则无需为每一行调用random.randrange。只需随机选择行号并前进到该行。
        【解决方案5】:

        在我的头顶:

        import random
        def pick_winner(self):
            lines = []
            with open("file.txt", "r") as f:
                lines = f.readlines();
            random_line_num = random.randrange(0, len(lines))
            return lines[random_lines_num]
        

        【讨论】:

          【解决方案6】:

          另一种方法:

          import random, fileinput
          
          text = None
          for line in fileinput.input('data.txt'):
              if random.randrange(fileinput.lineno()) == 0:
                  text = line
          print text
          

          分布:

          $ seq 1 10 > data.txt
          
          # run for 100000 times
          $ ./select.py > out.txt
          
          $ wc -l out.txt 
          100000 out.txt
          
          $ sort out.txt | uniq -c
            10066 1
            10004 10
            10023 2
             9979 3
             9926 4
             9936 5
             9878 6
            10023 7
            10154 8
            10011 9
          

          我没有看到偏斜,但可能数据集太小...

          【讨论】:

          • 这会使选择偏向文件中较早出现的数字。
          • 它与我预期的有点不同(我没有仔细查看您的代码)。您基本上是在选择一组从 1 到 10 的数字,然后输出最大的一个。因此,尽管选择 1 作为集合的一部分的可能性更大(事实上,它将始终成为集合的一部分,因为randrange(0,1) 将始终返回 0),但它永远不会被返回除非选择了 no 其他数字。请注意,您的分布看起来像一条倒置的钟形曲线,选择极端数字的频率明显高于中间数字。
          • @chepner - 你在这里做点什么。今天学了点儿新东西。我想我会玩一段时间的发行版。谢谢。
          • 所以,我计算了一些概率,并且对 选择 较小数字的偏见和对 输出 较大数字的偏见完全抵消了,所以你应该有 1/10 的机会输出 10 个数字中的任何一个。例如,选择数字 3 的几率是 1/3,但选择更大数字的几率是 (3/4)(4/5)。 ..(9/10),两者的乘积正好是 1/10。我认为我看到的倒钟形曲线可能是由于样本量小。
          • +1。没有偏斜。该算法产生均匀分布。 @chepner:这是众所周知的reservoir sampling with k==1 algorithmenumerate() could be used instead of fileinput.lineno()
          【解决方案7】:

          我看了一个python教程,发现了这个sn-p:

          def randomLine(filename):
          #Retrieve a  random line from a file, reading through the file once
                  fh = open("KEEP-IMPORANT.txt", "r")
                  lineNum = 0
                  it = ''
          
                  while 1:
                          aLine = fh.readline()
                          lineNum = lineNum + 1
                          if aLine != "":
                                  #
                                  # How likely is it that this is the last line of the file ? 
                                  if random.uniform(0,lineNum)<1:
                                          it = aLine
                          else:
                                  break
                  nmsg=it
                  return nmsg
                  #this is suposed to be a var pull = randomLine(filename)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-09-03
            • 2012-01-10
            • 2012-03-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多