从python中的随机行开始读取CSV文件

时间:2017-12-02 06:30:07

标签: python csv

我必须读取csv文件中的10,00,000行(692 MB),包含26,00,000行和4列,包含多个线程,每个行从一个随机行开始,当我达到100万行时停止< / p>

我的尝试:

from multiprocessing.pool import ThreadPool as Pool
import linecache
import random
import csv
from random import randint
from time import sleep

csvfile=csv.reader(open('sample.csv'))


def process_line(l):
  sleep(randint(0,3))
  print (l)
def get_random_line():    
  lines_to_get=random.randint(0,2600000)
  line = linecache.getline('sample.csv', lines_to_get)

  for lines_to_get, line in enumerate(csvfile):
      print (line)

      if lines_to_get >= 1000000:
        break

    yield (line)

f = get_random_line()

t = Pool(processes=3)

for i in f:
  t.map(process_line, (i,))


t.close()

但是在结果中,线条并非从随机开始,而是每次从第一行开始。

结果

['1', '31', '2.5', '1260759144']
['1', '1029', '3.0', '1260759179']
['1', '1061', '3.0', '1260759182']
['1', '1129', '2.0', '1260759185']
['1', '1172', '4.0', '1260759205']
['1', '1263', '2.0', '1260759151']
['1', '1287', '2.0', '1260759187']
['1', '1293', '2.0', '1260759148']
['1', '1339', '3.5', '1260759125']

严格要求我应该每次从随机行开始

3 个答案:

答案 0 :(得分:1)

如果没有多处理,这将完成您的要求,部分原因是您很可能不需要它。

一个简单的基准测试使选项3成为速度的赢家。

选项1:

import csv

import random

starting_points = [random.randint(0, 5) for i in range(3)]

read_nbr_of_lines = 2

for sp in starting_points:
    print('random starting line: %s'%sp)
    read_lines = 0
    with open('large_csv.csv') as cf:
        lines = csv.reader(cf)
        for nbr, line in enumerate(lines):
            if nbr < sp - 1: continue
            read_lines += 1
            if read_lines > read_nbr_of_lines: break
            print(nbr, line)

对于大量数据而言,这可能会变得很慢,但是在使用csv-module时,我希望在随机点开始时尝试解决这个问题。 / p>

通过使用f.seek(start_byte)对字节上的起始点进行种子设定,然后使用f.read(my_chunk_size)读取文件中的一大块字节,可以解决从字节0读取文件的问题。在这种情况下,为了获得一个新线,您必须在随机起始点之后通过new_line_char找到自己的行,为行创建自己的解析器并保留一个计数器来读取您读取的行数。

选项2: 如果您的文件小于1GB,这就是您所说的。 在计算机上安装numpy,一次读取文件。 通过索引到整个行集来选择1e6行。 下面将有dtype=np.float64,如果你想保持整数也有办法做到这一点。为此,我建议研究numpy的文档。

import random
import numpy as np
mycsv = np.genfromtxt('large_csv.csv', delimiter=',')    
starting_lines = [random.randint(0, 5) for i in range(3)]
read_nbr_of_lines = 2

for sl in starting_lines:
    print('lines %s to %s'%(sl, sl+read_nbr_of_lines-1))
    print(mycsv[sl:sl+read_nbr_of_lines])

选项3: 我对linecache有点好奇,所以我也为此做了一个解决方案。 更新了适当的发电机设置。

import linecache as lc
import csv
import random

starting_lines = [random.randint(1, 10) for i in range(3)]
read_nbr_of_lines = 2

for sl in starting_lines:
    iterator = (lc.getline('large_csv.csv', i) for
                i in range(sl, sl+read_nbr_of_lines))
    mycsv = csv.reader(iterator)
    print('lines %s to %s'%(sl, sl+read_nbr_of_lines-1))
    for row in mycsv:
        print(row)

简单基准(Py36):

具有3.5M线的csv,起始线1M,2M,3M和读取0.5M线。为了使它与numpy有些公平,其他人有一行将所有读取行转换为浮动列表。

<强>结果:

=====================================
random starting line: 1000000
last_line 1499999 [1.0, 1172.0, 4.0, 1260759205.0]
random starting line: 2000000
last_line 2499999 [1.0, 1263.0, 2.0, 1260759151.0]
random starting line: 3000000
last_line 3499999 [3499999.0, 1287.0, 2.0, 1260759187.0]
option 1 timing: 13.678 seconds
=====================================
random starting line: 1000000
last_line 1499999 [  1.50000000e+06   1.26300000e+03   2.00000000e+00   1.26075915e+09]
random starting line: 2000000
last_line 2499999 [  2.50000000e+06   1.28700000e+03   2.00000000e+00   1.26075919e+09]
random starting line: 3000000
last_line 3499999 [  3.50000000e+06   1.29300000e+03   2.00000000e+00   1.26075915e+09]
option 2 timing: 23.453 seconds
=====================================
lines 1000000 to 1500000
last_line 1500000 [1500000.0, 1263.0, 2.0, 1260759151.0]
lines 2000000 to 2500000
last_line 2500000 [2500000.0, 1287.0, 2.0, 1260759187.0]
lines 3000000 to 3500000
last_line 3500000 [3500000.0, 1293.0, 2.0, 1260759148.0]
option  timing: 7.338 seconds
=====================================

答案 1 :(得分:0)

你有没有试过在运行它之前播种你的随机数发生器?用这样的代码:

import time
random.seed(time.time())

在任意随机数生成之前添加

答案 2 :(得分:0)

据我所知:

line = linecache.getline('sample.csv', lines_to_get)

这会让你获得随机行并存储它。

在for循环之后,你立即将这个“line”变量替换为csvfile的第一行。

for lines_to_get, line in enumerate(csvfile):
      print (line)

这会导致您丢失先前设置的随机行。