5

我有一个行的文本文件(几 GB 和 ~ 1200 万行),其中每行是一个点 x、y、z 和附件信息。我希望逐块读取文件,处理点并拆分(遵循基于点位置的空间索引,尊重 0.25 m 的方形网格)结果在临时文件夹中的几个文本文件中。

449319.34;6242700.23;0.38;1;1;1;0;0;42;25;3;17;482375.326087;20224;23808;23808
449310.72;6242700.22;0.35;3;1;1;0;0;42;23;3;17;482375.334291;20480;24576;24576
449313.81;6242700.66;0.39;1;1;1;0;0;42;24;3;17;482375.342666;20224;24576;24576
449298.37;6242700.27;0.39;1;1;1;0;0;42;21;3;17;482375.350762;18176;22784;23552
449287.47;6242700.06;0.39;11;1;1;0;0;42;20;3;17;482375.358921;20736;24832;24832
449290.11;6242700.21;0.35;1;1;1;0;0;42;20;3;17;482375.358962;19968;24064;23808
449280.48;6242700.08;0.33;1;1;1;0;0;42;18;3;17;482375.367142;22528;25856;26624
449286.97;6242700.44;0.36;3;1;1;0;0;42;19;3;17;482375.367246;19712;23552;23296
449293.03;6242700.78;0.37;1;1;1;0;0;42;21;3;17;482375.367342;19456;23296;23808
449313.36;6242701.92;0.38;6;1;1;0;0;42;24;3;17;482375.367654;19968;24576;24576
449277.48;6242700.17;0.34;8;1;1;0;0;42;18;3;17;482375.375420;20224;23808;25088
449289.46;6242700.85;0.31;3;1;1;0;0;42;20;3;17;482375.375611;18944;23040;23040

哪里";"是分隔符和first two columns the x and y任何有用的给ID position

输出结果是另一个文本文件,其中每个 ID 仅随机提取一个点

前任:

    20;10;449319.34;6242700.23;0.38;1;1;1;0;0;42;25;3;17;482375.326087;20224;23808;23808
    20;10;449310.72;6242700.22;0.35;3;1;1;0;0;42;23;3;17;482375.334291;20480;24576;24576
    20;10;449313.81;6242700.66;0.39;1;1;1;0;0;42;24;3;17;482375.342666;20224;24576;24576
    20;10;449298.37;6242700.27;0.39;1;1;1;0;0;42;21;3;17;482375.350762;18176;22784;23552
    20;11;449287.47;6242700.06;0.39;11;1;1;0;0;42;20;3;17;482375.358921;20736;24832;24832
    20;11;449290.11;6242700.21;0.35;1;1;1;0;0;42;20;3;17;482375.358962;19968;24064;23808

其中前两列是 ID

最终输出将是(示例)没有 ID 值

         20;10;449313.81;6242700.66;0.39;1;1;1;0;0;42;24;3;17;482375.342666;20224;24576;24576
         20;11;449287.47;6242700.06;0.39;11;1;1;0;0;42;20;3;17;482375.358921;20736;24832;24832

我正在使用此博客中的解决方案

# File: readline-example-3.py

file = open("sample.txt")

while 1:
    lines = file.readlines(100000)
    if not lines:
        break
    for line in lines:
        pass # do something

我的代码如下:

from __future__ import division
import os
import glob
import tempfile
import sys

def print_flulsh(n, maxvalue = None):
    sys.stdout.write("\r")
    if maxvalue is None:
        sys.stdout.write("Laser points processed: %d" % n)
    else:
        sys.stdout.write("%d of %d laser points processed" % (n, maxvalue))
    sys.stdout.flush()


def point_grid_id(x, y, minx, maxy, size):
    """give id (row,col)"""
    col = int((x - minx) / size)
    row = int((maxy - y) / size)
    return row, col


def tempfile_tile_name(line, temp_dir, minx, maxy, size, parse):
    x, y = line.split(parse)[:2]
    row, col = point_grid_id(float(x), float(y), minx, maxy, size)
    return os.path.normpath(os.path.join(temp_dir + os.sep,"tempfile_%s_%s.tmp" % (row, col)))

# split the text file in small text files following the ID value given by tempfile_tile_name
# where:
# filename : name+path of text file
# temp_dir: temporary folder
# minx, maxy: origin of the grid (left-up corner)
# size: size of the grid
# parse: delimeter of the text file
# num: number of lines (~ 12 millions)

def tempfile_split(filename, temp_dir, minx, maxy, size, parse, num):
    index = 1
    with open(filename) as file:
        while True:
            lines = file.readlines(100000)
            if not lines:
                break
            for line in lines:
                print_flulsh(index, num)
                index += 1
                name = tempfile_tile_name(line, temp_dir, minx, maxy, size, parse)
                with open(name, 'a') as outfile:
                    outfile.write(line)

我的代码的主要问题是当大约 200 万个拆分文本文件保存在临时文件夹中时速度会降低。我想知道effbot.org是否有一种优化的方法来创建缓冲区的解决方案?

4

1 回答 1

1

代码中的瓶颈不在于读取,而在于打开和关闭每行读取的输出文件。在评论中,您提到了您的最终目标:拆分后,我需要再次打开每个文件并随机选择一行。

theodox 提到了一种可能的方法,为每个 ID 获取第一个条目,然后在内存中随机覆盖它。请注意,覆盖必须以概率 1/ n发生,其中n是到目前为止看到的具有相同 ID 的行数,以避免对以后的样本产生偏差。

编辑。您可以通过对文件执行两次传递来节省内存。第一遍构建一组被随机选择排除的行号,第二遍处理未排除的行。

from random import random

def random_selection(filename, temp_dir, minx, maxy, size, parse, num):
    selection = {}
    excluded = set()
    with open(filename) as file:
        for i, line in enumerate(file):
            x, y, _ = line.split(parse, 2)
            row_col = point_grid_id(float(x), float(y), minx, maxy, size)
            try:
                n, selected_i = selection[row_col]
            except KeyError:
                selection[row_col] = 1, i
            else:
                n += 1
                if random() < 1.0 / n:
                    excluded.add(selected_i)
                    selected_i = i
                selection[row_col] = n, selected_i

    with open(filename) as file:
        for i, line in enumerate(file):
            if i not in excluded:
                #process the line
于 2013-03-25T09:34:29.110 回答