如何随机采样文件的子集

如何随机采样文件的子集

是否有任何 Linux 命令可以用来对文件的子集进行采样?例如,一个文件包含一百万行,我们只想从该文件中随机采样一千行。

对于随机,我的意思是每条线都有相同的被选择概率,并且选择的线都不是重复的。

headtail可以选择文件的子集,但不是随机的。我知道我总是可以编写一个 python 脚本来执行此操作,但只是想知道是否有用于此用途的命令。

答案1

命令shuf(coreutils 的一部分)可以执行此操作:

shuf -n 1000 file

至少现在非古代版本(添加在从2013年开始承诺),这将在适当的时候使用水库采样,这意味着它不应该耗尽内存并且正在使用快速算法。

答案2

如果你有一个很大文件(这是取样的常见原因)您会发现:

  1. shuf耗尽内存
  2. $RANDOM如果文件超过 32767 行,则无法正常使用

如果您不需要“精确”n 条采样线你可以采样比例像这样:

cat input.txt | awk 'BEGIN {srand()} !/^$/ { if (rand() <= .01) print $0}' > sample.txt

用途持续记忆,对文件的 1% 进行采样(如果您知道文件的行数,则可以调整此系数以对接近有限的行数进行采样),并且适用于任何尺寸但它的文件将不会返回一个精确的行数,只是一个统计比例。

注:代码来自:https://stackoverflow.com/questions/692312/randomly-pick-lines-from-a-file-without-slurping-it-with-unix

答案3

与 @Txangel 的概率解决方案类似,但速度快了 100 倍。

perl -ne 'print if (rand() < .01)' huge_file.csv > sample.csv

如果您需要高性能、精确的样本大小,并且愿意接受文件末尾的样本间隙,则可以执行类似以下操作(从 1m 行文件中采样 1000 行):

perl -ne 'print if (rand() < .0012)' huge_file.csv | head -1000 > sample.csv

..或者确实链接第二个示例方法而不是head.

答案4

当我想保留标题行并且样本可以是文件的近似百分比时,我喜欢使用 awk。适用于非常大的文件:

awk 'BEGIN {srand()} !/^$/ { if (rand() <= .01 || FNR==1) print > "data-sample.txt"}' data.txt

相关内容