在python

时间:2017-11-07 22:46:32

标签: python list file numpy

我有一个包含几百万行文字的大文件。我想随机均匀地从这个文件中提取一个较小的(250000行)。我做了以下代码,但它非常慢,实际上速度非常慢。我该怎么做才能加快速度?

def get_shorter_subset(fname, new_len):
"""Extract a random shorter subset of length new_len from a given file"""
   out_lines = []
   with open(fname + "short.out", 'w') as out_file:
      with open(fname, 'r') as in_file:
        all_lines = in_file.readlines()
        total = len(all_lines)
        print "Total lines:", total
        for i in range(new_len):
            line = np.random.choice(all_lines)
            out_lines.append(line.rstrip('\t\r\n'))
            #out_file.write(line.rstrip('\t\r\n'))
            print "Done with", i, "lines"
            all_lines.remove(line)
      out_file.write("\n".join(out_lines))

5 个答案:

答案 0 :(得分:2)

所以,问题是:

all_lines = in_file.readlines()将所有行读入内存可能不是执行此操作的最佳方法...但如果 要执行此操作,那么肯定不会这样做这个all_lines.remove(line)因为这是一个O(N)操作,你在循环中做,给你二次复杂度。

我怀疑你会通过简单地做一些事情来获得巨大的性能提升:

idx = np.arange(total, dtype=np.int32)
idx = np.random.choice(idx, size=new_len, replace=False)
for i in idx:
    outfile.write(all_lines[i])

答案 1 :(得分:1)

你也可以尝试使用mmap:

https://docs.python.org/3.6/library/mmap.html

答案 2 :(得分:1)

读入所有行,将它们保存在内存中,然后对生成的文本执行250K大字符串操作。每次从文件中删除一行时,Python都必须为剩余行创建一个新副本。

相反,只需随机抽样。例如,如果您有500万行,则需要5%的文件。一次读取一行文件。滚动随机浮点数。如果< = 0.05,则将该行写入输出。

如果这么大的样本,你最终会得到所需大小的输出。

答案 3 :(得分:1)

使用Python numpy库。 numpy.choice()功能提供您所需的功能。它会在一次调用中获取所需大小的样本。所以你的功能看起来像是:

import numpy as np

def get_shorter_subset(fname, new_len):
    """Extract a random shorter subset of length new_len from a given file"""

    with open(fname + " short.out", 'w') as out_file, open(fname, 'r') as in_file:
        out_file.write(''.join(np.random.choice(list(in_file), new_len, False)))

get_shorter_subset('input.txt', 250000)

答案 4 :(得分:0)

感谢您的回答,我做了一个解决方案,在每个索引处生成一个随机数(概率对应于new_size / full_size),并根据该数据挑选或丢弃每个元素。所以代码是:

def get_shorter_subset(fname, new_len):
"""Extract a random shorter subset of length new_len from a given 
   file"""
   out_lines = []
   with open(fname + "short.out", 'w') as out_file:
       with open(fname, 'r') as in_file:
           all_lines = in_file.readlines()
           total = len(all_lines)

           freq = total/new_len + 1
           print "Total lines:", total, "new freq:", freq
           for i, line in enumerate(all_lines):
               t = np.random.randint(1,freq+1)
               if t == 1:
                   out_lines.append(line.rstrip('\t\r\n'))
               #out_file.write(line.rstrip('\t\r\n'))
               if i % 10000 == 0:
                   print "Done with", i, "lines"

       out_file.write("\n".join(out_lines))