随机选择文件中的行

时间:2010-06-09 20:49:14

标签: python perl shell

我有一堆文件,而且文件有5行的标题。在文件的其余部分,一对行形成一个条目。我需要从这些文件中随机选择条目。 如何选择随机文件和随机条目(一对行,不包括标题)?

7 个答案:

答案 0 :(得分:6)

您可能会发现perlfaq5有用。

答案 1 :(得分:6)

如果文件足够小,请将行对读入内存,然后从该数据结构中随机选择。如果文件太大,Eugene Y会提供正确的答案:使用reservoir sampling

这是算法的直观解释。

Process the file line by line.
pick = line, with probability 1/N, where N = line number

换句话说,在第1行,我们将以1/1概率选择第1行。在第2行,我们将更改选择到第2行,概率为1/2。在第3行,我们将选择更改为第3行,概率为1/3。等

为了直观证明,想象一下有3行的文件:

        1            Pick line 1.
       / \
     .5  .5
     /     \
    2       1        Switch to line 2?
   / \     / \
 .67 .33 .33 .67
 /     \ /     \
2       3       1    Switch to line 3?

每个结果的可能性:

Line 1: .5 * .67     = 1/3
Line 2: .5 * .67     = 1/3
Line 3: .5 * .33 * 2 = 1/3

从那里开始,其余的就是感应。例如,假设文件有4行。我们已经说服自己,从第3行开始,到目前为止,每一行(1,2,3)都有平等的机会成为我们的当前选择。当我们前进到第4行时,它将有1/4被挑选的机会 - 正是它应该是什么,从而将前3行的概率减少恰当的数量(1/3 * 3/4 = 1/4)。

这是适合您问题的Perl FAQ answer

use strict;
use warnings;

# Ignore 5 lines.
<> for 1 .. 5;

# Use reservoir sampling to select pairs from remaining lines.
my (@picks, $n);
until (eof){
    my @lines;
    $lines[$_] = <> for 0 .. 1;

    $n ++;
    @picks = @lines if rand($n) < 1;
}

print @picks;

答案 2 :(得分:3)

sed "1,5d" < FILENAME | sort -R | head -2

答案 3 :(得分:3)

Python解决方案 - 只读取一次文件并且需要很少的内存

像这样调用getRandomItems(file('myHuge.log'), 5, 2) - 将返回2行的列表

from random import randrange

def getRandomItems(f, skipFirst=0, numItems=1):
    for _ in xrange(skipFirst):
        f.next()
    n = 0; r = []
    while True:
        try:
            nxt = [f.next() for _ in range(numItems)]
        except StopIteration: break
        n += 1
        if not randrange(n):
            r = nxt
    return r

如果无法从f获取第一个可通过的项目,则返回空列表。代码的唯一要求是参数f是一个迭代器(支持next()方法)。因此,我们可以传递与文件不同的内容,比如说我们想要查看分发:

>>> s={}
>>> for i in xrange(5000):
...     r = getRandomItems(iter(xrange(50)))[0]
...     s[r] = 1 + s.get(r,0)
... 
>>> for i in s: 
...     print i, '*' * s[i]
... 
0 ***********************************************************************************************
1 **************************************************************************************************************
2 ******************************************************************************************************
3 ***************************************************************************
4 *************************************************************************************************************************
5 ********************************************************************************
6 **********************************************************************************************
7 ***************************************************************************************
8 ********************************************************************************************
9 ********************************************************************************************
10 ***********************************************************************************************
11 ************************************************************************************************
12 *******************************************************************************************************************
13 *************************************************************************************************************
14 ***************************************************************************************************************
15 *****************************************************************************************************
16 ********************************************************************************************************
17 ****************************************************************************************************
18 ************************************************************************************************
19 **********************************************************************************
20 ******************************************************************************************
21 ********************************************************************************************************
22 ******************************************************************************************************
23 **********************************************************************************************************
24 *******************************************************************************************************
25 ******************************************************************************************
26 ***************************************************************************************************************
27 ***********************************************************************************************************
28 *****************************************************************************************************
29 ****************************************************************************************************************
30 ********************************************************************************************************
31 ********************************************************************************************
32 ****************************************************************************************************
33 **********************************************************************************************
34 ****************************************************************************************************
35 **************************************************************************************************
36 *********************************************************************************************
37 ***************************************************************************************
38 *******************************************************************************************************
39 **********************************************************************************************************
40 ******************************************************************************************************
41 ********************************************************************************************************
42 ************************************************************************************
43 ****************************************************************************************************************************
44 ****************************************************************************************************************************
45 ***********************************************************************************************
46 *****************************************************************************************************
47 ***************************************************************************************
48 ***********************************************************************************************************
49 ****************************************************************************************************************

答案 4 :(得分:1)

答案是Python。假设您可以将整个文件读入内存。

#using python 2.6
import sys
import os
import itertools
import random

def main(directory, num_files=5, num_entries=5):
    file_paths = os.listdir(directory)

    # get a random sampling of the available paths
    chosen_paths = random.sample(file_paths, num_files)

    for path in chosen_paths:
        chosen_entries = get_random_entries(path, num_entries)
        for entry in chosen_entries:
            # do something with your chosen entries
            print entry

def get_random_entries(file_path, num_entries):
    with open(file_path, 'r') as file:
        # read the lines and slice off the headers
        lines = file.readlines()[5:]

        # group the lines into pairs (i.e. entries)
        entries = list(itertools.izip_longest(*[iter(lines)]*2))

        # return a random sampling of entries
        return random.sample(entries, num_entries)

if __name__ == '__main__':
    #use optparse here to do fancy things with the command line args
    main(sys.argv[1:])

链接:itertoolsrandomoptparse

答案 5 :(得分:0)

另一个Python选项;将所有文件的内容读入内存:

import random
import fileinput

def openhook(filename, mode):
    f = open(filename, mode)
    headers = [f.readline() for _ in range(5)]
    return f

num_entries = 3
lines = list(fileinput.input(openhook=openhook))
print random.sample(lines, num_entries)

答案 6 :(得分:0)

另外两种方法: 1-由生成器(可能仍需要大量内存): http://www.usrsb.in/Picking-Random-Items--Take-Two--Hacking-Python-s-Generators-.html

2-聪明的寻求(实际上最好的方法): http://www.regexprn.com/2008/11/read-random-line-in-large-file-in.html

我在这里复制了聪明的Jonathan Kupferman的代码:

#!/usr/bin/python

import os,random

filename="averylargefile"
file = open(filename,'r')

#Get the total file size
file_size = os.stat(filename)[6]

while 1:
      #Seek to a place in the file which is a random distance away
      #Mod by file size so that it wraps around to the beginning
      file.seek((file.tell()+random.randint(0,file_size-1))%file_size)

      #dont use the first readline since it may fall in the middle of a line
      file.readline()
      #this will return the next (complete) line from the file
      line = file.readline()

      #here is your random line in the file
      print line