我解决了在bash下面的问题,但我觉得这是相当低效的速度很慢给予我需要减少文件的大小。 希望某人有一个想法如何做同样在Python,并希望加快速度。
原来的问题是减少非常大的文本文件(50-60万线,制表符分隔列)。 其中一列被视为一个关键,即我们确定有多少行了一个独特的密钥是在该文件中,然后随机选择其中的一个百分比(例如总数的四分之一,如果减少了75%),以追加到一个新的文件,将让我们的结果。 我们继续走通过按键的其余部分,随机化,然后将含有相同的百分比每一个独特的密钥的所有线路。 如果还原无法做到的 - 我们只是承载所有的线条到生成的文件。
正如我所说,我的bash脚本工作得很好,但它是缓慢的,串在一起的各种AWK和grep结构。 从各方面来看,巨蟒应以更优雅的方式,在不损害记忆太多(再次,我们面对的是50多个亿行的文件在这种情况下)处理这个。 任何建议/技巧将是有益的! 谢谢!
简单的解决办法是排序键列例如,文件排序由所述第二柱制表符分隔输入:
#!/bin/bash
printf "a\tz\nb\ty\nc\tx" | sort -k 2 -t $'\t'
进而解决检索的随机行的每个唯一键,其中同键所有的线条都与相邻的约束,对于每一个独特的密钥至少一行应保留25%的简单的问题:
#!/usr/bin/env python
import random
import sys
from itertools import chain, groupby
def choose_random(iterator, fraction, random=random.random):
"""Lazy analog of:
L = list(iterator)
k = int(len(L) * fraction + .5) or 1 # get at least one
result = random.sample(L, k)
Note: this function doesn't randomize the order of elements
that would require to keep selected elements in memory
and number of output elements is not exactly k
"""
# always yield at least one item if input is not empty
item = next(iterator)
it = (x for x in chain([item], iterator) if random() < fraction)
for x in chain([next(it, item)], it):
yield x
def getkey(line):
return line.split("\t")[1] # 2nd column
for key, group in groupby(sys.stdin, key=getkey):
sys.stdout.writelines(choose_random(group, fraction=0.25))
注:在输入文件的最后一行应包含一个换行符,否则如果选择最后一行输出已损坏。
该脚本接受(由键列)上stdin和打印减小的输出到标准输出输入排序。 它要求只存储在内存线在时间。 它是一个单通算法(O(N))。
因为你的问题是模糊的,我会给予了很高的水平解决方案
- 不读内存中的整个文件
fileObj.read()
或fileObj.readlines()
而不是通过文件迭代for line in fileObj
。 为什么? 这将是内存friednly 创建基于列表队列的实现
class Queue(object): def __init__(self, max_size): self.queue = [] self.max_size = max_size def __getitem__(self, index): if 0 <= index < max_size: return self.queue[index] else: raise IndexError def __iter__(self): return iter(self.queue) def push(seq): if isinstance(seq, Iterable): if len(self.queue) + len(seq) > self.max_size: raise Full self.queue = seq else: if len(self.queue) + 1 > self.max_size: raise Full self.queue.append(seq) def pop(): if self.queue: return self.queue.pop(0)
创建队列的字典具有MAXSIZE = 2 *所选项目的百分比
就像是
PCT_SELECTED = 100
MAXSIZE = 2 * PCT_SELECTED
KEY_START = 10
KEY_STOP = 15
from collection import defaultdict
queue_dict = defaultdict(Queue(MAXSIZE))
- 放入队列元素在非阻挡FASION
- 如果队列已满,它会引发异常
Full
,在这种情况下,你随机选择从队列中元素的50%,并放弃休息。
就像是
with open("your-file") as fin:
for line in fin:
key = line[KEY_START: KEY_STOP]
try:
queue_dict[key].push(line)
except Full:
queue_dict[key] = random.sample(queue_dict[key], PCT_SELECTED)
通过字典最后迭代,并随机地修剪出队列
queue_dict = {key: random.sample(value, PCT_SELECTED) for key, value in queue_dict.items()}
现在,您可以通过词典]读取和写入文件。
对于大量项目只是选择75%的可以通过检查每一个随机数来完成。
import random
with open('input') as f:
for line in f:
if random.random() < 0.75:
print line
如果你需要从每个键(即使它只有两行)保证至少一个项目:
import random
keys = set()
with open('input') as f:
for line in f:
columns = line.split('\t')
key = columns[0]
if not key in keys:
print line
keys.add(key)
continue
if random.random() < 0.75:
print line