我正在尝试重写我认为非常低效的一些旧bash脚本(更不用说不优雅)并使用一些可怕的管道......也许有真正Python技能的人可以给我一些指示......
该脚本使用了多个临时文件......我认为另一件事是风格不好,可能可以避免......
它实际上是通过从顶部切掉一定数量的线(丢弃标题)来操纵INPUT-FILE
。
然后它拉出其中一列并且:
raws = N
的数量; sort -u -n FILE > S-FILE
)。之后,我创建一个从1到N的连续整数索引,并使用粘贴命令将此新索引列粘贴到原始INPUT-FILE
中。
然后我的bash脚本为我们写入S-FILE的值生成Percentile Ranks
我相信Python利用scipy.stats
,而在bash中我确定S-FILE中每个唯一条目的重复行数(dupline),然后计算per-rank=$((100*($counter+$dupline/2)/$length))
,其中$ length = FILE的长度而不是S -文件。然后,我将结果打印到一个单独的1列文件中(并且重复相同的每个等级,与我们有重复行一样多次)
然后我会将这个带有百分位数的新列重新粘贴到INPUT-FILE中(因为我会根据用于计算百分等级的列对INPUT-FILE进行排序 - 所有内容都会在结果中完美排列。)
在此之后,它会进入下面的丑陋......
sort -o $INPUT-FILE $INPUT-FILE
awk 'int($4)>2000' $INPUT-FILE | awk -v seed=$RANDOM 'BEGIN{srand(seed);} {print rand()"\t"$0}' | sort -k1 -k2 -n | cut -f2- | head -n 500 > 2000-$INPUT-FILE
diff $INPUT-FILE 2000-$INPUT-FILE | sed '/^[0-9][0-9]*/d; s/^. //; /^---$/d' | awk 'int($4)>1000' | awk -v seed=$RANDOM 'BEGIN{srand(seed);} {print rand()"\t"$0}' | sort -k1 -k2 -n | cut -f2- | head -n 500 > 1000-$INPUT-FILE
cat 2000-$INPUT-FILE 1000-$INPUT-FILE | sort > merge-$INPUT-FILE
diff merge-$INPUT-FILE $INPUT-FILE | sed '/^[0-9][0-9]*/d; s/^. //; /^---$/d' | awk 'int($4)>500' | awk -v seed=$RANDOM 'BEGIN{srand(seed);} {print rand()"\t"$0}' | sort -k1 -k2 -n | cut -f2- | head -n 500 > 500-$INPUT-FILE
rm merge-$INPUT-FILE
基本上,这是一种非常不优雅的bash方式:
再一次,我希望有人可以帮我把这个丑陋的管道事物改造成蟒蛇之美! :)谢谢!
答案 0 :(得分:1)
评论中的两个关键点:
(A)文件大约50k行~100个字符。小到足以在现代桌面/服务器/笔记本电脑系统中舒适地适应内存。
(B)作者的主要问题是如何跟踪已经选择的行,而不是再次选择它们。
我建议三个步骤。
(1)浏览文件,制作三个单独的列表 - 称为u,v,w - 满足每个条件的行号。这些列表可能有超过500行,它们可能包含重复项,但我们将在步骤(2)中解决这些问题。
u = []
v = []
w = []
with open(filename, "r") as f:
for linenum, line in enumerate(f):
x = int(line.split()[3])
if x > 2000:
u.append(x)
if x > 1000:
v.append(x)
if x > 500:
w.append(x)
(2)选择行号。您可以使用内置的Random.sample()从总体中选取k个元素的样本。我们想要删除之前选择的元素,因此请在集合中跟踪这些元素。 (“selected”集合是一个集合而不是列表,因为测试“如果x未被选中”对于集合是O(log(n)),而对于列表是O(n)。将其更改为列表并且如果你准确地测量时间,你会看到减速,尽管对于“仅”50k数据点/ 500个样本/ 3个类别的数据集可能不是明显的延迟。)
import random
rand = random.Random() # change to random.Random(1234) for repeatable results
chosen = set()
s0 = rand.sample(u, 500)
chosen.update(s0)
s1 = rand.sample([x for x in v if x not in chosen], 500)
chosen.update(s1)
s2 = rand.sample([x for x in w if x not in chosen], 500)
chosen.update(s2)
(3)再次传递输入文件,将编号为s0的行放入第一个输出文件,将编号为s1的行放入第二个输出文件,将编号为s2的行放入第三个输出文件。在任何语言中它都是微不足道的,但这是一个使用Python“习语”的实现:
linenum2sample = dict([(x, 0) for x in s0]+[(x, 1) for x in s1]+[(x, 2) for x in s2])
outfile = [open("-".join(x, filename), "w") for x in ["2000", "1000", "500"]]
try:
with open(filename, "r") as f:
for linenum, line in enumerate(f):
s = linenum2sample.get(linenum)
if s is not None:
outfile[s].write(line)
finally:
for f in outfile:
f.close()
答案 1 :(得分:0)
将其分解成简单的部分。
如果标头不可用,请使用csv.DictReader或csv.reader读取文件。当您遍历这些行时,检查第4列的值并将这些行插入列表字典中,其中字典键类似于“gt_2000”,“gt_1000”,“gt_500”。
迭代你的字典键,为每一个创建一个文件并进行500循环,每次迭代,使用random.randint(0,len(the_list)-1)得到一个随机索引列表,将其写入文件,然后从列表中删除该索引处的项目。如果任何桶中的物品数量少于500件,则需要更多的物品。