【问题标题】:Shuffling a large text file without/with group order maintained在不维护/不维护组顺序的情况下改组大型文本文件
【发布时间】:2013-10-30 18:25:06
【问题描述】:

它不是制作脚本,而是根据第一列中的独特元素,用一个衬垫来随机播放一个大的制表符分隔的文本文件。这意味着,对于第一列中的每个唯一元素,行数将相等并由用户指定。

有两种输出可能性,保持行顺序或随机行顺序。

输入:

chr1    3003204 3003454 *   37  +
chr1    3003235 3003485 *   37  +
chr1    3003148 3003152 *   37  -
chr1    3003461 3003711 *   37  +
chr11   71863609    71863647    *   37  +
chr11   71864025    71864275    *   37  +
chr11   71864058    71864308    *   37  -
chr11   71864534    71864784    *   37  +
chrY    90828920    90829170    *   23  -
chrY    90829096    90829346    *   23  +
chrY    90828924    90829174    *   23  -
chrY    90828925    90829175    *   23  -

输出(每个类别 1 行 - 由用户定义) 输出1(随机 - 行顺序会改变):

chr1    3003235 3003485 *   37  +
chr11   71863609    71863647    *   37  +
chrY    90828925    90829175    *   23  -

Output1(随机 - 将保持行顺序):

chr1    3003204 3003454 *   37  +
chr11   71863609    71863647    *   37  +
chrY    90828920    90829170    *   23  -

我尝试在第一列上使用sort -ucut 来获取唯一元素,然后为每个元素运行grephead 的组合以生成输出文件,可以使用shuf 随机生成输出文件,可能会有更好的解决方案,因为文件可能会超过 5000 万行。

干杯

【问题讨论】:

  • +1 有趣的问题。

标签: linux sorting text random shuffle


【解决方案1】:

尝试使用

维护行顺序

awk '!($1 in a) {a[$1]=$0} END { asort(a,b); for (x in b) print b[x] }' file

输出:

chr1    3003204 3003454 *   37  +
chr11   71863609    71863647    *   37  +
chrY    90828920    90829170    *   23  -

随机行顺序

为此,只需将 shuf 的输出通过管道传输到上述 awk 命令

shuf file | awk '!($1 in a) {a[$1]=$0} END { asort(a,b); for (x in b) print b[x] }'

输出(每次运行不同)

chr1    3003148 3003152 *   37  -
chr11   71864025    71864275    *   37  +
chrY    90829096    90829346    *   23  +

可变行数

#!/bin/bash
numRow=3
awk 'n[$1]<'$numRow' {a[$1]=a[$1]"\n"$0; n[$1]++} END { asort(a,b); for (x in b) print b[x] }' file

输出:

chr1    3003204 3003454 *   37  +
chr1    3003235 3003485 *   37  +
chr1    3003148 3003152 *   37  -

chr11   71863609    71863647    *   37  +
chr11   71864025    71864275    *   37  +
chr11   71864058    71864308    *   37  -

chrY    90828920    90829170    *   23  -
chrY    90829096    90829346    *   23  +
chrY    90828924    90829174    *   23  -

【讨论】:

  • 我喜欢你的回答,简短而高效。但是我如何指定每条染色体而不是 1 行(唯一元素 forst 列),给我每条染色体 10 或 100 个!
  • @SukhdeepSingh 附加要求!这似乎更棘手。我会检查并告诉你。同时你能用这个更新你的问题吗?
  • 原题里已经写好了,看第三行:)
  • @SukhdeepSingh 请使用命令检查更新的 ans 以了解可变行数。
  • @SukhdeepSingh 不,这在 shell 脚本中不是问题。 $1 内单引号将被视为第一列,外单引号或内双引号将被视为用户参数 awk 'n[$1]&lt;'$numRow' {a[$1]=a[$1]"\n"$0; n[$1]++} END { asort(a,b); for (x in b) print b[x] }' $1 应该有效。
【解决方案2】:

编写脚本肯定更容易吗?

perl -n -e 'BEGIN{ %c=qw(chr1 4 chr11 4 chrY 4); $c{$_}=int(rand($c{$_})) for keys %c;  $r="^(".join("|",keys %c).")\\s";} print if (/$r/o and !$c{$1}--);' filename.txt

BEGIN 块在脚本启动时执行一次。 print if.. 语句用于文件中的每一行

%c 关联数组具有要查找的键以及每个键的项目数

$r 是一个正则表达式,看起来像 ^(chr1|chr11|chrY)\s

如果找到正则表达式,则匹配中的匹配键用作对递减的关联数组的查找。当它为零时,打印该行

【讨论】:

  • 不错的解决方案,但答案要短得多,而且我们不必指定唯一元素:)
  • 我没有检查过,但我想其他答案使用更多内存
【解决方案3】:

如果有人喜欢在 Python 中使用 pandas 执行此操作。这是我的答案:

#!/bin/env python

import sys
import pandas as pd

column = 0
number = 1
method = pd.Series.head  # or pd.Series.sample

pd.read_table(sys.stdin, header=None) \
  .groupby(column) \
  .apply(method, n=number) \
  .to_csv(sys.stdout, sep="\t", index=False, header=False)

pd.read_table 将读取一个表格文件。它与pd.read_csv(..., sep='\t') 的作用相同。 header=None 将告诉 pandas 不要将第一行用作标题,默认情况下会这样做。
.groupby 将按 DataFrame 的给定列分组。
.apply(method, n=number) 将在每个字段上调用 ​​method给定关键字参数n=number 的组。
.to_csv 将写入 DataFrame,在这种情况下以制表符分隔,没有 DataFrame 的索引和标头到标准输出。

调用如下:

%$ python myscript.py < ${input_tsv} > ${output_tsv}

Pandas 是一个大包,需要时间来加载。因此,这个脚本比awk 脚本慢得多。但在更大的 Python 程序中可能很有用。

基准测试:

包含 49144 条记录的 BED 文件。

在 Zsh 中从 @jkshah 运行 Awk 脚本:

%$ awk '!($1 in a) {a[$1]=$0} END { asort(a,b); for (x in b) print b[x] }' ${bedfile} | sort >/dev/null
%$ shuf ${bedfile} | awk '!($1 in a) {a[$1]=$0} END { asort(a,b); for (x in b) print b[x] }' | sort >/dev/null

前大约 21 毫秒的挂墙时间(平均 70 次运行)。 第二个大约 30 毫秒的挂墙时间(平均 70 次运行)。

使用 %timeit 魔法在 IPython 中运行 Python 语句:

In [1]: %timeit pd.read_table("Every10cM.sort.bed", header=None).groupby(0).apply(pd.Series.head, n=1).to_csv(sep="\t", index=False, header=False)
In [2]: %timeit pd.read_table("Every10cM.sort.bed", header=None).groupby(0).apply(pd.Series.sample, n=1).to_csv(sep="\t", index=False, header=False)

两者都大约 72 毫秒的挂壁时间(平均 70 次运行)。所以它很慢......

【讨论】:

    猜你喜欢
    • 2014-03-03
    • 2018-06-16
    • 1970-01-01
    • 2015-09-12
    • 2014-02-08
    • 1970-01-01
    • 1970-01-01
    • 2016-10-07
    • 1970-01-01
    相关资源
    最近更新 更多