如何随机采样文件的一个子集

clw*_*wen 62 command-line files command

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

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

head并且tail可以选择文件的子集但不能随机选择。我知道我总是可以编写一个 python 脚本来这样做,但只是想知道是否有这种用法的命令。

der*_*ert 97

shuf命令(coreutils的部分)可以这样做:

shuf -n 1000 file
Run Code Online (Sandbox Code Playgroud)

至少对于现在的非古代版本(在2013年的提交中添加),它将在适当的时候使用水库采样,这意味着它不应该耗尽内存并使用快速算法。

  • @petrelharp `shuf -n` 进行水库采样,至少当输入大于 8K 时,他们确定的大小是更好的基准。查看源代码(例如,在 https://github.com/coreutils/coreutils/blob/master/src/shuf.c#L46 )。很抱歉这个很晚的答案。显然,这是 6 年前的新内容。 (3认同)
  • @Ketan 它只是在手册的错误部分,我相信。请注意,即使是手册中的示例也没有排序。另请注意,`sort` 位于同一部分,并且它显然不需要排序输入。 (2认同)
  • `shuf` 是在 `6.0 (2006-08-15)` 版本中引入 coreutils 的,不管你信不信,一些相当普遍的系统(特别是 CentOS 6.5)没有那个版本:-| (2认同)

Txa*_*gel 33

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

  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

  • @G-Man 这个问题似乎以从一百万中获取 10k 行为例。周围的答案都没有对我有用(因为文件的大小和硬件限制),我建议这是一个合理的妥协。它不会让你在一百万行中得到一万行,但对于大多数实际目的来说它可能已经足够接近了。我已经按照你的建议澄清了一点。谢谢。 (2认同)

geo*_*ory 10

类似于@Txangel 的概率解决方案,但速度接近 100 倍。

perl -ne 'print if (rand() < .01)' huge_file.csv > sample.csv
Run Code Online (Sandbox Code Playgroud)

如果您需要高性能、精确的样本大小,并且乐于忍受文件末尾的样本间隙,您可以执行以下操作(从 1m 行文件中抽取 1000 行样本):

perl -ne 'print if (rand() < .0012)' huge_file.csv | head -1000 > sample.csv
Run Code Online (Sandbox Code Playgroud)

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


hro*_*tyr 7

如果shuf -n大文件的技巧耗尽内存并且您仍然需要固定大小的示例并且可以安装外部实用程序,请尝试示例

$ sample -N 1000 < FILE_WITH_MILLIONS_OF_LINES 
Run Code Online (Sandbox Code Playgroud)

需要注意的是,样本示例中为1000 行)必须适合内存。

免责声明:我是推荐软件的作者。

  • 对于那些安装了它并且在路径中的“/usr/bin/”之前有“/usr/local/bin”的人,请注意 macOS 附带了一个名为“sample”的内置调用堆栈采样器,它会执行一些操作完全不同,在`/usr/bin/`中。 (2认同)