如何从一个巨大的 txt 文件中获取分数列表的反向百分位数?
How to get the reverse percentile for a list of scores from a huge txt file?
我有一个非常大的文本文件 (>80Gb)。它包含 tab-delimited 个值。我只对一列感兴趣。对于该特定列,我想获得 ~10 个阈值的 reverse percentile。所以基本上,我的问题是这样的:"What is the percentage of rows where the value of column x is below $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
在上面的情况下,我想问"What is the percentage of values below 500?",答案是80%。
我该怎么做?
备注:
- 首先使用 awk 为有趣的列过滤文件花费了 ~26 分钟,这很好 speed-wise(最终文件 <10Gb)。
- 将生成的文件读入 pandas 数据帧需要大约 7 分钟;但是计算 (
df[df < threshold].shape(0) / total_length
) 花费的时间太长了。几个小时后我停止了计算。我想 ~1h 就可以了。
wc -l <filename>
和 df = pd.read_csv(filename, sep='\t', header=None); print(pandasdataframe)
产生了不同的行数,这让我感到惊讶。 (虽然我是 Pandas 的新手)。
- 我更喜欢 Python/Shell 中的解决方案,但我愿意接受任何想法。
编辑:
下面的答案是正确的。我想出了下面的脚本。仅供参考,读取预过滤文件(仅一列,<10G)花费了 1h02,读取原始文件(5 列,>80G)花费了 1h16。为了简单起见,我不会对文件进行预过滤。在我的测试中,mawk 比 gawk 好 2 倍。我使用 NR
而不是 (NR-1)
因为没有 header 行。
#!/bin/bash
FILENAME=
COL= # one-based
AWK_CMD=mawk
THRESHOLDS="0 5 10 20 50 100 200 300 400 500 1000"
[ "$#" -ne 2 ] && { echo >&2 "usage: [=11=] <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 来执行此操作:
awk 'NR > 1 && < 500 { ++n } END { if (NR > 1) print n / (NR - 1) * 100 }' file
对于第三个字段小于 500 的第一行之后的所有行,递增 n
。处理文件后,打印百分比,只要读取了一条或多条记录(这避免除以 0)。
我有一个非常大的文本文件 (>80Gb)。它包含 tab-delimited 个值。我只对一列感兴趣。对于该特定列,我想获得 ~10 个阈值的 reverse percentile。所以基本上,我的问题是这样的:"What is the percentage of rows where the value of column x is below $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
在上面的情况下,我想问"What is the percentage of values below 500?",答案是80%。
我该怎么做?
备注:
- 首先使用 awk 为有趣的列过滤文件花费了 ~26 分钟,这很好 speed-wise(最终文件 <10Gb)。
- 将生成的文件读入 pandas 数据帧需要大约 7 分钟;但是计算 (
df[df < threshold].shape(0) / total_length
) 花费的时间太长了。几个小时后我停止了计算。我想 ~1h 就可以了。 wc -l <filename>
和df = pd.read_csv(filename, sep='\t', header=None); print(pandasdataframe)
产生了不同的行数,这让我感到惊讶。 (虽然我是 Pandas 的新手)。- 我更喜欢 Python/Shell 中的解决方案,但我愿意接受任何想法。
编辑:
下面的答案是正确的。我想出了下面的脚本。仅供参考,读取预过滤文件(仅一列,<10G)花费了 1h02,读取原始文件(5 列,>80G)花费了 1h16。为了简单起见,我不会对文件进行预过滤。在我的测试中,mawk 比 gawk 好 2 倍。我使用 NR
而不是 (NR-1)
因为没有 header 行。
#!/bin/bash
FILENAME=
COL= # one-based
AWK_CMD=mawk
THRESHOLDS="0 5 10 20 50 100 200 300 400 500 1000"
[ "$#" -ne 2 ] && { echo >&2 "usage: [=11=] <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 来执行此操作:
awk 'NR > 1 && < 500 { ++n } END { if (NR > 1) print n / (NR - 1) * 100 }' file
对于第三个字段小于 500 的第一行之后的所有行,递增 n
。处理文件后,打印百分比,只要读取了一条或多条记录(这避免除以 0)。