【发布时间】:2015-08-16 09:24:34
【问题描述】:
我有一个非常大的文本文件 (>80Gb)。它包含制表符分隔的值。我只对一栏感兴趣。对于该特定列,我想获得 reverse percentile 约 10 个阈值。所以基本上,我的问题看起来像这样:“列 x 的值低于 $threshold 的行的百分比是多少?”。阈值大致为 1、5、10、100、500、1000。 样本数据:
dontcare dontcare interesting
1 10 502
2 10 0
3 10 100
4 10 23
5 10 5
在上述情况下,我想问“低于 500 的值的百分比是多少?”答案是 80%。
我该怎么做?
注意事项:
- 首先使用 awk 过滤感兴趣的列的文件大约需要 26 分钟,这在速度方面很好(最终得到一个
- 将生成的文件读入 pandas 数据帧大约需要 7 分钟;但计算 (
df[df < threshold].shape(0) / total_length) 耗时太长。几个小时后我停止了计算。我想 1 小时左右就可以了。 -
wc -l <filename>和df = pd.read_csv(filename, sep='\t', header=None); print(pandasdataframe)产生了不同数量的行,这让我感到惊讶。 (不过,我是 Pandas 的新手)。 - 我更喜欢 Python/Shell 中的解决方案,但我愿意接受任何想法。
编辑:
下面的答案是正确的。我想出了下面的脚本。仅供参考,读取预过滤文件(仅一列,80G)需要 1h16。为简单起见,我不会对文件进行预过滤。在我的测试中,mawk 比 gawk 好 2 倍。我使用NR 而不是(NR-1),因为没有标题行。
#!/bin/bash
FILENAME=$1
COL=$2 # one-based
AWK_CMD=mawk
THRESHOLDS="0 5 10 20 50 100 200 300 400 500 1000"
[ "$#" -ne 2 ] && { echo >&2 "usage: $0 <filename> <one-based-col>"; exit 1; }
# check if awk cmd exists
command -v $AWK_CMD >/dev/null 2>&1 || { echo >&2 "Cannot find $AWK_CMD. Please install and/or put it into your \$PATH."; exit 1; }
# constuct final cmd
CMD="$AWK_CMD 'BEGIN { total=0;"
for t in $THRESHOLDS; do
# set init vars to zero
CMD="${CMD} n$t=0;"
done
CMD="${CMD}}; { total+=\$$COL}; "
for t in $THRESHOLDS; do
# increment depending on threshold
CMD="${CMD} {if (\$$COL>$t) {n$t+=1}} ;"
done
CMD="${CMD} END { print \"mean: \" total/NR; "
for t in $THRESHOLDS; do
# output percentage
CMD="${CMD} print \"above$t: \" n$t/NR*100 ;"
done
CMD="${CMD} }' $FILENAME"
# echo $CMD
eval $CMD # backticks and $() won't work here
【问题讨论】:
-
这段代码应该足够快:
awk 'BEGIN {n=0;getline}; {if ($3<500) {n+=1}} END {print n/(NR-1)*100}' x.txt -
@MaratTalipov 开始块的意义何在?
-
@User112638726,跳过标题行
-
@MaratTalipov 啊,好吧,虽然不需要 n=0。无论如何,所有变量在 awk 中都初始化为 0。
-
显式优于隐式 ...